From d94c673cee1d9f363df0fdb876609f21824c5aab Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Tue, 11 Jun 2024 07:21:00 +0200 Subject: [PATCH 01/47] fix(#1175): OpenAPI connector enhancements for simulator random message generation --- connectors/citrus-openapi/pom.xml | 6 +- .../openapi/OpenApiRepository.java | 66 +++++++ .../openapi/OpenApiSpecification.java | 39 ++-- .../OpenApiSpecificationProcessor.java | 59 +++++++ .../openapi/OpenApiTestDataGenerator.java | 52 +++++- .../OpenApiClientResponseActionBuilder.java | 134 ++++++++++---- .../OpenApiServerRequestActionBuilder.java | 166 +++++++++++++----- .../OpenApiServerResponseActionBuilder.java | 56 +++--- .../openapi/model/OasModelHelper.java | 159 ++++++++++++++--- .../openapi/model/v2/Oas20ModelHelper.java | 113 +++++++++++- .../openapi/model/v3/Oas30ModelHelper.java | 119 ++++++++----- .../openapi/OpenApiRepositoryTest.java | 50 ++++++ .../openapi/SampleOpenApiProcessor.java | 30 ++++ .../model/v2/Oas20ModelHelperTest.java | 119 +++++++++++++ .../model/v3/Oas30ModelHelperTest.java | 126 +++++++++++-- .../openapi/processor/sampleOpenApiProcessor | 2 + .../spi/ReferenceResolverAware.java | 5 +- .../repository/BaseRepository.java | 107 +++++++++++ .../org/citrusframework/util/StringUtils.java | 21 +++ .../json/JsonSchemaRepository.java | 69 ++------ .../json/schema/JsonSchemaValidationTest.java | 14 +- .../xml/XsdSchemaRepository.java | 84 ++------- 22 files changed, 1266 insertions(+), 330 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/SampleOpenApiProcessor.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java create mode 100644 connectors/citrus-openapi/src/test/resources/META-INF/citrus/openapi/processor/sampleOpenApiProcessor create mode 100644 core/citrus-base/src/main/java/org/citrusframework/repository/BaseRepository.java diff --git a/connectors/citrus-openapi/pom.xml b/connectors/citrus-openapi/pom.xml index d8b8c6ce27..b842f11d8a 100644 --- a/connectors/citrus-openapi/pom.xml +++ b/connectors/citrus-openapi/pom.xml @@ -41,11 +41,15 @@ ${project.version} provided - io.apicurio apicurio-data-models + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.17.0 + diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java new file mode 100644 index 0000000000..75b62e59c7 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -0,0 +1,66 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import java.util.ArrayList; +import java.util.List; +import org.citrusframework.repository.BaseRepository; +import org.citrusframework.spi.Resource; + +/** + * OpenApi repository holding a set of {@link OpenApiSpecification} known in the test scope. + * @since 4.4.0 + */ +public class OpenApiRepository extends BaseRepository { + + private static final String DEFAULT_NAME = "openApiSchemaRepository"; + + /** List of schema resources */ + private final List openApiSpecifications = new ArrayList<>(); + + + /** An optional context path, used for each api, without taking into account any {@link OpenApiSpecification} specific context path. */ + private String rootContextPath; + + public OpenApiRepository() { + super(DEFAULT_NAME); + } + + public String getRootContextPath() { + return rootContextPath; + } + + public void setRootContextPath(String rootContextPath) { + this.rootContextPath = rootContextPath; + } + + @Override + public void addRepository(Resource openApiResource) { + + OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); + openApiSpecification.setRootContextPath(rootContextPath); + + this.openApiSpecifications.add(openApiSpecification); + + OpenApiSpecificationProcessor.lookup().values().forEach(processor -> processor.process(openApiSpecification)); + } + + public List getOpenApiSpecifications() { + return openApiSpecifications; + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index 00c5a1c382..5c28f5e67a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -34,12 +34,21 @@ */ public class OpenApiSpecification { + public static final String HTTPS = "https"; + public static final String HTTP = "http"; /** URL to load the OpenAPI specification */ private String specUrl; private String httpClient; private String requestUrl; + /** + * The optional root context path to which the OpenAPI is hooked. + * This path is prepended to the base path specified in the OpenAPI configuration. + * If no root context path is specified, only the base path and additional segments are used. + */ + private String rootContextPath; + private OasDocument openApiDoc; private boolean generateOptionalFields = true; @@ -56,7 +65,7 @@ public static OpenApiSpecification from(String specUrl) { public static OpenApiSpecification from(URL specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc; - if (specUrl.getProtocol().startsWith("https")) { + if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); @@ -76,11 +85,11 @@ public static OpenApiSpecification from(Resource resource) { specification.setOpenApiDoc(openApiDoc); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList("http")) + .orElse(Collections.singletonList(HTTP)) .stream() - .filter(s -> s.equals("http") || s.equals("https")) + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) .findFirst() - .orElse("http"); + .orElse(HTTP); specification.setSpecUrl(resource.getLocation()); specification.setRequestUrl(String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), OasModelHelper.getBasePath(openApiDoc))); @@ -102,17 +111,17 @@ public OasDocument getOpenApiDoc(TestContext context) { resolvedSpecUrl = requestUrl.endsWith("/") ? requestUrl + resolvedSpecUrl.substring(1) : requestUrl + resolvedSpecUrl; } else if (httpClient != null && context.getReferenceResolver().isResolvable(httpClient, HttpClient.class)) { String baseUrl = context.getReferenceResolver().resolve(httpClient, HttpClient.class).getEndpointConfiguration().getRequestUrl(); - resolvedSpecUrl = baseUrl.endsWith("/") ? baseUrl + resolvedSpecUrl.substring(1) : baseUrl + resolvedSpecUrl;; + resolvedSpecUrl = baseUrl.endsWith("/") ? baseUrl + resolvedSpecUrl.substring(1) : baseUrl + resolvedSpecUrl; } else { throw new CitrusRuntimeException(("Failed to resolve OpenAPI spec URL from relative path %s - " + "make sure to provide a proper base URL when using relative paths").formatted(resolvedSpecUrl)); } } - if (resolvedSpecUrl.startsWith("http")) { + if (resolvedSpecUrl.startsWith(HTTP)) { try { URL specWebResource = new URL(resolvedSpecUrl); - if (resolvedSpecUrl.startsWith("https")) { + if (resolvedSpecUrl.startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specWebResource); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specWebResource); @@ -129,11 +138,11 @@ public OasDocument getOpenApiDoc(TestContext context) { if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList("http")) + .orElse(Collections.singletonList(HTTP)) .stream() - .filter(s -> s.equals("http") || s.equals("https")) + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) .findFirst() - .orElse("http"); + .orElse(HTTP); setRequestUrl(String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), OasModelHelper.getBasePath(openApiDoc))); } @@ -190,4 +199,14 @@ public boolean isValidateOptionalFields() { public void setValidateOptionalFields(boolean validateOptionalFields) { this.validateOptionalFields = validateOptionalFields; } + + public String getRootContextPath() { + return rootContextPath; + } + + public void setRootContextPath(String rootContextPath) { + this.rootContextPath = rootContextPath; + } + + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java new file mode 100644 index 0000000000..b7ca0b5bdc --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java @@ -0,0 +1,59 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import java.util.Map; +import org.citrusframework.spi.ResourcePathTypeResolver; +import org.citrusframework.spi.TypeResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Interface for processing OpenAPI specifications. + *

+ * This interface is designed to be implemented by custom processors that handle OpenAPI specifications. + * Implementations of this interface are discovered by the standard citrus SPI mechanism. + *

+ */ +public interface OpenApiSpecificationProcessor { + + /** Logger */ + Logger logger = LoggerFactory.getLogger(OpenApiSpecificationProcessor.class); + + /** OpenAPI processors resource lookup path */ + String RESOURCE_PATH = "META-INF/citrus/openapi/processor"; + + /** Type resolver to find OpenAPI processors on classpath via resource path lookup */ + TypeResolver TYPE_RESOLVER = new ResourcePathTypeResolver(RESOURCE_PATH); + + void process(OpenApiSpecification openApiSpecification); + + /** + * Resolves all available processors from resource path lookup. Scans classpath for processors meta information + * and instantiates those processors. + */ + static Map lookup() { + Map processors = TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name"); + + if (logger.isDebugEnabled()) { + processors.forEach((k, v) -> logger.debug(String.format("Found openapi specification processor '%s' as %s", k, v.getClass()))); + } + + return processors; + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index c5aadd01e2..d9cb31f977 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -16,12 +16,12 @@ package org.citrusframework.openapi; +import io.apicurio.datamodels.openapi.models.OasSchema; import java.util.Map; import java.util.stream.Collectors; - -import io.apicurio.datamodels.openapi.models.OasSchema; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.model.OasModelHelper; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; @@ -348,4 +348,52 @@ public static String createRandomValueExpression(OasSchema schema) { return ""; } } + + /** + * Create validation expression using regex according to schema type and format. + * @param name + * @param oasSchema + * @return + */ + public static String createValidationRegex(String name, OasSchema oasSchema) { + + if (oasSchema != null && (OasModelHelper.isReferenceType(oasSchema) || OasModelHelper.isObjectType(oasSchema))) { + throw new CitrusRuntimeException(String.format("Unable to create a validation regex for an reference of object schema '%s'!", name)); + } + + return createValidationRegex(oasSchema); + } + + public static String createValidationRegex(OasSchema schema) { + + if (schema == null) { + return ""; + } + + switch (schema.type) { + case "string": + if (schema.format != null && schema.format.equals("date")) { + return "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"; + } else if (schema.format != null && schema.format.equals("date-time")) { + return "\\d{4}-\\d{2}-\\d{2}T[01]\\d:[0-5]\\d:[0-5]\\d"; + } else if (StringUtils.hasText(schema.pattern)) { + return schema.pattern; + } else if (!CollectionUtils.isEmpty(schema.enum_)) { + return "(" + (String.join("|", schema.enum_)) + ")"; + } else if (schema.format != null && schema.format.equals("uuid")){ + return "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; + } else { + return ".*"; + } + case "number": + return "[0-9]+\\.?[0-9]*"; + case "integer": + return "[0-9]+"; + case "boolean": + return "(true|false)"; + default: + return ""; + } + } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index 49b8a21c3a..bc1ad3370e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -16,15 +16,16 @@ package org.citrusframework.openapi.actions; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; - import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; +import jakarta.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -32,11 +33,14 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; +import org.citrusframework.message.MessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.util.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; /** * @since 4.1 @@ -46,13 +50,78 @@ public class OpenApiClientResponseActionBuilder extends HttpClientResponseAction /** * Default constructor initializes http response message builder. */ - public OpenApiClientResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, String statusCode) { + public OpenApiClientResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, + String statusCode) { this(new HttpMessage(), openApiSpec, operationId, statusCode); } - public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId, String statusCode) { - super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpec, operationId, statusCode), httpMessage); + public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId, String statusCode) { + super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpec, operationId, + statusCode), httpMessage); + } + + public static void fillMessageFromResponse(OpenApiSpecification openApiSpecification, + TestContext context, HttpMessage httpMessage, @Nullable OasOperation operation, + @Nullable OasResponse response) { + + if (operation == null || response == null) { + return; + } + + fillRequiredHeaders( + openApiSpecification, context, httpMessage, response); + + Optional responseSchema = OasModelHelper.getSchema(response); + responseSchema.ifPresent(oasSchema -> { + httpMessage.setPayload( + OpenApiTestDataGenerator.createInboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions( + openApiSpecification.getOpenApiDoc(context)), openApiSpecification)); + + // Best guess for the content type. Currently, we can only determine the content type + // for sure for json. Other content types will be neglected. + OasSchema resolvedSchema = OasModelHelper.resolveSchema( + openApiSpecification.getOpenApiDoc(null), oasSchema); + if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType( + resolvedSchema)) { + Collection responseTypes = OasModelHelper.getResponseTypes(operation, + response); + if (responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)) { + httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, + MediaType.APPLICATION_JSON_VALUE); + httpMessage.setType(MessageType.JSON); + } + } + } + ); + } + + private static void fillRequiredHeaders( + OpenApiSpecification openApiSpecification, TestContext context, HttpMessage httpMessage, + OasResponse response) { + + Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); + for (Map.Entry header : requiredHeaders.entrySet()) { + httpMessage.setHeader(header.getKey(), + OpenApiTestDataGenerator.createValidationExpression(header.getKey(), + header.getValue(), + OasModelHelper.getSchemaDefinitions( + openApiSpecification.getOpenApiDoc(context)), false, + openApiSpecification, + context)); + } + + Map headers = OasModelHelper.getHeaders(response); + for (Map.Entry header : headers.entrySet()) { + if (!requiredHeaders.containsKey(header.getKey()) && context.getVariables() + .containsKey(header.getKey())) { + httpMessage.setHeader(header.getKey(), + CitrusSettings.VARIABLE_PREFIX + header.getKey() + + CitrusSettings.VARIABLE_SUFFIX); + } + } } private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuilder { @@ -63,8 +132,9 @@ private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuil private final HttpMessage httpMessage; - public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId, String statusCode) { + public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId, String statusCode) { super(httpMessage); this.openApiSpec = openApiSpec; this.operationId = operationId; @@ -78,9 +148,10 @@ public Message build(TestContext context, String messageType) { OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); for (OasPathItem path : OasModelHelper.getPathItems(oasDocument.paths)) { - Optional> operationEntry = OasModelHelper.getOperationMap(path).entrySet().stream() - .filter(op -> operationId.equals(op.getValue().operationId)) - .findFirst(); + Optional> operationEntry = OasModelHelper.getOperationMap( + path).entrySet().stream() + .filter(op -> operationId.equals(op.getValue().operationId)) + .findFirst(); if (operationEntry.isPresent()) { operation = operationEntry.get().getValue(); @@ -89,36 +160,27 @@ public Message build(TestContext context, String messageType) { } if (operation == null) { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpec.getSpecUrl())); } if (operation.responses != null) { - OasResponse response = Optional.ofNullable(operation.responses.getItem(statusCode)) - .orElse(operation.responses.default_); + OasResponse response; - if (response != null) { - Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); - for (Map.Entry header : requiredHeaders.entrySet()) { - httpMessage.setHeader(header.getKey(), OpenApiTestDataGenerator.createValidationExpression(header.getKey(), header.getValue(), - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context)); - } - - Map headers = OasModelHelper.getHeaders(response); - for (Map.Entry header : headers.entrySet()) { - if (!requiredHeaders.containsKey(header.getKey()) && context.getVariables().containsKey(header.getKey())) { - httpMessage.setHeader(header.getKey(), CitrusSettings.VARIABLE_PREFIX + header.getKey() + CitrusSettings.VARIABLE_SUFFIX); - } - } - - Optional responseSchema = OasModelHelper.getSchema(response); - responseSchema.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + if (StringUtils.hasText(statusCode)) { + response = Optional.ofNullable(operation.responses.getItem(statusCode)) + .orElse(operation.responses.default_); + } else { + response = OasModelHelper.getResponseForRandomGeneration( + openApiSpec.getOpenApiDoc(null), operation) + .orElse(operation.responses.default_); } - } - OasModelHelper.getResponseContentType(oasDocument, operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + fillMessageFromResponse(openApiSpec, context, httpMessage, operation, response); + } - if (Pattern.compile("[0-9]+").matcher(statusCode).matches()) { + if (Pattern.compile("\\d+").matcher(statusCode).matches()) { httpMessage.status(HttpStatus.valueOf(Integer.parseInt(statusCode))); } else { httpMessage.status(HttpStatus.OK); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java index 30c7a0b17a..2574c75631 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java @@ -16,17 +16,25 @@ package org.citrusframework.openapi.actions; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; +import static java.lang.String.format; +import static org.citrusframework.message.MessageType.JSON; +import static org.citrusframework.message.MessageType.PLAINTEXT; +import static org.citrusframework.message.MessageType.XML; +import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; +import static org.citrusframework.util.StringUtils.appendSegmentToPath; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -74,6 +82,24 @@ public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecif @Override public Message build(TestContext context, String messageType) { + OasOperationParams oasOperationParams = getResult(context); + + if (oasOperationParams.operation() == null) { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + } + + setSpecifiedMessageType(oasOperationParams); + setSpecifiedHeaders(context, oasOperationParams); + setSpecifiedQueryParameters(context, oasOperationParams); + setSpecifiedPath(context, oasOperationParams); + setSpecifiedBody(oasOperationParams); + setSpecifiedRequestContentType(oasOperationParams); + setSpecifiedMethod(oasOperationParams); + + return super.build(context, messageType); + } + + private OasOperationParams getResult(TestContext context) { OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); OasOperation operation = null; OasPathItem pathItem = null; @@ -91,58 +117,110 @@ public Message build(TestContext context, String messageType) { break; } } + return new OasOperationParams(oasDocument, operation, pathItem, method); + } - if (operation == null) { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); - } + private void setSpecifiedRequestContentType(OasOperationParams oasOperationParams) { + OasModelHelper.getRequestContentType(oasOperationParams.operation) + .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, String.format("@startsWith(%s)@", contentType))); + } + + private void setSpecifiedPath(TestContext context, OasOperationParams oasOperationParams) { + String randomizedPath = OasModelHelper.getBasePath(oasOperationParams.oasDocument) + oasOperationParams.pathItem.getPath(); + randomizedPath = randomizedPath.replace("//", "/"); + + randomizedPath = appendSegmentToPath(openApiSpec.getRootContextPath(), randomizedPath); - if (operation.parameters != null) { - operation.parameters.stream() - .filter(param -> "header".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createValidationExpression(param.getName(), (OasSchema) param.schema, - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context))); - - operation.parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createValidationExpression(param.getName(), (OasSchema) param.schema, - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context))); + if (oasOperationParams.operation.parameters != null) { + randomizedPath = determinePath(context, oasOperationParams.operation, randomizedPath); } - Optional body = OasModelHelper.getRequestBodySchema(oasDocument, operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + httpMessage.path(randomizedPath); + } - String randomizedPath = OasModelHelper.getBasePath(oasDocument) + pathItem.getPath(); - randomizedPath = randomizedPath.replaceAll("//", "/"); + private void setSpecifiedBody(OasOperationParams oasOperationParams) { + Optional body = OasModelHelper.getRequestBodySchema(oasOperationParams.oasDocument, oasOperationParams.operation); + body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions( + oasOperationParams.oasDocument), openApiSpec))); + } - if (operation.parameters != null) { - List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + private String determinePath(TestContext context, OasOperation operation, + String randomizedPath) { + List pathParams = operation.parameters.stream() + .filter(p -> "path".equals(p.in)).toList(); - for (OasParameter parameter : pathParams) { - String parameterValue; - if (context.getVariables().containsKey(parameter.getName())) { - parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; - } else { - parameterValue = OpenApiTestDataGenerator.createValidationExpression((OasSchema) parameter.schema, - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec); - } + for (OasParameter parameter : pathParams) { + String parameterValue; + if (context.getVariables().containsKey(parameter.getName())) { + parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") - .matcher(randomizedPath) - .replaceAll(parameterValue); + .matcher(randomizedPath) + .replaceAll(parameterValue); + } else { + parameterValue = OpenApiTestDataGenerator.createValidationRegex(parameter.getName(), OasModelHelper.getParameterSchema(parameter).orElse(null)); + + randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") + .matcher(randomizedPath) + .replaceAll(parameterValue); + + randomizedPath = format("@matches('%s')@", randomizedPath); } } + return randomizedPath; + } - OasModelHelper.getRequestContentType(operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, String.format("@startsWith(%s)@", contentType))); + private void setSpecifiedQueryParameters(TestContext context, OasOperationParams oasOperationParams) { - httpMessage.path(randomizedPath); - httpMessage.method(method); + if (oasOperationParams.operation.parameters == null) { + return; + } + + oasOperationParams.operation.parameters.stream() + .filter(param -> "query".equals(param.in)) + .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> httpMessage.queryParam(param.getName(), + OpenApiTestDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), + OasModelHelper.getSchemaDefinitions(oasOperationParams.oasDocument), false, openApiSpec, + context))); - return super.build(context, messageType); } + + private void setSpecifiedHeaders(TestContext context, OasOperationParams oasOperationParams) { + + if (oasOperationParams.operation.parameters == null) { + return; + } + + oasOperationParams.operation.parameters.stream() + .filter(param -> "header".equals(param.in)) + .filter( + param -> (param.required != null && param.required) || context.getVariables() + .containsKey(param.getName())) + .forEach(param -> httpMessage.setHeader(param.getName(), + OpenApiTestDataGenerator.createValidationExpression(param.getName(), + OasModelHelper.getParameterSchema(param).orElse(null), + OasModelHelper.getSchemaDefinitions(oasOperationParams.oasDocument), false, openApiSpec, + context))); + } + + private void setSpecifiedMessageType(OasOperationParams oasOperationParams) { + Optional requestContentType = getRequestContentType( + oasOperationParams.operation); + if (requestContentType.isPresent() && APPLICATION_JSON_VALUE.equals(requestContentType.get())) { + httpMessage.setType(JSON); + } else if (requestContentType.isPresent() && APPLICATION_XML_VALUE.equals(requestContentType.get())) { + httpMessage.setType(XML); + } else { + httpMessage.setType(PLAINTEXT); + } + } + + private void setSpecifiedMethod(OasOperationParams oasOperationParams) { + httpMessage.method(oasOperationParams.method); + } + + } + + private record OasOperationParams(OasDocument oasDocument, OasOperation operation, OasPathItem pathItem, HttpMethod method) { } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index 8a77e21e73..b285259cd0 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -94,34 +94,13 @@ public Message build(TestContext context, String messageType) { } if (operation.responses != null) { - OasResponse response = Optional.ofNullable(operation.responses.getItem(statusCode)) - .orElse(operation.responses.default_); - - if (response != null) { - Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); - for (Map.Entry header : requiredHeaders.entrySet()) { - httpMessage.setHeader(header.getKey(), - OpenApiTestDataGenerator.createRandomValueExpression(header.getKey(), header.getValue(), - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context)); - } - - Map headers = OasModelHelper.getHeaders(response); - for (Map.Entry header : headers.entrySet()) { - if (!requiredHeaders.containsKey(header.getKey()) && context.getVariables().containsKey(header.getKey())) { - httpMessage.setHeader(header.getKey(), CitrusSettings.VARIABLE_PREFIX + header.getKey() + CitrusSettings.VARIABLE_SUFFIX); - } - } - - Optional responseSchema = OasModelHelper.getSchema(response); - responseSchema.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); - } + buildResponse(context, operation, oasDocument); } - OasModelHelper.getResponseContentType(oasDocument, operation) + OasModelHelper.getResponseContentTypeForRandomGeneration(oasDocument, operation) .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); - if (Pattern.compile("[0-9]+").matcher(statusCode).matches()) { + if (Pattern.compile("\\d+").matcher(statusCode).matches()) { httpMessage.status(HttpStatus.valueOf(Integer.parseInt(statusCode))); } else { httpMessage.status(HttpStatus.OK); @@ -129,5 +108,34 @@ public Message build(TestContext context, String messageType) { return super.build(context, messageType); } + + private void buildResponse(TestContext context, OasOperation operation, + OasDocument oasDocument) { + OasResponse response = Optional.ofNullable(operation.responses.getItem(statusCode)) + .orElse(operation.responses.default_); + + if (response != null) { + Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); + for (Map.Entry header : requiredHeaders.entrySet()) { + httpMessage.setHeader(header.getKey(), + OpenApiTestDataGenerator.createRandomValueExpression(header.getKey(), header.getValue(), + OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, + context)); + } + + Map headers = OasModelHelper.getHeaders(response); + for (Map.Entry header : headers.entrySet()) { + if (!requiredHeaders.containsKey(header.getKey()) && + context.getVariables().containsKey(header.getKey())) { + httpMessage.setHeader(header.getKey(), + CitrusSettings.VARIABLE_PREFIX + header.getKey() + CitrusSettings.VARIABLE_SUFFIX); + } + } + + Optional responseSchema = OasModelHelper.getSchema(response); + responseSchema.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + } + } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index 4f4bd6b8bf..c081e8013b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,26 +16,31 @@ package org.citrusframework.openapi.model; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.BiFunction; -import java.util.function.Function; - import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; +import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasPaths; import io.apicurio.datamodels.openapi.models.OasResponse; +import io.apicurio.datamodels.openapi.models.OasResponses; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; import io.apicurio.datamodels.openapi.v2.models.Oas20Operation; +import io.apicurio.datamodels.openapi.v2.models.Oas20Parameter; import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Document; import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; +import io.apicurio.datamodels.openapi.v3.models.Oas30Parameter; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Function; import org.citrusframework.openapi.model.v2.Oas20ModelHelper; import org.citrusframework.openapi.model.v3.Oas30ModelHelper; @@ -51,7 +56,7 @@ private OasModelHelper() { * @return true if given schema is an object. */ public static boolean isObjectType(OasSchema schema) { - return "object".equals(schema.type); + return schema != null && "object".equals(schema.type); } /** @@ -63,13 +68,32 @@ public static boolean isArrayType(OasSchema schema) { return "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)) { + return false; + } + Object items = schema.items; + if (items instanceof OasSchema oasSchema) { + return isObjectType(oasSchema); + } else if (items instanceof List list) { + return list.stream().allMatch(item -> item instanceof OasSchema oasSchema && isObjectType(oasSchema)); + } + + return false; + } + /** * Determines if given schema has a reference to another schema object. * @param schema to check * @return true if given schema has a reference. */ public static boolean isReferenceType(OasSchema schema) { - return schema.$ref != null; + return schema != null && schema.$ref != null; } public static String getHost(OasDocument openApiDoc) { @@ -80,6 +104,14 @@ public static List getSchemes(OasDocument openApiDoc) { return delegate(openApiDoc, Oas20ModelHelper::getSchemes, Oas30ModelHelper::getSchemes); } + public static OasSchema resolveSchema(OasDocument oasDocument, OasSchema schema) { + if (isReferenceType(schema)) { + return getSchemaDefinitions(oasDocument).get(schema.$ref); + } + + return schema; + } + public static String getBasePath(OasDocument openApiDoc) { return delegate(openApiDoc, Oas20ModelHelper::getBasePath, Oas30ModelHelper::getBasePath); } @@ -160,6 +192,10 @@ public static Optional getSchema(OasResponse response) { return delegate(response, Oas20ModelHelper::getSchema, Oas30ModelHelper::getSchema); } + public static Optional getParameterSchema(OasParameter parameter) { + return delegate(parameter, Oas20ModelHelper::getParameterSchema, Oas30ModelHelper::getParameterSchema); + } + public static Map getRequiredHeaders(OasResponse response) { return delegate(response, Oas20ModelHelper::getHeaders, Oas30ModelHelper::getRequiredHeaders); } @@ -176,8 +212,27 @@ public static Optional getRequestBodySchema(OasDocument openApiDoc, O return delegate(openApiDoc, operation, Oas20ModelHelper::getRequestBodySchema, Oas30ModelHelper::getRequestBodySchema); } - public static Optional getResponseContentType(OasDocument openApiDoc, OasOperation operation) { - return delegate(openApiDoc, operation, Oas20ModelHelper::getResponseContentType, Oas30ModelHelper::getResponseContentType); + public static Collection getResponseTypes(OasOperation operation, OasResponse response) { + return delegate(operation, response, Oas20ModelHelper::getResponseTypes, Oas30ModelHelper::getResponseTypes); + } + + /** + * Determines the appropriate response from an OAS (OpenAPI Specification) operation. + * The method looks for the response status code within the range 200 to 299 and returns + * the corresponding response if one is found. The first response in the list of responses, + * that satisfies the constraint will be returned. (TODO: see comment in Oas30ModelHelper) If none of the responses has a 2xx status code, + * the first response in the list will be returned. + * + */ + public static Optional getResponseForRandomGeneration(OasDocument openApiDoc, OasOperation operation) { + return delegate(openApiDoc, operation, Oas20ModelHelper::getResponseForRandomGeneration, Oas30ModelHelper::getResponseForRandomGeneration); + } + + /** + * Returns the response type used for random response generation. See specific helper implementations for detail. + */ + public static Optional getResponseContentTypeForRandomGeneration(OasDocument openApiDoc, OasOperation operation) { + return delegate(openApiDoc, operation, Oas20ModelHelper::getResponseContentTypeForRandomGeneration, Oas30ModelHelper::getResponseContentTypeForRandomGeneration); } /** @@ -207,15 +262,51 @@ private static T delegate(OasDocument openApiDoc, Function * @return */ private static T delegate(OasResponse response, Function oas20Function, Function oas30Function) { - if (response instanceof Oas20Response) { - return oas20Function.apply((Oas20Response) response); - } else if (response instanceof Oas30Response) { - return oas30Function.apply((Oas30Response) response); + if (response instanceof Oas20Response oas20Response) { + return oas20Function.apply(oas20Response); + } else if (response instanceof Oas30Response oas30Response) { + return oas30Function.apply(oas30Response); } throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); } + /** + * Delegate method to version specific model helpers for Open API v2 or v3. + * @param response + * @param oas20Function function to apply in case of v2 + * @param oas30Function function to apply in case of v3 + * @param generic return value + * @return + */ + private static T delegate(OasOperation operation, OasResponse response, BiFunction oas20Function, BiFunction oas30Function) { + if (operation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { + return oas20Function.apply(oas20Operation, oas20Response); + } else if (operation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { + return oas30Function.apply(oas30Operation, oas30Response); + } + + throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); + } + + /** + * Delegate method to version specific model helpers for Open API v2 or v3. + * @param parameter + * @param oas20Function function to apply in case of v2 + * @param oas30Function function to apply in case of v3 + * @param generic return value + * @return + */ + private static T delegate(OasParameter parameter, Function oas20Function, Function oas30Function) { + if (parameter instanceof Oas20Parameter oas20Parameter) { + return oas20Function.apply(oas20Parameter); + } else if (parameter instanceof Oas30Parameter oas30Parameter) { + return oas30Function.apply(oas30Parameter); + } + + throw new IllegalArgumentException(String.format("Unsupported operation parameter type: %s", parameter.getClass())); + } + /** * Delegate method to version specific model helpers for Open API v2 or v3. * @param operation @@ -225,10 +316,10 @@ private static T delegate(OasResponse response, Function o * @return */ private static T delegate(OasOperation operation, Function oas20Function, Function oas30Function) { - if (operation instanceof Oas20Operation) { - return oas20Function.apply((Oas20Operation) operation); - } else if (operation instanceof Oas30Operation) { - return oas30Function.apply((Oas30Operation) operation); + if (operation instanceof Oas20Operation oas20Operation) { + return oas20Function.apply(oas20Operation); + } else if (operation instanceof Oas30Operation oas30Operation) { + return oas30Function.apply(oas30Operation); } throw new IllegalArgumentException(String.format("Unsupported operation type: %s", operation.getClass())); @@ -259,4 +350,32 @@ private static boolean isOas30(OasDocument openApiDoc) { private static boolean isOas20(OasDocument openApiDoc) { return OpenApiVersion.fromDocumentType(openApiDoc).equals(OpenApiVersion.V2); } + + /** + * Resolves all responses in the given {@link OasResponses} instance using the provided {@code responseResolver} function. + * + *

This method iterates over the responses contained in the {@link OasResponses} object. If a response has a reference + * (indicated by a non-null {@code $ref} field), the reference is resolved using the {@code responseResolver} function. Other responses + * will be added to the result list as is.

+ * + * @param responses the {@link OasResponses} instance containing the responses to be resolved. + * @param responseResolver a {@link Function} that takes a reference string and returns the corresponding {@link OasResponse}. + * @return a {@link List} of {@link OasResponse} instances, where all references have been resolved. + */ + public static List resolveResponses(OasResponses responses, Function responseResolver) { + + List responseList = new ArrayList<>(); + for (OasResponse response : responses.getResponses()) { + if (response.$ref != null) { + OasResponse resolved = responseResolver.apply(getReferenceName(response.$ref)); + if (resolved != null) { + responseList.add(resolved); + } + } else { + responseList.add(response); + } + } + + return responseList; + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index a1a5055146..114bcfa45f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -16,21 +16,26 @@ package org.citrusframework.openapi.model.v2; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - import io.apicurio.datamodels.openapi.models.OasHeader; import io.apicurio.datamodels.openapi.models.OasParameter; +import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; import io.apicurio.datamodels.openapi.v2.models.Oas20Header; import io.apicurio.datamodels.openapi.v2.models.Oas20Operation; +import io.apicurio.datamodels.openapi.v2.models.Oas20Parameter; import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition; +import jakarta.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import org.citrusframework.openapi.model.OasModelHelper; +import org.springframework.http.MediaType; public final class Oas20ModelHelper { @@ -86,14 +91,60 @@ public static Optional getRequestContentType(Oas20Operation operation) { return Optional.empty(); } - public static Optional getResponseContentType(Oas20Document openApiDoc, Oas20Operation operation) { + public static Collection getResponseTypes(Oas20Operation operation, @Nullable Oas20Response response) { + if (operation == null) { + return Collections.emptyList(); + } + return operation.produces; + } + + /** + * 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 operation + * @return + */ + public static Optional getResponseContentTypeForRandomGeneration(@Nullable Oas20Document openApiDoc, Oas20Operation operation) { if (operation.produces != null) { - return Optional.of(operation.produces.get(0)); + for (String mediaType : operation.produces) { + if (MediaType.APPLICATION_JSON_VALUE.equals(mediaType)) { + return Optional.of(mediaType); + } + } } return Optional.empty(); } + public static Optional getResponseForRandomGeneration(Oas20Document openApiDoc, Oas20Operation operation) { + + if (operation.responses == null) { + return Optional.empty(); + } + + List responses = OasModelHelper.resolveResponses(operation.responses, + responseRef -> openApiDoc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))); + + // Pick the response object related to the first 2xx return code found + Optional response = responses.stream() + .filter(Oas20Response.class::isInstance) + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .filter(res -> OasModelHelper.getSchema(res).isPresent()) + .findFirst(); + + if (response.isEmpty()) { + // TODO: Although the Swagger specification states that at least one successful response SHOULD be specified in the responses, + // the Petstore API does not. It only specifies error responses. As a result, we currently only return a successful response if one is found. + // If no successful response is specified, we return an empty response instead, to be backwards compatible. + response = Optional.empty(); + } + + return response; + } + public static Map getHeaders(Oas20Response response) { if (response.headers == null) { return Collections.emptyMap(); @@ -103,6 +154,13 @@ public static Map getHeaders(Oas20Response response) { .collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema)); } + /** + * If the header already contains a schema (and it is an instance of {@link Oas20Header}), this schema is returned. + * Otherwise, a new {@link Oas20Header} is created based on the properties of the parameter and returned. + * + * @param header the {@link Oas20Header} from which to extract or create the schema + * @return an {@link Optional} containing the extracted or newly created {@link OasSchema} + */ private static OasSchema getHeaderSchema(Oas20Header header) { Oas20Schema schema = new Oas20Schema(); schema.title = header.getName(); @@ -129,4 +187,43 @@ private static OasSchema getHeaderSchema(Oas20Header header) { schema.exclusiveMinimum = header.exclusiveMinimum; return schema; } + + /** + * If the parameter already contains a schema (and it is an instance of {@link Oas20Schema}), this schema is returned. + * Otherwise, a new {@link Oas20Schema} is created based on the properties of the parameter and returned. + * + * @param parameter the {@link Oas20Parameter} from which to extract or create the schema + * @return an {@link Optional} containing the extracted or newly created {@link OasSchema} + */ + public static Optional getParameterSchema(Oas20Parameter parameter) { + if (parameter.schema instanceof Oas20Schema oasSchema) { + return Optional.of(oasSchema); + } + + Oas20Schema schema = new Oas20Schema(); + schema.title = parameter.getName(); + schema.type = parameter.type; + schema.format = parameter.format; + schema.items = parameter.items; + schema.multipleOf = parameter.multipleOf; + + schema.default_ = parameter.default_; + schema.enum_ = parameter.enum_; + + schema.pattern = parameter.pattern; + schema.description = parameter.description; + schema.uniqueItems = parameter.uniqueItems; + + schema.maximum = parameter.maximum; + schema.maxItems = parameter.maxItems; + schema.maxLength = parameter.maxLength; + schema.exclusiveMaximum = parameter.exclusiveMaximum; + + schema.minimum = parameter.minimum; + schema.minItems = parameter.minItems; + schema.minLength = parameter.minLength; + schema.exclusiveMinimum = parameter.exclusiveMinimum; + + return Optional.of(schema); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index fec97b4c3b..859ef42627 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -16,17 +16,6 @@ package org.citrusframework.openapi.model.v3; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - import io.apicurio.datamodels.core.models.common.Server; import io.apicurio.datamodels.core.models.common.ServerVariable; import io.apicurio.datamodels.openapi.models.OasResponse; @@ -34,16 +23,31 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Document; import io.apicurio.datamodels.openapi.v3.models.Oas30MediaType; import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; +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; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import org.citrusframework.openapi.model.OasModelHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; public final class Oas30ModelHelper { /** Logger */ private static final Logger LOG = LoggerFactory.getLogger(Oas30ModelHelper.class); + public static final String NO_URL_ERROR_MESSAGE = "Unable to determine base path from server URL: %s"; private Oas30ModelHelper() { // utility class @@ -59,7 +63,7 @@ public static String getHost(Oas30Document openApiDoc) { try { return new URL(serverUrl).getHost(); } catch (MalformedURLException e) { - throw new IllegalStateException(String.format("Unable to determine base path from server URL: %s", serverUrl)); + throw new IllegalStateException(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); } } @@ -77,12 +81,12 @@ public static List getSchemes(Oas30Document openApiDoc) { try { return new URL(serverUrl).getProtocol(); } catch (MalformedURLException e) { - LOG.warn(String.format("Unable to determine base path from server URL: %s", serverUrl)); + LOG.warn(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); return null; } }) .filter(Objects::nonNull) - .collect(Collectors.toList()); + .toList(); } public static String getBasePath(Oas30Document openApiDoc) { @@ -98,7 +102,7 @@ public static String getBasePath(Oas30Document openApiDoc) { try { basePath = new URL(serverUrl).getPath(); } catch (MalformedURLException e) { - throw new IllegalStateException(String.format("Unable to determine base path from server URL: %s", serverUrl)); + throw new IllegalStateException(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); } } else { basePath = serverUrl; @@ -114,7 +118,7 @@ public static Map getSchemaDefinitions(Oas30Document openApiD return openApiDoc.components.schemas.entrySet() .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> (OasSchema) entry.getValue())); + .collect(Collectors.toMap(Map.Entry::getKey, Entry::getValue)); } public static Optional getSchema(Oas30Response response) { @@ -169,44 +173,69 @@ public static Optional getRequestContentType(Oas30Operation operation) { .findFirst(); } - public static Optional getResponseContentType(Oas30Document openApiDoc, Oas30Operation operation) { - if (operation.responses == null) { - return Optional.empty(); + public static Collection getResponseTypes(@Nullable Oas30Operation operation, Oas30Response response) { + if (operation == null) { + return Collections.emptySet(); } + return response.content != null ? response.content.keySet() : Collections.emptyList(); + } - List responses = new ArrayList<>(); + /** + * 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 operation + * @return + */ + public static Optional getResponseContentTypeForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) { + Optional responseForRandomGeneration = getResponseForRandomGeneration( + openApiDoc, operation); + return responseForRandomGeneration.map( + 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()); + } - for (OasResponse response : operation.responses.getResponses()) { - if (response.$ref != null) { - responses.add(openApiDoc.components.responses.get(OasModelHelper.getReferenceName(response.$ref))); - } else { - responses.add(response); - } + public static Optional getResponseForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) { + if (operation.responses == null) { + return Optional.empty(); } + List responses = OasModelHelper.resolveResponses(operation.responses, + responseRef -> openApiDoc.components.responses.get(OasModelHelper.getReferenceName(responseRef))); + // Pick the response object related to the first 2xx return code found - Optional response = responses.stream() - .filter(Oas30Response.class::isInstance) - .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) - .map(Oas30Response.class::cast) - .filter(res -> Oas30ModelHelper.getSchema(res).isPresent()) - .findFirst(); + Optional response = responses.stream() + .filter(Oas30Response.class::isInstance) + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .filter(res -> OasModelHelper.getSchema(res).isPresent()) + .findFirst(); // No 2xx response given so pick the first one no matter what status code - if (!response.isPresent()) { + if (response.isEmpty()) { + // TODO: This behavior differs from OAS2 and is very likely a bug because it may result in returning error messages. + // According to the specification, there MUST be at least one response, which SHOULD be a successful response. + // If the response is NOT A SUCCESSFUL one, we encounter an error case, which is likely not the intended behavior. + // The specification likely does not intend to define operations that always fail. On the other hand, it is not + // against the spec to NOT document an OK response that is empty. + // For testing purposes, note that the difference between OAS2 and OAS3 is evident in the Petstore API. + // The Petstore API specifies successful response codes for OAS3 but lacks these definitions for OAS2. + // Therefore, while tests pass for OAS3, they fail for OAS2. + // I would suggest to return an empty response in case we fail to resolve a good response, as in Oas2. + // In case of absence of a response an OK response will be sent as default. response = responses.stream() - .filter(Oas30Response.class::isInstance) - .map(Oas30Response.class::cast) - .filter(res -> Oas30ModelHelper.getSchema(res).isPresent()) - .findFirst(); + .filter(Oas30Response.class::isInstance) + .map(OasResponse.class::cast) + .filter(res -> OasModelHelper.getSchema(res).isPresent()) + .findFirst(); } - return response.flatMap(res -> res.content.entrySet() - .stream() - .filter(entry -> entry.getValue().schema != null) - .map(Map.Entry::getKey) - .findFirst()); - + return response; } public static Map getRequiredHeaders(Oas30Response response) { @@ -251,4 +280,8 @@ private static String resolveUrl(Server server) { return url; } + + public static Optional getParameterSchema(Oas30Parameter parameter) { + return Optional.ofNullable((OasSchema) parameter.schema); + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java new file mode 100644 index 0000000000..3c449ff5fe --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -0,0 +1,50 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.util.List; +import org.testng.annotations.Test; + +@Test +public class OpenApiRepositoryTest { + + public static final String ROOT = "/root"; + + public void initializeOpenApiRepository() { + OpenApiRepository openApiRepository = new OpenApiRepository(); + openApiRepository.setRootContextPath(ROOT); + openApiRepository.setLocations(List.of("org/citrusframework/openapi/petstore/petstore**.json")); + openApiRepository.initialize(); + + List openApiSpecifications = openApiRepository.getOpenApiSpecifications(); + + assertEquals(openApiRepository.getRootContextPath(), ROOT); + assertNotNull(openApiSpecifications); + assertEquals(openApiSpecifications.size(),3); + + assertEquals(openApiSpecifications.get(0).getRootContextPath(), ROOT); + assertEquals(openApiSpecifications.get(1).getRootContextPath(), ROOT); + + assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); + assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); + assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/SampleOpenApiProcessor.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/SampleOpenApiProcessor.java new file mode 100644 index 0000000000..c39605e35e --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/SampleOpenApiProcessor.java @@ -0,0 +1,30 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import java.util.ArrayList; +import java.util.List; + +public class SampleOpenApiProcessor implements OpenApiSpecificationProcessor { + + public static List processedSpecifications = new ArrayList<>(); + + @Override + public void process(OpenApiSpecification openApiSpecification) { + processedSpecifications.add(openApiSpecification); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java new file mode 100644 index 0000000000..742641ad6c --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java @@ -0,0 +1,119 @@ +package org.citrusframework.openapi.model.v2; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasResponse; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v2.models.Oas20Document; +import io.apicurio.datamodels.openapi.v2.models.Oas20Items; +import io.apicurio.datamodels.openapi.v2.models.Oas20Operation; +import io.apicurio.datamodels.openapi.v2.models.Oas20Parameter; +import io.apicurio.datamodels.openapi.v2.models.Oas20Response; +import io.apicurio.datamodels.openapi.v2.models.Oas20Responses; +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; +import java.util.List; +import java.util.Optional; +import org.testng.annotations.Test; + +public class Oas20ModelHelperTest { + + @Test + public void shouldFindRandomResponse() { + Oas20Document document = new Oas20Document(); + Oas20Operation operation = new Oas20Operation("GET"); + + operation.responses = new Oas20Responses(); + + Oas20Response nokResponse = new Oas20Response("403"); + nokResponse.schema = new Oas20Schema(); + + Oas20Response okResponse = new Oas20Response("200"); + okResponse.schema = new Oas20Schema(); + + operation.responses = new Oas20Responses(); + operation.responses.addResponse("403", nokResponse); + operation.responses.addResponse("200", okResponse); + + Optional responseForRandomGeneration = Oas20ModelHelper.getResponseForRandomGeneration( + document, operation); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(okResponse, responseForRandomGeneration.get()); + } + + @Test + public void shouldNotFindAnyResponse() { + Oas20Document document = new Oas20Document(); + Oas20Operation operation = new Oas20Operation("GET"); + + operation.responses = new Oas20Responses(); + + Oas20Response nokResponse403 = new Oas20Response("403"); + Oas20Response nokResponse407 = new Oas20Response("407"); + + operation.responses = new Oas20Responses(); + operation.responses.addResponse("403", nokResponse403); + operation.responses.addResponse("407", nokResponse407); + + Optional responseForRandomGeneration = Oas20ModelHelper.getResponseForRandomGeneration( + document, operation); + assertTrue(responseForRandomGeneration.isEmpty()); + } + + @Test + public void shouldFindParameterSchema() { + Oas20Parameter parameter = new Oas20Parameter(); + parameter.schema = new Oas20Schema(); + + Optional parameterSchema = Oas20ModelHelper.getParameterSchema(parameter); + assertTrue(parameterSchema.isPresent()); + assertEquals(parameter.schema, parameterSchema.get()); + } + + @Test + public void shouldFindSchemaFromParameter() { + Oas20Parameter parameter = new Oas20Parameter("testParameter"); + parameter.type = "string"; + parameter.format = "date-time"; + parameter.items = new Oas20Items(); + parameter.multipleOf = 2; + parameter.default_ = "defaultValue"; + parameter.enum_ = List.of("value1", "value2"); + parameter.pattern = "pattern"; + parameter.description = "description"; + parameter.uniqueItems = true; + parameter.maximum = 100.0; + parameter.maxItems = 10; + parameter.maxLength = 20; + parameter.exclusiveMaximum = true; + parameter.minimum = 0.0; + parameter.minItems = 1; + parameter.minLength = 5; + parameter.exclusiveMinimum = false; + + Optional schemaOptional = Oas20ModelHelper.getParameterSchema(parameter); + assertTrue(schemaOptional.isPresent()); + + OasSchema parameterSchema = schemaOptional.get(); + assertEquals(parameterSchema.title, "testParameter"); + assertEquals(parameterSchema.type, "string"); + assertEquals(parameterSchema.format, "date-time"); + assertEquals(parameter.items, parameterSchema.items); + assertEquals(parameter.multipleOf, parameterSchema.multipleOf); + assertEquals(parameter.default_, parameterSchema.default_); + assertEquals(parameter.enum_, parameterSchema.enum_); + assertEquals(parameter.pattern, parameterSchema.pattern); + assertEquals(parameter.description, parameterSchema.description); + assertEquals(parameter.uniqueItems, parameterSchema.uniqueItems); + assertEquals(parameter.maximum, parameterSchema.maximum); + assertEquals(parameter.maxItems, parameterSchema.maxItems); + assertEquals(parameter.maxLength, parameterSchema.maxLength); + assertEquals(parameter.exclusiveMaximum, parameterSchema.exclusiveMaximum); + assertEquals(parameter.minimum, parameterSchema.minimum); + assertEquals(parameter.minItems, parameterSchema.minItems); + assertEquals(parameter.minLength, parameterSchema.minLength); + assertEquals(parameter.exclusiveMinimum, parameterSchema.exclusiveMinimum); + + } + +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java index 38d8b13fde..8735ecd083 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java @@ -1,13 +1,24 @@ package org.citrusframework.openapi.model.v3; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Document; import io.apicurio.datamodels.openapi.v3.models.Oas30Header; +import io.apicurio.datamodels.openapi.v3.models.Oas30MediaType; +import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; +import io.apicurio.datamodels.openapi.v3.models.Oas30Parameter; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; +import io.apicurio.datamodels.openapi.v3.models.Oas30Responses; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import org.testng.Assert; -import org.testng.annotations.Test; - +import java.util.Collection; import java.util.Map; +import java.util.Optional; +import org.springframework.http.MediaType; +import org.testng.annotations.Test; public class Oas30ModelHelperTest { @@ -15,40 +26,135 @@ public class Oas30ModelHelperTest { public void shouldNotFindRequiredHeadersWithoutRequiredAttribute() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = null; // explicitely assigned because this is test case + header.required = null; // explicitly assigned because this is test case var response = new Oas30Response("200"); response.headers.put(header.getName(), header); Map result = Oas30ModelHelper.getRequiredHeaders(response); - Assert.assertEquals(result.size(), 0); + assertEquals(result.size(), 0); } @Test public void shouldFindRequiredHeaders() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = Boolean.TRUE; // explicitely assigned because this is test case + header.required = Boolean.TRUE; // explicitly assigned because this is test case var response = new Oas30Response("200"); response.headers.put(header.getName(), header); Map result = Oas30ModelHelper.getRequiredHeaders(response); - Assert.assertEquals(result.size(), 1); - Assert.assertSame(result.get(header.getName()), header.schema); + assertEquals(result.size(), 1); + assertSame(result.get(header.getName()), header.schema); } @Test public void shouldNotFindOptionalHeaders() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = Boolean.FALSE; // explicitely assigned because this is test case + header.required = Boolean.FALSE; // explicitly assigned because this is test case var response = new Oas30Response("200"); response.headers.put(header.getName(), header); Map result = Oas30ModelHelper.getRequiredHeaders(response); - Assert.assertEquals(result.size(), 0); + assertEquals(result.size(), 0); + } + + @Test + public void shouldFindAllRequestTypesForOperation() { + Oas30Operation operation = new Oas30Operation("GET"); + operation.responses = new Oas30Responses(); + + Oas30Response response = new Oas30Response("200"); + response.content = Map.of(MediaType.APPLICATION_JSON_VALUE, + new Oas30MediaType(MediaType.APPLICATION_JSON_VALUE), + MediaType.APPLICATION_XML_VALUE, new Oas30MediaType(MediaType.APPLICATION_XML_VALUE)); + + operation.responses = new Oas30Responses(); + operation.responses.addResponse("200", response); + + Collection responseTypes = Oas30ModelHelper.getResponseTypes(operation, response); + + assertTrue(responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)); + assertTrue(responseTypes.contains(MediaType.APPLICATION_XML_VALUE)); + + } + + @Test + public void shouldFindRandomResponse() { + Oas30Document document = new Oas30Document(); + Oas30Operation operation = new Oas30Operation("GET"); + + operation.responses = new Oas30Responses(); + + Oas30Response nokResponse = new Oas30Response("403"); + Oas30MediaType plainTextMediaType = new Oas30MediaType(MediaType.TEXT_PLAIN_VALUE); + plainTextMediaType.schema = new Oas30Schema(); + nokResponse.content = Map.of(MediaType.TEXT_PLAIN_VALUE, plainTextMediaType); + + Oas30Response okResponse = new Oas30Response("200"); + Oas30MediaType jsonMediaType = new Oas30MediaType(MediaType.APPLICATION_JSON_VALUE); + jsonMediaType.schema = new Oas30Schema(); + + Oas30MediaType xmlMediaType = new Oas30MediaType(MediaType.APPLICATION_XML_VALUE); + xmlMediaType.schema = new Oas30Schema(); + + okResponse.content = Map.of(MediaType.APPLICATION_JSON_VALUE, jsonMediaType, + MediaType.APPLICATION_XML_VALUE, xmlMediaType); + + operation.responses = new Oas30Responses(); + operation.responses.addResponse("403", nokResponse); + operation.responses.addResponse("200", okResponse); + + Optional responseForRandomGeneration = Oas30ModelHelper.getResponseForRandomGeneration( + document, operation); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(okResponse, responseForRandomGeneration.get()); + } + + @Test + public void shouldFindAnyResponse() { + Oas30Document document = new Oas30Document(); + Oas30Operation operation = new Oas30Operation("GET"); + + operation.responses = new Oas30Responses(); + + Oas30Response nokResponse403 = new Oas30Response("403"); + Oas30MediaType plainTextMediaType = new Oas30MediaType(MediaType.TEXT_PLAIN_VALUE); + plainTextMediaType.schema = new Oas30Schema(); + nokResponse403.content = Map.of(MediaType.TEXT_PLAIN_VALUE, plainTextMediaType); + + Oas30Response nokResponse407 = new Oas30Response("407"); + nokResponse407.content = Map.of(MediaType.TEXT_PLAIN_VALUE, plainTextMediaType); + + operation.responses = new Oas30Responses(); + operation.responses.addResponse("403", nokResponse403); + operation.responses.addResponse("407", nokResponse407); + + Optional responseForRandomGeneration = Oas30ModelHelper.getResponseForRandomGeneration( + document, operation); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(nokResponse403, responseForRandomGeneration.get()); + } + + @Test + public void shouldFindParameterSchema() { + Oas30Parameter parameter = new Oas30Parameter(); + parameter.schema = new Oas30Schema(); + + Optional parameterSchema = Oas30ModelHelper.getParameterSchema(parameter); + assertTrue(parameterSchema.isPresent()); + assertEquals(parameter.schema, parameterSchema.get()); + } + + @Test + public void shouldNotFindParameterSchema() { + Oas30Parameter parameter = new Oas30Parameter(); + + Optional parameterSchema = Oas30ModelHelper.getParameterSchema(parameter); + assertTrue(parameterSchema.isEmpty()); } } \ No newline at end of file diff --git a/connectors/citrus-openapi/src/test/resources/META-INF/citrus/openapi/processor/sampleOpenApiProcessor b/connectors/citrus-openapi/src/test/resources/META-INF/citrus/openapi/processor/sampleOpenApiProcessor new file mode 100644 index 0000000000..1092e9da72 --- /dev/null +++ b/connectors/citrus-openapi/src/test/resources/META-INF/citrus/openapi/processor/sampleOpenApiProcessor @@ -0,0 +1,2 @@ +name=sampleOpenApiProcessor +type=org.citrusframework.openapi.SampleOpenApiProcessor diff --git a/core/citrus-api/src/main/java/org/citrusframework/spi/ReferenceResolverAware.java b/core/citrus-api/src/main/java/org/citrusframework/spi/ReferenceResolverAware.java index 0e741bbde5..b2b97fe318 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/spi/ReferenceResolverAware.java +++ b/core/citrus-api/src/main/java/org/citrusframework/spi/ReferenceResolverAware.java @@ -16,12 +16,13 @@ package org.citrusframework.spi; +import jakarta.annotation.Nullable; + @FunctionalInterface public interface ReferenceResolverAware { /** * Sets the reference resolver. - * @param referenceResolver */ - void setReferenceResolver(ReferenceResolver referenceResolver); + void setReferenceResolver(@Nullable ReferenceResolver referenceResolver); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/repository/BaseRepository.java b/core/citrus-base/src/main/java/org/citrusframework/repository/BaseRepository.java new file mode 100644 index 0000000000..eae38431bd --- /dev/null +++ b/core/citrus-base/src/main/java/org/citrusframework/repository/BaseRepository.java @@ -0,0 +1,107 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.repository; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.citrusframework.common.InitializingPhase; +import org.citrusframework.common.Named; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.ClasspathResourceResolver; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.StringUtils; + +/** + * Base class for repositories providing common functionality for initializing and managing resources. + * Implementations must provide the logic for loading and adding resources to the repository. + */ +public abstract class BaseRepository implements Named, InitializingPhase { + + private String name; + + /** List of location patterns that will be translated to schema resources */ + private List locations = new ArrayList<>(); + + protected BaseRepository(String name) { + this.name = name; + } + + @Override + public void initialize() { + try { + ClasspathResourceResolver resourceResolver = new ClasspathResourceResolver(); + for (String location : locations) { + Resource found = Resources.create(location); + if (found.exists()) { + addRepository(found); + } else { + Set findings; + if (StringUtils.hasText(FileUtils.getFileExtension(location))) { + String fileNamePattern = FileUtils.getFileName(location).replace(".", "\\.").replace("*", ".*"); + String basePath = FileUtils.getBasePath(location); + findings = resourceResolver.getResources(basePath, fileNamePattern); + } else { + findings = resourceResolver.getResources(location); + } + + for (Path resource : findings) { + addRepository(Resources.fromClasspath(resource.toString())); + } + } + } + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to initialize repository", e); + } + } + + protected abstract void addRepository(Resource resource); + + @Override + public void setName(String name) { + this.name = name; + } + + /** + * Gets the name. + * @return the name to get. + */ + public String getName() { + return name; + } + + /** + * Gets the locations. + * @return the locations to get. + */ + public List getLocations() { + return locations; + } + + /** + * Sets the locations. + * @param locations the locations to set + */ + public void setLocations(List locations) { + this.locations = locations; + } + +} diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index cfb32699c2..33b94a02ef 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -38,4 +38,25 @@ public static boolean hasText(String str) { public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } + + public static String appendSegmentToPath(String path, String segment) { + + if (path == null) { + return segment; + } + + if (segment == null) { + return path; + } + + if (!path.endsWith("/")) { + path = path +"/"; + } + + if (segment.startsWith("/")) { + segment = segment.substring(1); + } + + return path+segment; + } } diff --git a/validation/citrus-validation-json/src/main/java/org/citrusframework/json/JsonSchemaRepository.java b/validation/citrus-validation-json/src/main/java/org/citrusframework/json/JsonSchemaRepository.java index 754bb63652..c3dfc33a37 100644 --- a/validation/citrus-validation-json/src/main/java/org/citrusframework/json/JsonSchemaRepository.java +++ b/validation/citrus-validation-json/src/main/java/org/citrusframework/json/JsonSchemaRepository.java @@ -16,21 +16,11 @@ package org.citrusframework.json; -import java.io.IOException; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Set; - -import org.citrusframework.common.InitializingPhase; -import org.citrusframework.common.Named; -import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.json.schema.SimpleJsonSchema; -import org.citrusframework.spi.ClasspathResourceResolver; +import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; -import org.citrusframework.spi.Resources; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,70 +28,35 @@ * Schema repository holding a set of json schema resources known in the test scope. * @since 2.7.3 */ -public class JsonSchemaRepository implements Named, InitializingPhase { +public class JsonSchemaRepository extends BaseRepository { - /** This repositories name in the Spring application context */ - private String name; + private static final String DEFAULT_NAME = "jsonSchemaRepository"; /** List of schema resources */ private List schemas = new ArrayList<>(); - /** List of location patterns that will be translated to schema resources */ - private List locations = new ArrayList<>(); /** Logger */ private static Logger logger = LoggerFactory.getLogger(JsonSchemaRepository.class); - @Override - public void setName(String name) { - this.name = name; + public JsonSchemaRepository() { + super(DEFAULT_NAME); } - @Override - public void initialize() { - try { - ClasspathResourceResolver resourceResolver = new ClasspathResourceResolver(); - for (String location : locations) { - Resource found = Resources.create(location); - if (found.exists()) { - addSchemas(found); - } else { - Set findings; - if (StringUtils.hasText(FileUtils.getFileExtension(location))) { - String fileNamePattern = FileUtils.getFileName(location).replace(".", "\\.").replace("*", ".*"); - String basePath = FileUtils.getBasePath(location); - findings = resourceResolver.getResources(basePath, fileNamePattern); - } else { - findings = resourceResolver.getResources(location); - } - - for (Path resource : findings) { - addSchemas(Resources.fromClasspath(resource.toString())); - } - } - } - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to initialize Json schema repository", e); - } - } - private void addSchemas(Resource resource) { + protected void addRepository(Resource resource) { if (resource.getLocation().endsWith(".json")) { if (logger.isDebugEnabled()) { - logger.debug("Loading json schema resource " + resource.getLocation()); + logger.debug("Loading json schema resource '{}'", resource.getLocation()); } SimpleJsonSchema simpleJsonSchema = new SimpleJsonSchema(resource); simpleJsonSchema.initialize(); schemas.add(simpleJsonSchema); } else { - logger.warn("Skipped resource other than json schema for repository (" + resource.getLocation() + ")"); + logger.warn("Skipped resource other than json schema for repository '{}'", resource.getLocation()); } } - public String getName() { - return name; - } - public List getSchemas() { return schemas; } @@ -118,11 +73,7 @@ public static void setLog(Logger logger) { JsonSchemaRepository.logger = logger; } - public List getLocations() { - return locations; - } - - public void setLocations(List locations) { - this.locations = locations; + public void addSchema(SimpleJsonSchema simpleJsonSchema) { + schemas.add(simpleJsonSchema); } } diff --git a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/schema/JsonSchemaValidationTest.java b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/schema/JsonSchemaValidationTest.java index 9ca46b5290..1ec1183b83 100644 --- a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/schema/JsonSchemaValidationTest.java +++ b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/schema/JsonSchemaValidationTest.java @@ -34,6 +34,7 @@ import org.citrusframework.validation.json.report.GraciousProcessingReport; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -58,12 +59,21 @@ public class JsonSchemaValidationTest { private JsonSchemaValidation fixture; + private AutoCloseable mocks; + @BeforeMethod void beforeMethodSetup() { - MockitoAnnotations.openMocks(this); + mocks = MockitoAnnotations.openMocks(this); fixture = new JsonSchemaValidation(jsonSchemaFilterMock); } + @AfterMethod + void afterMethod() throws Exception { + if (mocks != null) { + mocks.close(); + } + } + @Test public void testValidJsonMessageSuccessfullyValidated() { // Setup json schema repositories @@ -263,7 +273,7 @@ public void testJsonSchemaFilterIsCalled() { @Test public void testLookup() { Map> validators = SchemaValidator.lookup(); - assertEquals(validators.size(), 1L); + assertEquals(1L, validators.size()); assertNotNull(validators.get("defaultJsonSchemaValidator")); assertEquals(validators.get("defaultJsonSchemaValidator").getClass(), JsonSchemaValidation.class); } diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/xml/XsdSchemaRepository.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/xml/XsdSchemaRepository.java index a8847e9995..dcc95220b0 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/xml/XsdSchemaRepository.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/xml/XsdSchemaRepository.java @@ -17,20 +17,14 @@ package org.citrusframework.xml; import java.io.IOException; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; -import java.util.Set; import javax.xml.parsers.ParserConfigurationException; - -import org.citrusframework.common.InitializingPhase; -import org.citrusframework.common.Named; import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.ClasspathResourceResolver; +import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; import org.citrusframework.util.FileUtils; -import org.citrusframework.util.StringUtils; import org.citrusframework.xml.schema.TargetNamespaceSchemaMappingStrategy; import org.citrusframework.xml.schema.WsdlXsdSchema; import org.citrusframework.xml.schema.XsdSchemaMappingStrategy; @@ -47,22 +41,23 @@ * */ @SuppressWarnings("unused") -public class XsdSchemaRepository implements Named, InitializingPhase { - /** The name of the repository */ - private String name = "schemaRepository"; +public class XsdSchemaRepository extends BaseRepository { + + private static final String DEFAULT_NAME = "schemaRepository"; /** List of schema resources */ private List schemas = new ArrayList<>(); - /** List of location patterns that will be translated to schema resources */ - private List locations = new ArrayList<>(); - /** Mapping strategy */ private XsdSchemaMappingStrategy schemaMappingStrategy = new TargetNamespaceSchemaMappingStrategy(); /** Logger */ private static final Logger logger = LoggerFactory.getLogger(XsdSchemaRepository.class); + public XsdSchemaRepository() { + super(DEFAULT_NAME); + } + /** * Find the matching schema for document using given schema mapping strategy. * @param doc the document instance to validate. @@ -75,28 +70,8 @@ public boolean canValidate(Document doc) { @Override public void initialize() { + super.initialize(); try { - ClasspathResourceResolver resourceResolver = new ClasspathResourceResolver(); - for (String location : locations) { - Resource found = Resources.create(location); - if (found.exists()) { - addSchemas(found); - } else { - Set findings; - if (StringUtils.hasText(FileUtils.getFileExtension(location))) { - String fileNamePattern = FileUtils.getFileName(location).replace(".", "\\.").replace("*", ".*"); - String basePath = FileUtils.getBasePath(location); - findings = resourceResolver.getResources(basePath, fileNamePattern); - } else { - findings = resourceResolver.getResources(location); - } - - for (Path resource : findings) { - addSchemas(Resources.fromClasspath(resource.toString())); - } - } - } - // Add default Citrus message schemas if available on classpath addCitrusSchema("citrus-http-message"); addCitrusSchema("citrus-mail-message"); @@ -104,7 +79,7 @@ public void initialize() { addCitrusSchema("citrus-ssh-message"); addCitrusSchema("citrus-rmi-message"); addCitrusSchema("citrus-jmx-message"); - } catch (SAXException | ParserConfigurationException | IOException e) { + } catch (SAXException | ParserConfigurationException e) { throw new CitrusRuntimeException("Failed to initialize Xsd schema repository", e); } } @@ -113,26 +88,26 @@ public void initialize() { * Adds Citrus message schema to repository if available on classpath. * @param schemaName The name of the schema within the citrus schema package */ - protected void addCitrusSchema(String schemaName) throws IOException, SAXException, ParserConfigurationException { + protected void addCitrusSchema(String schemaName) throws SAXException, ParserConfigurationException { Resource resource = Resources.fromClasspath("classpath:org/citrusframework/schema/" + schemaName + ".xsd"); if (resource.exists()) { addXsdSchema(resource); } } - private void addSchemas(Resource resource) { + protected void addRepository(Resource resource) { if (resource.getLocation().endsWith(".xsd")) { addXsdSchema(resource); } else if (resource.getLocation().endsWith(".wsdl")) { addWsdlSchema(resource); } else { - logger.warn("Skipped resource other than XSD schema for repository (" + resource.getLocation() + ")"); + logger.warn("Skipped resource other than XSD schema for repository '{}'", resource.getLocation()); } } private void addWsdlSchema(Resource resource) { if (logger.isDebugEnabled()) { - logger.debug("Loading WSDL schema resource " + resource.getLocation()); + logger.debug("Loading WSDL schema resource '{}'", resource.getLocation()); } WsdlXsdSchema wsdl = new WsdlXsdSchema(resource); @@ -142,7 +117,7 @@ private void addWsdlSchema(Resource resource) { private void addXsdSchema(Resource resource) { if (logger.isDebugEnabled()) { - logger.debug("Loading XSD schema resource " + resource.getLocation()); + logger.debug("Loading XSD schema resource '{}'", resource.getLocation()); } SimpleXsdSchema schema = new SimpleXsdSchema(new ByteArrayResource(FileUtils.copyToByteArray(resource))); @@ -185,33 +160,4 @@ public void setSchemaMappingStrategy(XsdSchemaMappingStrategy schemaMappingStrat public XsdSchemaMappingStrategy getSchemaMappingStrategy() { return schemaMappingStrategy; } - - @Override - public void setName(String name) { - this.name = name; - } - - /** - * Gets the name. - * @return the name to get. - */ - public String getName() { - return name; - } - - /** - * Gets the locations. - * @return the locations to get. - */ - public List getLocations() { - return locations; - } - - /** - * Sets the locations. - * @param locations the locations to set - */ - public void setLocations(List locations) { - this.locations = locations; - } } From f453c35686c5c32f6872729515ed479a3b107150 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Tue, 11 Jun 2024 07:21:00 +0200 Subject: [PATCH 02/47] fix(#1175): OpenAPI connector enhancements for simulator random message generation --- connectors/citrus-openapi/pom.xml | 6 ++ .../OpenApiClientResponseActionBuilder.java | 1 + .../openapi/model/OasModelHelper.java | 17 ++-- .../openapi/model/v2/Oas20ModelHelper.java | 18 ++-- .../openapi/model/v3/Oas30ModelHelper.java | 83 +++++++++---------- 5 files changed, 65 insertions(+), 60 deletions(-) diff --git a/connectors/citrus-openapi/pom.xml b/connectors/citrus-openapi/pom.xml index b842f11d8a..02a0d19012 100644 --- a/connectors/citrus-openapi/pom.xml +++ b/connectors/citrus-openapi/pom.xml @@ -76,6 +76,12 @@ ${project.version} test
+ + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + 2.17.0 + compile + diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index bc1ad3370e..de47454232 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -96,6 +96,7 @@ public static void fillMessageFromResponse(OpenApiSpecification openApiSpecifica } } ); + } private static void fillRequiredHeaders( diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index c081e8013b..94f966901e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -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); } @@ -64,8 +64,8 @@ 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); } /** @@ -73,14 +73,14 @@ public static boolean isArrayType(OasSchema schema) { * @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)); } @@ -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; } @@ -191,7 +191,6 @@ public static String getReferenceName(String reference) { public static Optional getSchema(OasResponse response) { return delegate(response, Oas20ModelHelper::getSchema, Oas30ModelHelper::getSchema); } - public static Optional getParameterSchema(OasParameter parameter) { return delegate(parameter, Oas20ModelHelper::getParameterSchema, Oas30ModelHelper::getParameterSchema); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index 114bcfa45f..8cb66e20fc 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -53,12 +53,12 @@ public static List 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 getSchemaDefinitions(Oas20Document openApiDoc) { if (openApiDoc == null - || openApiDoc.definitions == null) { + || openApiDoc.definitions == null) { return Collections.emptyMap(); } @@ -69,7 +69,7 @@ public static Optional getSchema(Oas20Response response) { return Optional.ofNullable(response.schema); } - public static Optional getRequestBodySchema(Oas20Document openApiDoc, Oas20Operation operation) { + public static Optional getRequestBodySchema(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { if (operation.parameters == null) { return Optional.empty(); } @@ -77,8 +77,8 @@ public static Optional getRequestBodySchema(Oas20Document openApiDoc, final List operationParameters = operation.parameters; Optional 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); } @@ -91,7 +91,7 @@ public static Optional getRequestContentType(Oas20Operation operation) { return Optional.empty(); } - public static Collection getResponseTypes(Oas20Operation operation, @Nullable Oas20Response response) { + public static Collection getResponseTypes(Oas20Operation operation,@Nullable Oas20Response ignoredResponse) { if (operation == null) { return Collections.emptyList(); } @@ -102,11 +102,11 @@ public static Collection 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 getResponseContentTypeForRandomGeneration(@Nullable Oas20Document openApiDoc, Oas20Operation operation) { + public static Optional getResponseContentTypeForRandomGeneration(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { if (operation.produces != null) { for (String mediaType : operation.produces) { if (MediaType.APPLICATION_JSON_VALUE.equals(mediaType)) { @@ -151,7 +151,7 @@ public static Map getHeaders(Oas20Response response) { } return response.headers.getHeaders().stream() - .collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema)); + .collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema)); } /** diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 859ef42627..cfc3dd1efe 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -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; @@ -76,17 +75,17 @@ public static List 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) { @@ -117,8 +116,8 @@ public static Map 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 getSchema(Oas30Response response) { @@ -128,11 +127,11 @@ public static Optional 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 getRequestBodySchema(Oas30Document openApiDoc, Oas30Operation operation) { @@ -143,8 +142,8 @@ public static Optional 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)); } @@ -153,12 +152,12 @@ public static Optional 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 getRequestContentType(Oas30Operation operation) { @@ -167,13 +166,13 @@ public static Optional 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 getResponseTypes(@Nullable Oas30Operation operation, Oas30Response response) { + public static Collection getResponseTypes(Oas30Operation operation, Oas30Response response) { if (operation == null) { return Collections.emptySet(); } @@ -192,12 +191,12 @@ public static Optional getResponseContentTypeForRandomGeneration(Oas30Do Optional 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 getResponseForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) { @@ -244,9 +243,9 @@ public static Map 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 getHeaders(Oas30Response response) { @@ -255,8 +254,8 @@ public static Map 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) { From e911e28e0dc5f7016503e8031b74a7ad3f1aea00 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Fri, 21 Jun 2024 07:27:10 +0200 Subject: [PATCH 03/47] feat(#1175): Add OpenApiRepository and Validation --- connectors/citrus-openapi/pom.xml | 11 +- .../openapi/OpenApiPathRegistry.java | 191 +++++++++ .../openapi/OpenApiRepository.java | 90 +++- .../openapi/OpenApiResourceLoader.java | 138 ++++++- .../openapi/OpenApiSettings.java | 49 +++ .../openapi/OpenApiSpecification.java | 346 ++++++++++++++-- .../openapi/OpenApiSpecificationAdapter.java | 43 ++ .../openapi/OpenApiTestDataGenerator.java | 40 +- .../citrusframework/openapi/OpenApiUtils.java | 55 +++ .../OpenApiClientRequestActionBuilder.java | 134 +++--- .../OpenApiClientResponseActionBuilder.java | 63 ++- .../actions/OpenApiServerActionBuilder.java | 16 +- .../OpenApiServerRequestActionBuilder.java | 167 ++++---- .../OpenApiServerResponseActionBuilder.java | 229 ++++++++--- .../openapi/model/OasAdapter.java | 24 ++ .../openapi/model/OasModelHelper.java | 207 ++++++++-- .../openapi/model/OasOperationVisitor.java | 28 ++ .../openapi/model/OperationPathAdapter.java | 39 ++ .../openapi/model/v2/Oas20ModelHelper.java | 84 ++-- .../openapi/model/v3/Oas30ModelHelper.java | 159 +++---- .../OpenApiRequestValidationProcessor.java | 60 +++ .../validation/OpenApiRequestValidator.java | 97 +++++ .../OpenApiResponseValidationProcessor.java | 58 +++ .../validation/OpenApiResponseValidator.java | 77 ++++ .../openapi/validation/OpenApiValidator.java | 61 +++ .../openapi/OpenApiPathRegistryTest.java | 171 ++++++++ .../openapi/OpenApiRepositoryTest.java | 86 +++- .../openapi/OpenApiSettingsTest.java | 196 +++++++++ .../OpenApiSpecificationAdapterTest.java | 49 +++ .../openapi/OpenApiSpecificationTest.java | 387 ++++++++++++++++++ .../openapi/OpenApiTestDataGeneratorTest.java | 49 +++ .../openapi/OpenApiUtilsTest.java | 80 ++++ .../openapi/groovy/OpenApiServerTest.java | 118 +++--- .../openapi/integration/OpenApiClientIT.java | 104 ++++- .../openapi/integration/OpenApiServerIT.java | 121 +++++- .../model/OperationPathAdapterTest.java | 34 ++ .../model/v2/Oas20ModelHelperTest.java | 41 +- .../model/v3/Oas30ModelHelperTest.java | 48 ++- ...OpenApiRequestValidationProcessorTest.java | 118 ++++++ .../OpenApiRequestValidatorTest.java | 148 +++++++ ...penApiResponseValidationProcessorTest.java | 114 ++++++ .../OpenApiResponseValidatorTest.java | 128 ++++++ .../openapi/xml/OpenApiClientTest.java | 4 +- .../openapi/xml/OpenApiServerTest.java | 3 +- .../openapi/yaml/OpenApiServerTest.java | 3 +- .../openapi/petstore/pet_invalid.json | 15 + .../openapi/ping/ping-api.yaml | 244 +++++++++++ .../message/DefaultMessage.java | 1 + .../org/citrusframework/util/StringUtils.java | 12 +- .../http/message/HttpMessage.java | 6 +- pom.xml | 31 +- .../spring/TestNGCitrusSpringSupport.java | 8 +- 52 files changed, 4180 insertions(+), 605 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasOperationVisitor.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java create mode 100644 connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/pet_invalid.json create mode 100644 connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml diff --git a/connectors/citrus-openapi/pom.xml b/connectors/citrus-openapi/pom.xml index 02a0d19012..d01061c17e 100644 --- a/connectors/citrus-openapi/pom.xml +++ b/connectors/citrus-openapi/pom.xml @@ -45,6 +45,11 @@ io.apicurio apicurio-data-models + + com.atlassian.oai + swagger-request-validator-core + 2.40.0 + com.fasterxml.jackson.datatype jackson-datatype-jsr310 @@ -76,12 +81,6 @@ ${project.version} test - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - 2.17.0 - compile - diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java new file mode 100644 index 0000000000..1c05877806 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java @@ -0,0 +1,191 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static java.lang.String.format; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A registry to store objects by OpenApi paths. The registry uses a digital tree data structure + * that performs path matching with variable placeholders. Variable + * placeholders must be enclosed in curly braces '{}', e.g., '/api/v1/pet/{id}'. This data structure + * is optimized for matching paths efficiently, handling both static and dynamic segments. + *

+ * This class is currently not in use but may serve scenarios where a path needs to be mapped to an + * OasOperation without explicit knowledge of the API to which the path belongs. + * It could be utilized, for instance, in implementing an OAS message validator based on + * {@link org.citrusframework.validation.AbstractMessageValidator}. + */ +public class OpenApiPathRegistry { + + private static final Logger logger = LoggerFactory.getLogger(OpenApiPathRegistry.class); + + private final RegistryNode root = new RegistryNode(); + + private final Map allPaths = new ConcurrentHashMap<>(); + + public T search(String path) { + RegistryNode trieNode = internalSearch(path); + return trieNode != null ? trieNode.value : null; + } + + RegistryNode internalSearch(String path) { + String[] segments = path.split("/"); + return searchHelper(root, segments, 0); + } + + public boolean insert(String path, T value) { + return insertInternal(path, value) != null; + } + + RegistryNode insertInternal(String path, T value) { + + if (path == null || value == null) { + return null; + } + + String[] segments = path.split("/"); + RegistryNode node = root; + + if (!allPaths.isEmpty() && (isPathAlreadyContainedWithDifferentValue(path, value) + || isPathMatchedByOtherPath(path, value))) { + return null; + } + + allPaths.put(path, value); + StringBuilder builder = new StringBuilder(); + for (String segment : segments) { + if (builder.isEmpty() || builder.charAt(builder.length() - 1) != '/') { + builder.append("/"); + } + builder.append(segment); + + if (!node.children.containsKey(segment)) { + RegistryNode trieNode = new RegistryNode(); + trieNode.path = builder.toString(); + node.children.put(segment, trieNode); + } + node = node.children.get(segment); + } + + // Sanity check to disallow overwrite of existing values + if (node.value != null && !node.value.equals(value)) { + throw new CitrusRuntimeException(format( + "Illegal attempt to overwrite an existing node value. This is probably a bug. path=%s value=%s", + node.path, node.value)); + } + node.value = value; + + return node; + } + + /** + * Tests if the path is either matching an existing path or any existing path matches the given + * patch. + *

+ * For example '/a/b' does not match '/{a}/{b}', but '/{a}/{b}' matches '/a/b'. + */ + private boolean isPathMatchedByOtherPath(String path, T value) { + + // Does the given path match any existing + RegistryNode currentValue = internalSearch(path); + if (currentValue != null && !Objects.equals(path, currentValue.path)) { + logger.error( + "Attempt to insert an equivalent path potentially overwriting an existing value. Value for path is ignored: path={}, value={} currentValue={} ", + path, currentValue, value); + return true; + } + + // Does any existing match the path. + OpenApiPathRegistry tmpTrie = new OpenApiPathRegistry<>(); + tmpTrie.insert(path, value); + + List allMatching = allPaths.keySet().stream() + .filter(existingPath -> { + RegistryNode trieNode = tmpTrie.internalSearch(existingPath); + return trieNode != null && !existingPath.equals(trieNode.path); + }).map(existingPath -> "'" + existingPath + "'").toList(); + if (!allMatching.isEmpty() && logger.isErrorEnabled()) { + logger.error( + "Attempt to insert an equivalent path overwritten by existing paths. Value for path is ignored: path={}, value={} existingPaths=[{}]", + path, currentValue, String.join(",", allMatching)); + + } + + return !allMatching.isEmpty(); + } + + private boolean isPathAlreadyContainedWithDifferentValue(String path, T value) { + T currentValue = allPaths.get(path); + if (currentValue != null) { + if (value.equals(currentValue)) { + return false; + } + logger.error( + "Attempt to overwrite value for path is ignored: path={}, value={} currentValue={} ", + path, currentValue, value); + return true; + } + return false; + } + + private RegistryNode searchHelper(RegistryNode node, String[] segments, int index) { + if (node == null) { + return null; + } + if (index == segments.length) { + return node; + } + + String segment = segments[index]; + + // Exact match + if (node.children.containsKey(segment)) { + RegistryNode foundNode = searchHelper(node.children.get(segment), segments, index + 1); + if (foundNode != null && foundNode.value != null) { + return foundNode; + } + } + + // Variable match + for (String key : node.children.keySet()) { + if (key.startsWith("{") && key.endsWith("}")) { + RegistryNode foundNode = searchHelper(node.children.get(key), segments, index + 1); + if (foundNode != null && foundNode.value != null) { + return foundNode; + } + } + } + + return null; + } + + class RegistryNode { + Map children = new HashMap<>(); + String path; + T value = null; + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 75b62e59c7..36f113ea83 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -16,26 +16,45 @@ package org.citrusframework.openapi; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * OpenApi repository holding a set of {@link OpenApiSpecification} known in the test scope. + * * @since 4.4.0 */ public class OpenApiRepository extends BaseRepository { + private static final Logger logger = LoggerFactory.getLogger(OpenApiRepository.class); + private static final String DEFAULT_NAME = "openApiSchemaRepository"; - /** List of schema resources */ + /** + * List of schema resources + */ private final List openApiSpecifications = new ArrayList<>(); - - /** An optional context path, used for each api, without taking into account any {@link OpenApiSpecification} specific context path. */ + /** + * An optional context path, used for each api, without taking into account any + * {@link OpenApiSpecification} specific context path. + */ private String rootContextPath; + private boolean requestValidationEnabled = true; + + private boolean responseValidationEnabled = true; + public OpenApiRepository() { super(DEFAULT_NAME); } @@ -48,19 +67,80 @@ public void setRootContextPath(String rootContextPath) { this.rootContextPath = rootContextPath; } + public boolean isRequestValidationEnabled() { + return requestValidationEnabled; + } + + public void setRequestValidationEnabled(boolean requestValidationEnabled) { + this.requestValidationEnabled = requestValidationEnabled; + } + + public boolean isResponseValidationEnabled() { + return responseValidationEnabled; + } + + public void setResponseValidationEnabled(boolean responseValidationEnabled) { + this.responseValidationEnabled = responseValidationEnabled; + } + + /** + * Adds an OpenAPI Specification specified by the given resource to the repository. + * If an alias is determined from the resource name, it is added to the specification. + * + * @param openApiResource the resource to add as an OpenAPI specification + */ @Override public void addRepository(Resource openApiResource) { - OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); + determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); + openApiSpecification.setRequestValidationEnabled(requestValidationEnabled); + openApiSpecification.setResponseValidationEnabled(responseValidationEnabled); openApiSpecification.setRootContextPath(rootContextPath); this.openApiSpecifications.add(openApiSpecification); - OpenApiSpecificationProcessor.lookup().values().forEach(processor -> processor.process(openApiSpecification)); + OpenApiSpecificationProcessor.lookup().values() + .forEach(processor -> processor.process(openApiSpecification)); + } + + /** + * @param openApiResource the OpenAPI resource from which to determine the alias + * @return an {@code Optional} containing the resource alias if it can be resolved, otherwise an empty {@code Optional} + */ + // Package protection for testing + static Optional determineResourceAlias(Resource openApiResource) { + String resourceAlias = null; + + try { + File file = openApiResource.getFile(); + if (file != null) { + return Optional.of(file.getName()); + } + } catch (Exception e) { + // Ignore and try with url + } + + try { + URL url = openApiResource.getURL(); + if (url != null) { + String urlString = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8).replace("\\","/"); + int index = urlString.lastIndexOf("/"); + resourceAlias = urlString; + if (index != -1 && index != urlString.length()-1) { + resourceAlias = resourceAlias.substring(index+1); + } + } + } catch (MalformedURLException e) { + logger.error("Unable to determine resource alias from resource!", e); + } + + return Optional.ofNullable(resourceAlias); } public List getOpenApiSpecifications() { return openApiSpecifications; } + + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java index e2427165b2..47fe703e7a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java @@ -16,6 +16,11 @@ package org.citrusframework.openapi; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.apicurio.datamodels.Library; +import io.apicurio.datamodels.openapi.models.OasDocument; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; @@ -25,14 +30,11 @@ import java.util.Objects; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; - -import com.fasterxml.jackson.databind.JsonNode; -import io.apicurio.datamodels.Library; -import io.apicurio.datamodels.openapi.models.OasDocument; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.TrustAllStrategy; import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.ssl.SSLContexts; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.Resource; import org.citrusframework.util.FileUtils; import org.springframework.http.HttpMethod; @@ -43,6 +45,11 @@ */ public final class OpenApiResourceLoader { + static final RawResolver RAW_RESOLVER = new RawResolver(); + + + static final OasResolver OAS_RESOLVER = new OasResolver(); + /** * Prevent instantiation of utility class. */ @@ -56,17 +63,40 @@ private OpenApiResourceLoader() { * @return */ public static OasDocument fromFile(String resource) { - return fromFile(FileUtils.getFileResource(resource)); + return fromFile(FileUtils.getFileResource(resource), OAS_RESOLVER); } /** - * Loads the specification from a file resource. Either classpath or file system resource path is supported. + * Loads the raw specification from a file resource. Either classpath or file system resource path is supported. + * @param resource + * @return + */ + public static String rawFromFile(String resource) { + return fromFile(FileUtils.getFileResource(resource), + RAW_RESOLVER); + } + + /** + * Loads the specification from a resource. * @param resource * @return */ public static OasDocument fromFile(Resource resource) { + return fromFile(resource, OAS_RESOLVER); + } + + /** + * Loads the raw specification from a resource. + * @param resource + * @return + */ + public static String rawFromFile(Resource resource) { + return fromFile(resource, RAW_RESOLVER); + } + + private static T fromFile(Resource resource, Resolver resolver) { try { - return resolve(FileUtils.readToString(resource)); + return resolve(FileUtils.readToString(resource), resolver); } catch (IOException e) { throw new IllegalStateException("Failed to parse Open API specification: " + resource, e); } @@ -78,6 +108,19 @@ public static OasDocument fromFile(Resource resource) { * @return */ public static OasDocument fromWebResource(URL url) { + return fromWebResource(url, OAS_RESOLVER); + } + + /** + * Loads raw specification from given web URL location. + * @param url + * @return + */ + public static String rawFromWebResource(URL url) { + return fromWebResource(url, RAW_RESOLVER); + } + + private static T fromWebResource(URL url, Resolver resolver) { HttpURLConnection con = null; try { con = (HttpURLConnection) url.openConnection(); @@ -87,9 +130,9 @@ public static OasDocument fromWebResource(URL url) { int status = con.getResponseCode(); if (status > 299) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), - new IOException(FileUtils.readToString(con.getErrorStream()))); + new IOException(FileUtils.readToString(con.getErrorStream()))); } else { - return resolve(FileUtils.readToString(con.getInputStream())); + return resolve(FileUtils.readToString(con.getInputStream()), resolver); } } catch (IOException e) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), e); @@ -106,14 +149,27 @@ public static OasDocument fromWebResource(URL url) { * @return */ public static OasDocument fromSecuredWebResource(URL url) { + return fromSecuredWebResource(url, OAS_RESOLVER); + } + + /** + * Loads raw specification from given web URL location using secured Http connection. + * @param url + * @return + */ + public static String rawFromSecuredWebResource(URL url) { + return fromSecuredWebResource(url, RAW_RESOLVER); + } + + private static T fromSecuredWebResource(URL url, Resolver resolver) { Objects.requireNonNull(url); HttpsURLConnection con = null; try { SSLContext sslcontext = SSLContexts - .custom() - .loadTrustMaterial(TrustAllStrategy.INSTANCE) - .build(); + .custom() + .loadTrustMaterial(TrustAllStrategy.INSTANCE) + .build(); HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE); @@ -125,9 +181,9 @@ public static OasDocument fromSecuredWebResource(URL url) { int status = con.getResponseCode(); if (status > 299) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), - new IOException(FileUtils.readToString(con.getErrorStream()))); + new IOException(FileUtils.readToString(con.getErrorStream()))); } else { - return resolve(FileUtils.readToString(con.getInputStream())); + return resolve(FileUtils.readToString(con.getInputStream()), resolver); } } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { throw new IllegalStateException("Failed to create https client for ssl connection", e); @@ -140,16 +196,64 @@ public static OasDocument fromSecuredWebResource(URL url) { } } - private static OasDocument resolve(String specification) { + private static T resolve(String specification, Resolver resolver) { if (isJsonSpec(specification)) { - return (OasDocument) Library.readDocumentFromJSONString(specification); + return resolver.resolveFromString(specification); } final JsonNode node = OpenApiSupport.json().convertValue(OpenApiSupport.yaml().load(specification), JsonNode.class); - return (OasDocument) Library.readDocument(node); + return resolver.resolveFromNode(node); } private static boolean isJsonSpec(final String specification) { return specification.trim().startsWith("{"); } + + private interface Resolver { + + T resolveFromString(String specification); + + T resolveFromNode(JsonNode node); + + } + + /** + * {@link Resolver} implementation, that resolves to {@link OasDocument}. + */ + private static class OasResolver implements Resolver { + + @Override + public OasDocument resolveFromString(String specification) { + return (OasDocument) Library.readDocumentFromJSONString(specification); + } + + @Override + public OasDocument resolveFromNode(JsonNode node) { + return (OasDocument) Library.readDocument(node); + } + } + + /** + * {@link Resolver} implementation, that resolves to {@link String}. + */ + private static class RawResolver implements Resolver { + + private static final ObjectMapper mapper = new ObjectMapper(); + + @Override + public String resolveFromString(String specification) { + return specification; + } + + @Override + public String resolveFromNode(JsonNode node) { + + try { + return mapper.writeValueAsString(node); + } catch (JsonProcessingException e) { + throw new CitrusRuntimeException("Unable to write OpenApi specification node to string!", e); + } + } + } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java new file mode 100644 index 0000000000..ea99928985 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java @@ -0,0 +1,49 @@ +package org.citrusframework.openapi; + +import static java.lang.Boolean.parseBoolean; + +/** + * The {@code OpenApiSettings} class provides configuration settings for enabling or disabling + * OpenAPI request and response validation globally. The settings can be controlled through + * system properties or environment variables. + */ +public class OpenApiSettings { + + public static final String GENERATE_OPTIONAL_FIELDS_PROPERTY = "citrus.openapi.generate.optional.fields"; + public static final String GENERATE_OPTIONAL_FIELDS_ENV = "CITRUS_OPENAPI_GENERATE_OPTIONAL_FIELDS"; + + public static final String VALIDATE_OPTIONAL_FIELDS_PROPERTY = "citrus.openapi.validate.optional.fields"; + public static final String VALIDATE_OPTIONAL_FIELDS_ENV = "CITRUS_OPENAPI_VALIDATE_OPTIONAL_FIELDS"; + + public static final String REQUEST_VALIDATION_ENABLED_PROPERTY = "citrus.openapi.validation.enabled.request"; + public static final String REQUEST_VALIDATION_ENABLED_ENV = "CITRUS_OPENAPI_VALIDATION_DISABLE_REQUEST"; + + public static final String RESPONSE_VALIDATION_ENABLED_PROPERTY = "citrus.openapi.validation.enabled.response"; + public static final String RESPONSE_VALIDATION_ENABLED_ENV = "CITRUS_OPENAPI_VALIDATION_DISABLE_RESPONSE"; + + private OpenApiSettings() { + // static access only + } + + public static boolean isGenerateOptionalFieldsGlobally() { + return parseBoolean(System.getProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) != null ? + System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) : "true")); + } + + public static boolean isValidateOptionalFieldsGlobally() { + return parseBoolean(System.getProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) != null ? + System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) : "true")); + } + + public static boolean isRequestValidationEnabledlobally() { + return parseBoolean(System.getProperty( + REQUEST_VALIDATION_ENABLED_PROPERTY, System.getenv(REQUEST_VALIDATION_ENABLED_ENV) != null ? + System.getenv(REQUEST_VALIDATION_ENABLED_ENV) : "true")); + } + + public static boolean isResponseValidationEnabledGlobally() { + return parseBoolean(System.getProperty( + RESPONSE_VALIDATION_ENABLED_PROPERTY, System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) != null ? + System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) : "true")); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index 5c28f5e67a..918aee6f6c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -16,44 +16,111 @@ package org.citrusframework.openapi; +import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.OpenApiInteractionValidator.Builder; +import io.apicurio.datamodels.core.models.common.Info; +import io.apicurio.datamodels.openapi.models.OasDocument; +import io.apicurio.datamodels.openapi.models.OasOperation; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collection; import java.util.Collections; +import java.util.HashSet; +import java.util.Map; import java.util.Optional; - -import io.apicurio.datamodels.openapi.models.OasDocument; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.client.HttpClient; import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiRequestValidator; +import org.citrusframework.openapi.validation.OpenApiResponseValidator; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * OpenApi specification resolves URL or local file resources to a specification document. + *

+ * The OpenApiSpecification class is responsible for handling the loading and processing of OpenAPI + * specification documents from various sources, such as URLs or local files. It supports the + * extraction and usage of key information from these documents, facilitating the interaction with + * OpenAPI-compliant APIs. + *

+ *

+ * The class maintains a set of aliases derived from the OpenAPI document's information. These + * aliases typically include the title of the API and its version, providing easy reference and + * identification. For example, if the OpenAPI document's title is "Sample API" and its version is + * "1.0", the aliases set will include "Sample API" and "Sample API/1.0". + *

+ * Users are responsible for ensuring that the sources provided to this class have unique aliases, + * or at least use the correct alias. If the same API is registered with different versions, all + * versions will likely share the same title alias but can be distinguished by the version alias + * (e.g., "Sample API/1.0" and "Sample API/2.0"). This distinction is crucial to avoid conflicts and + * ensure the correct identification and reference of each OpenAPI specification. Also note, that + * aliases may be added manually or programmatically by + * {@link OpenApiSpecification#addAlias(String)}. */ public class OpenApiSpecification { + private static final Logger logger = LoggerFactory.getLogger(OpenApiSpecification.class); + public static final String HTTPS = "https"; public static final String HTTP = "http"; - /** URL to load the OpenAPI specification */ + + /** + * URL to load the OpenAPI specification + */ private String specUrl; private String httpClient; private String requestUrl; /** - * The optional root context path to which the OpenAPI is hooked. - * This path is prepended to the base path specified in the OpenAPI configuration. - * If no root context path is specified, only the base path and additional segments are used. + * The optional root context path to which the OpenAPI is hooked. This path is prepended to the + * base path specified in the OpenAPI configuration. If no root context path is specified, only + * the base path and additional segments are used. */ private String rootContextPath; private OasDocument openApiDoc; - private boolean generateOptionalFields = true; + private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); + + private boolean validateOptionalFields = isValidateOptionalFieldsGlobally(); + + private boolean requestValidationEnabled = isRequestValidationEnabledlobally(); + + private boolean responseValidationEnabled = isResponseValidationEnabledGlobally(); + + private final Set aliases = Collections.synchronizedSet(new HashSet<>()); - private boolean validateOptionalFields = true; + /** + * Maps the identifier (id) of an operation to OperationPathAdapters. Two different keys may be used for each operation. + * Refer to {@link org.citrusframework.openapi.OpenApiSpecification#storeOperationPathAdapter} for more details. + */ + private final Map operationIdToOperationPathAdapter = new ConcurrentHashMap<>(); + + /** + * Stores the unique identifier (uniqueId) of an operation, derived from its HTTP method and path. + * This identifier can always be determined and is therefore safe to use, even for operations without + * an optional operationId defined. + */ + private final Map operationToUniqueId = new ConcurrentHashMap<>(); + + private OpenApiRequestValidator openApiRequestValidator; + + private OpenApiResponseValidator openApiResponseValidator; public static OpenApiSpecification from(String specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); @@ -65,15 +132,25 @@ public static OpenApiSpecification from(String specUrl) { public static OpenApiSpecification from(URL specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc; + OpenApiInteractionValidator validator; if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); + validator = new OpenApiInteractionValidator.Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromSecuredWebResource(specUrl)).build(); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); + validator = new OpenApiInteractionValidator.Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromWebResource(specUrl)).build(); } specification.setSpecUrl(specUrl.toString()); + specification.initPathLookups(); specification.setOpenApiDoc(openApiDoc); - specification.setRequestUrl(String.format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", OasModelHelper.getBasePath(openApiDoc))); + specification.setValidator(validator); + specification.setRequestUrl( + String.format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), + specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", + OasModelHelper.getBasePath(openApiDoc))); return specification; } @@ -81,23 +158,28 @@ public static OpenApiSpecification from(URL specUrl) { public static OpenApiSpecification from(Resource resource) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); + OpenApiInteractionValidator validator = new Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromFile(resource)).build(); specification.setOpenApiDoc(openApiDoc); + specification.setValidator(validator); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList(HTTP)) - .stream() - .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) - .findFirst() - .orElse(HTTP); + .orElse(Collections.singletonList(HTTP)) + .stream() + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) + .findFirst() + .orElse(HTTP); specification.setSpecUrl(resource.getLocation()); - specification.setRequestUrl(String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), OasModelHelper.getBasePath(openApiDoc))); + specification.setRequestUrl( + String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), + OasModelHelper.getBasePath(openApiDoc))); return specification; } - public OasDocument getOpenApiDoc(TestContext context) { + public synchronized OasDocument getOpenApiDoc(TestContext context) { if (openApiDoc != null) { return openApiDoc; } @@ -108,43 +190,63 @@ public OasDocument getOpenApiDoc(TestContext context) { if (resolvedSpecUrl.startsWith("/")) { // relative path URL - try to resolve with given request URL if (requestUrl != null) { - resolvedSpecUrl = requestUrl.endsWith("/") ? requestUrl + resolvedSpecUrl.substring(1) : requestUrl + resolvedSpecUrl; - } else if (httpClient != null && context.getReferenceResolver().isResolvable(httpClient, HttpClient.class)) { - String baseUrl = context.getReferenceResolver().resolve(httpClient, HttpClient.class).getEndpointConfiguration().getRequestUrl(); - resolvedSpecUrl = baseUrl.endsWith("/") ? baseUrl + resolvedSpecUrl.substring(1) : baseUrl + resolvedSpecUrl; + resolvedSpecUrl = + requestUrl.endsWith("/") ? requestUrl + resolvedSpecUrl.substring(1) + : requestUrl + resolvedSpecUrl; + } else if (httpClient != null && context.getReferenceResolver() + .isResolvable(httpClient, HttpClient.class)) { + String baseUrl = context.getReferenceResolver() + .resolve(httpClient, HttpClient.class).getEndpointConfiguration() + .getRequestUrl(); + resolvedSpecUrl = baseUrl.endsWith("/") ? baseUrl + resolvedSpecUrl.substring(1) + : baseUrl + resolvedSpecUrl; } else { - throw new CitrusRuntimeException(("Failed to resolve OpenAPI spec URL from relative path %s - " + - "make sure to provide a proper base URL when using relative paths").formatted(resolvedSpecUrl)); + throw new CitrusRuntimeException( + ("Failed to resolve OpenAPI spec URL from relative path %s - " + + "make sure to provide a proper base URL when using relative paths").formatted( + resolvedSpecUrl)); } } if (resolvedSpecUrl.startsWith(HTTP)) { - try { - URL specWebResource = new URL(resolvedSpecUrl); - if (resolvedSpecUrl.startsWith(HTTPS)) { - openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specWebResource); - } else { - openApiDoc = OpenApiResourceLoader.fromWebResource(specWebResource); - } - - if (requestUrl == null) { - setRequestUrl(String.format("%s://%s%s%s", specWebResource.getProtocol(), specWebResource.getHost(), specWebResource.getPort() > 0 ? ":" + specWebResource.getPort() : "", OasModelHelper.getBasePath(openApiDoc))); - } - } catch (MalformedURLException e) { - throw new IllegalStateException("Failed to retrieve Open API specification as web resource: " + specUrl, e); + + URL specWebResource = toSpecUrl(resolvedSpecUrl); + if (resolvedSpecUrl.startsWith(HTTPS)) { + initApiDoc( + () -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); + setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromSecuredWebResource(specWebResource)).build()); + } else { + initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); + setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromWebResource(specWebResource)).build()); + } + + if (requestUrl == null) { + setRequestUrl(String.format("%s://%s%s%s", specWebResource.getProtocol(), + specWebResource.getHost(), + specWebResource.getPort() > 0 ? ":" + specWebResource.getPort() : "", + OasModelHelper.getBasePath(openApiDoc))); } + } else { - openApiDoc = OpenApiResourceLoader.fromFile(Resources.create(resolvedSpecUrl)); + Resource resource = Resources.create(resolvedSpecUrl); + initApiDoc( + () -> OpenApiResourceLoader.fromFile(resource)); + setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( + OpenApiResourceLoader.rawFromFile(resource)).build()); if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList(HTTP)) - .stream() - .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) - .findFirst() - .orElse(HTTP); - - setRequestUrl(String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), OasModelHelper.getBasePath(openApiDoc))); + .orElse(Collections.singletonList(HTTP)) + .stream() + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) + .findFirst() + .orElse(HTTP); + + setRequestUrl( + String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), + OasModelHelper.getBasePath(openApiDoc))); } } } @@ -152,8 +254,79 @@ public OasDocument getOpenApiDoc(TestContext context) { return openApiDoc; } - public void setOpenApiDoc(OasDocument openApiDoc) { - this.openApiDoc = openApiDoc; + // provided for testing + URL toSpecUrl(String resolvedSpecUrl) { + try { + return new URL(resolvedSpecUrl); + } catch (MalformedURLException e) { + throw new IllegalStateException( + "Failed to retrieve Open API specification as web resource: " + specUrl, e); + } + } + + void setOpenApiDoc(OasDocument openApiDoc) { + initApiDoc(() -> openApiDoc); + } + + private void setValidator(OpenApiInteractionValidator openApiInteractionValidator) { + openApiRequestValidator = new OpenApiRequestValidator(openApiInteractionValidator); + openApiRequestValidator.setEnabled(requestValidationEnabled); + + openApiResponseValidator = new OpenApiResponseValidator(openApiInteractionValidator); + openApiRequestValidator.setEnabled(responseValidationEnabled); + } + + private void initApiDoc(Supplier openApiDocSupplier) { + this.openApiDoc = openApiDocSupplier.get(); + this.aliases.addAll(collectAliases(openApiDoc)); + initPathLookups(); + } + + private void initPathLookups() { + + if (this.openApiDoc == null) { + return; + } + + operationIdToOperationPathAdapter.clear(); + OasModelHelper.visitOasOperations(this.openApiDoc, (oasPathItem, oasOperation) -> { + String path = oasPathItem.getPath(); + + if (StringUtils.isEmpty(path)) { + logger.warn("Skipping path item without path."); + return; + } + + for (Map.Entry operationEntry : OasModelHelper.getOperationMap( + oasPathItem).entrySet()) { + storeOperationPathAdapter(operationEntry.getValue(), path); + } + }); + } + + /** + * Stores an {@link OperationPathAdapter} in {@link org.citrusframework.openapi.OpenApiSpecification#operationIdToOperationPathAdapter}. + * The adapter is stored using two keys: the operationId (optional) and the full path of the operation, including the method. + * The full path is always determinable and thus can always be safely used. + * + * @param operation The {@link OperationPathAdapter} to store. + * @param path The full path of the operation, including the method. + */ + private void storeOperationPathAdapter(OasOperation operation, String path) { + + String basePath = OasModelHelper.getBasePath(openApiDoc); + String fullOperationPath = StringUtils.appendSegmentToUrlPath(basePath, path); + + OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, + StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation); + + String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(fullOperationPath, operation); + operationToUniqueId.put(operation, uniqueOperationId); + + operationIdToOperationPathAdapter.put(uniqueOperationId, operationPathAdapter); + if (StringUtils.hasText(operation.operationId)) { + operationIdToOperationPathAdapter.put(operation.operationId, operationPathAdapter); + } } public String getSpecUrl() { @@ -184,6 +357,28 @@ public void setRequestUrl(String requestUrl) { this.requestUrl = requestUrl; } + public boolean isRequestValidationEnabled() { + return requestValidationEnabled; + } + + public void setRequestValidationEnabled(boolean enabled) { + this.requestValidationEnabled = enabled; + if (this.openApiRequestValidator != null) { + this.openApiRequestValidator.setEnabled(enabled); + } + } + + public boolean isResponseValidationEnabled() { + return responseValidationEnabled; + } + + public void setResponseValidationEnabled(boolean enabled) { + this.responseValidationEnabled = enabled; + if (this.openApiResponseValidator != null) { + this.openApiResponseValidator.setEnabled(enabled); + } + } + public boolean isGenerateOptionalFields() { return generateOptionalFields; } @@ -206,7 +401,68 @@ public String getRootContextPath() { public void setRootContextPath(String rootContextPath) { this.rootContextPath = rootContextPath; + initPathLookups(); } + public void addAlias(String alias) { + aliases.add(alias); + } + + public Set getAliases() { + return Collections.unmodifiableSet(aliases); + } + + private Collection collectAliases(OasDocument document) { + if (document == null) { + return Collections.emptySet(); + } + + Info info = document.info; + if (info == null) { + return Collections.emptySet(); + } + + Set set = new HashSet<>(); + if (StringUtils.hasText(info.title)) { + set.add(info.title); + + if (StringUtils.hasText(info.version)) { + set.add(info.title + "/" + info.version); + } + } + return set; + } + + public Optional getOperation(String operationId, TestContext context) { + + if (operationId == null) { + return Optional.empty(); + } + + // This is ugly, but we need not make sure that the openApiDoc is initialized, which might + // happen, when instance is created with org.citrusframework.openapi.OpenApiSpecification.from(java.lang.String) + if (openApiDoc == null) { + getOpenApiDoc(context); + } + + return Optional.ofNullable(operationIdToOperationPathAdapter.get(operationId)); + } + + public Optional getRequestValidator() { + return Optional.ofNullable(openApiRequestValidator); + } + + public Optional getResponseValidator() { + return Optional.ofNullable(openApiResponseValidator); + } + + public OpenApiSpecification withRootContext(String rootContextPath) { + setRootContextPath(rootContextPath); + return this; + } + + public String getUniqueId(OasOperation oasOperation) { + return operationToUniqueId.get(oasOperation); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java new file mode 100644 index 0000000000..fa3eaca62c --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java @@ -0,0 +1,43 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +/** + * Adapter class that links an OAS entity to its associated OpenAPI specification context. + * This class provides methods to access both the OpenAPI specification and the specific OAS entity. + * + * @param the type to which the specification is adapted. + */ +public class OpenApiSpecificationAdapter { + + private final OpenApiSpecification openApiSpecification; + + private final T entity; + + public OpenApiSpecificationAdapter(OpenApiSpecification openApiSpecification, T entity) { + this.openApiSpecification = openApiSpecification; + this.entity = entity; + } + + public OpenApiSpecification getOpenApiSpecification() { + return openApiSpecification; + } + + public T getEntity() { + return entity; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index d9cb31f977..a09be519ea 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -95,6 +95,15 @@ public static String createRandomValueExpression(String name, OasSchema schema, return createRandomValueExpression(schema, definitions, quotes, specification); } + public static T createRawRandomValueExpression(String name, OasSchema schema, Map definitions, + boolean quotes, OpenApiSpecification specification, TestContext context) { + if (context.getVariables().containsKey(name)) { + return (T)context.getVariables().get(CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX); + } + + return createRawRandomValueExpression(schema, definitions, quotes, specification, context); + } + /** * Create payload from schema with random values. * @param schema @@ -120,7 +129,7 @@ public static String createRandomValueExpression(OasSchema schema, Map T createRawRandomValueExpression(OasSchema schema, Map definitions, boolean quotes, + OpenApiSpecification specification, TestContext context) { + if (OasModelHelper.isReferenceType(schema)) { + OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); + return createRawRandomValueExpression(resolved, definitions, quotes, specification, context); + } + + StringBuilder payload = new StringBuilder(); + if ("string".equals(schema.type) || OasModelHelper.isObjectType(schema) || OasModelHelper.isArrayType(schema)) { + return (T)createRandomValueExpression(schema, definitions, quotes, specification); + } else if ("number".equals(schema.type)) { + return (T)Double.valueOf(context.replaceDynamicContentInString("citrus:randomNumber(8,2)")); + } else if ("integer".equals(schema.type)) { + return (T)Double.valueOf(context.replaceDynamicContentInString("citrus:randomNumber(8)")); + } else if ("boolean".equals(schema.type)) { + return (T)Boolean.valueOf(context.replaceDynamicContentInString("citrus:randomEnumValue('true', 'false')")); + } else if (quotes) { + payload.append("\"\""); + } + + return (T)payload.toString(); + } + /** * Creates control payload from schema for validation. * @param schema @@ -284,7 +316,7 @@ private static String createValidationExpression(OasSchema schema) { if (schema.format != null && schema.format.equals("date")) { return "@matchesDatePattern('yyyy-MM-dd')@"; } else if (schema.format != null && schema.format.equals("date-time")) { - return "@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ss')@"; + return "@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ssZ')@"; } else if (StringUtils.hasText(schema.pattern)) { return String.format("@matches(%s)@", schema.pattern); } else if (!CollectionUtils.isEmpty(schema.enum_)) { @@ -329,7 +361,7 @@ public static String createRandomValueExpression(OasSchema schema) { if (schema.format != null && schema.format.equals("date")) { return "\"citrus:currentDate('yyyy-MM-dd')\""; } else if (schema.format != null && schema.format.equals("date-time")) { - return "\"citrus:currentDate('yyyy-MM-dd'T'hh:mm:ss')\""; + return "\"citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')\""; } else if (StringUtils.hasText(schema.pattern)) { return "\"citrus:randomValue(" + schema.pattern + ")\""; } else if (!CollectionUtils.isEmpty(schema.enum_)) { @@ -375,7 +407,7 @@ public static String createValidationRegex(OasSchema schema) { if (schema.format != null && schema.format.equals("date")) { return "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"; } else if (schema.format != null && schema.format.equals("date-time")) { - return "\\d{4}-\\d{2}-\\d{2}T[01]\\d:[0-5]\\d:[0-5]\\d"; + return "\\d{4}-\\d{2}-\\d{2}T[01]\\d:[0-5]\\d:[0-5]\\dZ"; } else if (StringUtils.hasText(schema.pattern)) { return schema.pattern; } else if (!CollectionUtils.isEmpty(schema.enum_)) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java new file mode 100644 index 0000000000..c7f1c7b1e4 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java @@ -0,0 +1,55 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static java.lang.String.format; + +import io.apicurio.datamodels.openapi.models.OasOperation; +import jakarta.annotation.Nonnull; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.util.StringUtils; + +public class OpenApiUtils { + + private OpenApiUtils() { + // Static access only + } + + public static String getMethodPath(@Nonnull HttpMessage httpMessage) { + Object methodHeader = httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD); + Object path = httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI); + + return getMethodPath(methodHeader != null ? methodHeader.toString().toLowerCase() : "null", + path != null? path.toString() : "null"); + } + + public static String getMethodPath(@Nonnull String method, @Nonnull String path) { + if (StringUtils.hasText(path) && path.startsWith("/")) { + path = path.substring(1); + } + return String.format("/%s/%s", method.toLowerCase(), path); + } + + /** + * @return a unique scenario id for the {@link OasOperation} + */ + public static String createFullPathOperationIdentifier(String path, OasOperation oasOperation) { + return format("%s_%s", oasOperation.getMethod().toUpperCase(), path); + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index a9574f5310..e51329d449 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -16,17 +16,13 @@ package org.citrusframework.openapi.actions; +import io.apicurio.datamodels.openapi.models.OasOperation; +import io.apicurio.datamodels.openapi.models.OasParameter; +import io.apicurio.datamodels.openapi.models.OasSchema; import java.util.List; import java.util.Locale; -import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; - -import io.apicurio.datamodels.openapi.models.OasDocument; -import io.apicurio.datamodels.openapi.models.OasOperation; -import io.apicurio.datamodels.openapi.models.OasParameter; -import io.apicurio.datamodels.openapi.models.OasPathItem; -import io.apicurio.datamodels.openapi.models.OasSchema; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -37,6 +33,8 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiRequestValidationProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -45,6 +43,8 @@ */ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBuilder { + private final OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + /** * Default constructor initializes http request message builder. */ @@ -55,6 +55,16 @@ public OpenApiClientRequestActionBuilder(OpenApiSpecification openApiSpec, Strin public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, String operationId) { super(new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage); + + openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); + process(openApiRequestValidationProcessor); + } + + public OpenApiClientRequestActionBuilder disableOasValidation(boolean b) { + if (openApiRequestValidationProcessor != null) { + openApiRequestValidationProcessor.setEnabled(!b); + } + return this; } private static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilder { @@ -74,65 +84,32 @@ public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecif @Override public Message build(TestContext context, String messageType) { - OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); - OasOperation operation = null; - OasPathItem pathItem = null; - HttpMethod method = null; - - for (OasPathItem path : OasModelHelper.getPathItems(oasDocument.paths)) { - Optional> operationEntry = OasModelHelper.getOperationMap(path).entrySet().stream() - .filter(op -> operationId.equals(op.getValue().operationId)) - .findFirst(); - - if (operationEntry.isPresent()) { - method = HttpMethod.valueOf(operationEntry.get().getKey().toUpperCase(Locale.US)); - operation = operationEntry.get().getValue(); - pathItem = path; - break; - } - } + openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(operationPathAdapter, context), () -> { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + }); - if (operation == null) { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); - } + return super.build(context, messageType); + } + + private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { + OasOperation operation = operationPathAdapter.operation(); + String path = operationPathAdapter.apiPath(); + HttpMethod method = HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); if (operation.parameters != null) { - List configuredHeaders = getHeaderBuilders() - .stream() - .flatMap(b -> b.builderHeaders(context).keySet().stream()) - .toList(); - operation.parameters.stream() - .filter(param -> "header".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> { - if(httpMessage.getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { - httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context)); - } - }); - - operation.parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> { - if(!httpMessage.getQueryParams().containsKey(param.getName())) { - httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, context)); - } - }); + setSpecifiedHeaders(context, operation); + setSpecifiedQueryParameters(context, operation); } if(httpMessage.getPayload() == null || (httpMessage.getPayload() instanceof String p && p.isEmpty())) { - Optional body = OasModelHelper.getRequestBodySchema(oasDocument, operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + setSpecifiedBody(context, operation); } - String randomizedPath = pathItem.getPath(); + String randomizedPath = path; if (operation.parameters != null) { List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; @@ -142,18 +119,55 @@ public Message build(TestContext context, String messageType) { parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema); } randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") - .matcher(randomizedPath) - .replaceAll(parameterValue); + .matcher(randomizedPath) + .replaceAll(parameterValue); } } OasModelHelper.getRequestContentType(operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); httpMessage.path(randomizedPath); httpMessage.method(method); - return super.build(context, messageType); + } + + private void setSpecifiedBody(TestContext context, OasOperation operation) { + Optional body = OasModelHelper.getRequestBodySchema( + openApiSpec.getOpenApiDoc(context), operation); + body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), openApiSpec))); + } + + private void setSpecifiedQueryParameters(TestContext context, OasOperation operation) { + operation.parameters.stream() + .filter(param -> "query".equals(param.in)) + .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> { + if(!httpMessage.getQueryParams().containsKey(param.getName())) { + httpMessage.queryParam(param.getName(), + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, + context)); + } + }); + } + + private void setSpecifiedHeaders(TestContext context, OasOperation operation) { + List configuredHeaders = getHeaderBuilders() + .stream() + .flatMap(b -> b.builderHeaders(context).keySet().stream()) + .toList(); + operation.parameters.stream() + .filter(param -> "header".equals(param.in)) + .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> { + if(httpMessage.getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { + httpMessage.setHeader(param.getName(), + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, + OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc( + context)), false, openApiSpec, context)); + } + }); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index de47454232..b0d9aeb26a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -16,9 +16,7 @@ package org.citrusframework.openapi.actions; -import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; -import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; @@ -37,7 +35,8 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; -import org.citrusframework.util.StringUtils; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -47,6 +46,7 @@ */ public class OpenApiClientResponseActionBuilder extends HttpClientResponseActionBuilder { + private final OpenApiResponseValidationProcessor openApiResponseValidationProcessor; /** * Default constructor initializes http response message builder. */ @@ -60,6 +60,16 @@ public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, String operationId, String statusCode) { super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpec, operationId, statusCode), httpMessage); + + openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); + validate(openApiResponseValidationProcessor); + } + + public OpenApiClientResponseActionBuilder disableOasValidation(boolean b) { + if (openApiResponseValidationProcessor != null) { + openApiResponseValidationProcessor.setEnabled(!b); + } + return this; } public static void fillMessageFromResponse(OpenApiSpecification openApiSpecification, @@ -145,40 +155,25 @@ public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, @Override public Message build(TestContext context, String messageType) { - OasOperation operation = null; - OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); - - for (OasPathItem path : OasModelHelper.getPathItems(oasDocument.paths)) { - Optional> operationEntry = OasModelHelper.getOperationMap( - path).entrySet().stream() - .filter(op -> operationId.equals(op.getValue().operationId)) - .findFirst(); - - if (operationEntry.isPresent()) { - operation = operationEntry.get().getValue(); - break; - } - } - if (operation == null) { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpec.getSpecUrl())); - } + openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(operationPathAdapter, context), () -> { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + }); + + return super.build(context, messageType); + } + + private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { + OasOperation operation = operationPathAdapter.operation(); if (operation.responses != null) { - OasResponse response; - - if (StringUtils.hasText(statusCode)) { - response = Optional.ofNullable(operation.responses.getItem(statusCode)) - .orElse(operation.responses.default_); - } else { - response = OasModelHelper.getResponseForRandomGeneration( - openApiSpec.getOpenApiDoc(null), operation) - .orElse(operation.responses.default_); - } + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + openApiSpec.getOpenApiDoc(context), operation, statusCode, null); - fillMessageFromResponse(openApiSpec, context, httpMessage, operation, response); + responseForRandomGeneration.ifPresent( + oasResponse -> fillMessageFromResponse(openApiSpec, context, httpMessage, + operation, oasResponse)); } if (Pattern.compile("\\d+").matcher(statusCode).matches()) { @@ -186,8 +181,6 @@ public Message build(TestContext context, String messageType) { } else { httpMessage.status(HttpStatus.OK); } - - return super.build(context, messageType); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java index b1feee6faf..304893486b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java @@ -86,11 +86,25 @@ public OpenApiServerResponseActionBuilder send(String operationId, HttpStatus st return send(operationId, String.valueOf(status.value())); } + /** + * Send Http response messages as server to client. + */ + public OpenApiServerResponseActionBuilder send(String operationId, HttpStatus status, String accept) { + return send(operationId, String.valueOf(status.value()), accept); + } + /** * Send Http response messages as server to client. */ public OpenApiServerResponseActionBuilder send(String operationId, String statusCode) { - OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder(specification, operationId, statusCode); + return send(operationId, statusCode, null); + } + + /** + * Send Http response messages as server to client. + */ + public OpenApiServerResponseActionBuilder send(String operationId, String statusCode, String accept) { + OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder(specification, operationId, statusCode, accept); if (httpServer != null) { builder.endpoint(httpServer); } else { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java index 2574c75631..c748772783 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java @@ -21,18 +21,14 @@ import static org.citrusframework.message.MessageType.PLAINTEXT; import static org.citrusframework.message.MessageType.XML; import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; -import static org.citrusframework.util.StringUtils.appendSegmentToPath; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; -import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; -import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasSchema; import java.util.List; -import java.util.Locale; -import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; @@ -45,6 +41,8 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiRequestValidationProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -53,6 +51,8 @@ */ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBuilder { + private final OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + /** * Default constructor initializes http request message builder. */ @@ -60,9 +60,21 @@ public OpenApiServerRequestActionBuilder(OpenApiSpecification openApiSpec, Strin this(new HttpMessage(), openApiSpec, operationId); } - public OpenApiServerRequestActionBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId) { - super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage); + public OpenApiServerRequestActionBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId) { + super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpec, operationId), + httpMessage); + + openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); + validate(openApiRequestValidationProcessor); + } + + public OpenApiServerRequestActionBuilder disableOasValidation(boolean b) { + if (openApiRequestValidationProcessor != null) { + openApiRequestValidationProcessor.setEnabled(!b); + } + return this; } private static class OpenApiServerRequestMessageBuilder extends HttpMessageBuilder { @@ -72,8 +84,9 @@ private static class OpenApiServerRequestMessageBuilder extends HttpMessageBuild private final HttpMessage httpMessage; - public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId) { + public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId) { super(httpMessage); this.openApiSpec = openApiSpec; this.operationId = operationId; @@ -82,116 +95,114 @@ public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecif @Override public Message build(TestContext context, String messageType) { - OasOperationParams oasOperationParams = getResult(context); - if (oasOperationParams.operation() == null) { + openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(operationPathAdapter, context), () -> { throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); - } - - setSpecifiedMessageType(oasOperationParams); - setSpecifiedHeaders(context, oasOperationParams); - setSpecifiedQueryParameters(context, oasOperationParams); - setSpecifiedPath(context, oasOperationParams); - setSpecifiedBody(oasOperationParams); - setSpecifiedRequestContentType(oasOperationParams); - setSpecifiedMethod(oasOperationParams); + }); return super.build(context, messageType); } - private OasOperationParams getResult(TestContext context) { - OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); - OasOperation operation = null; - OasPathItem pathItem = null; - HttpMethod method = null; - - for (OasPathItem path : OasModelHelper.getPathItems(oasDocument.paths)) { - Optional> operationEntry = OasModelHelper.getOperationMap(path).entrySet().stream() - .filter(op -> operationId.equals(op.getValue().operationId)) - .findFirst(); - - if (operationEntry.isPresent()) { - method = HttpMethod.valueOf(operationEntry.get().getKey().toUpperCase(Locale.US)); - operation = operationEntry.get().getValue(); - pathItem = path; - break; - } - } - return new OasOperationParams(oasDocument, operation, pathItem, method); + private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { + + setSpecifiedMessageType(operationPathAdapter); + setSpecifiedHeaders(context, operationPathAdapter); + setSpecifiedQueryParameters(context, operationPathAdapter); + setSpecifiedPath(context, operationPathAdapter); + setSpecifiedBody(context, operationPathAdapter); + setSpecifiedRequestContentType(operationPathAdapter); + setSpecifiedMethod(operationPathAdapter); + } - private void setSpecifiedRequestContentType(OasOperationParams oasOperationParams) { - OasModelHelper.getRequestContentType(oasOperationParams.operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, String.format("@startsWith(%s)@", contentType))); + private void setSpecifiedRequestContentType(OperationPathAdapter operationPathAdapter) { + OasModelHelper.getRequestContentType(operationPathAdapter.operation()) + .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, + String.format("@startsWith(%s)@", contentType))); } - private void setSpecifiedPath(TestContext context, OasOperationParams oasOperationParams) { - String randomizedPath = OasModelHelper.getBasePath(oasOperationParams.oasDocument) + oasOperationParams.pathItem.getPath(); + private void setSpecifiedPath(TestContext context, OperationPathAdapter operationPathAdapter) { + String randomizedPath = OasModelHelper.getBasePath(openApiSpec.getOpenApiDoc(context)) + + operationPathAdapter.apiPath(); randomizedPath = randomizedPath.replace("//", "/"); - randomizedPath = appendSegmentToPath(openApiSpec.getRootContextPath(), randomizedPath); + randomizedPath = appendSegmentToUrlPath(openApiSpec.getRootContextPath(), randomizedPath); - if (oasOperationParams.operation.parameters != null) { - randomizedPath = determinePath(context, oasOperationParams.operation, randomizedPath); + if (operationPathAdapter.operation().parameters != null) { + randomizedPath = determinePath(context, operationPathAdapter.operation(), + randomizedPath); } httpMessage.path(randomizedPath); } - private void setSpecifiedBody(OasOperationParams oasOperationParams) { - Optional body = OasModelHelper.getRequestBodySchema(oasOperationParams.oasDocument, oasOperationParams.operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions( - oasOperationParams.oasDocument), openApiSpec))); + private void setSpecifiedBody(TestContext context, OperationPathAdapter operationPathAdapter) { + Optional body = OasModelHelper.getRequestBodySchema( + openApiSpec.getOpenApiDoc(context), operationPathAdapter.operation()); + body.ifPresent(oasSchema -> httpMessage.setPayload( + OpenApiTestDataGenerator.createInboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions( + openApiSpec.getOpenApiDoc(context)), openApiSpec))); } private String determinePath(TestContext context, OasOperation operation, String randomizedPath) { List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; if (context.getVariables().containsKey(parameter.getName())) { - parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; + parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + + CitrusSettings.VARIABLE_SUFFIX; randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") .matcher(randomizedPath) .replaceAll(parameterValue); } else { - parameterValue = OpenApiTestDataGenerator.createValidationRegex(parameter.getName(), OasModelHelper.getParameterSchema(parameter).orElse(null)); + parameterValue = OpenApiTestDataGenerator.createValidationRegex( + parameter.getName(), + OasModelHelper.getParameterSchema(parameter).orElse(null)); randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") .matcher(randomizedPath) .replaceAll(parameterValue); - randomizedPath = format("@matches('%s')@", randomizedPath); + randomizedPath = format("@matches('%s')@", randomizedPath); } } return randomizedPath; } - private void setSpecifiedQueryParameters(TestContext context, OasOperationParams oasOperationParams) { + private void setSpecifiedQueryParameters(TestContext context, + OperationPathAdapter operationPathAdapter) { - if (oasOperationParams.operation.parameters == null) { + if (operationPathAdapter.operation().parameters == null) { return; } - oasOperationParams.operation.parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(oasOperationParams.oasDocument), false, openApiSpec, - context))); + operationPathAdapter.operation().parameters.stream() + .filter(param -> "query".equals(param.in)) + .filter( + param -> (param.required != null && param.required) || context.getVariables() + .containsKey(param.getName())) + .forEach(param -> httpMessage.queryParam(param.getName(), + OpenApiTestDataGenerator.createValidationExpression(param.getName(), + OasModelHelper.getParameterSchema(param).orElse(null), + OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, + openApiSpec, + context))); } - private void setSpecifiedHeaders(TestContext context, OasOperationParams oasOperationParams) { + private void setSpecifiedHeaders(TestContext context, + OperationPathAdapter operationPathAdapter) { - if (oasOperationParams.operation.parameters == null) { + if (operationPathAdapter.operation().parameters == null) { return; } - oasOperationParams.operation.parameters.stream() + operationPathAdapter.operation().parameters.stream() .filter(param -> "header".equals(param.in)) .filter( param -> (param.required != null && param.required) || context.getVariables() @@ -199,28 +210,30 @@ private void setSpecifiedHeaders(TestContext context, OasOperationParams oasOper .forEach(param -> httpMessage.setHeader(param.getName(), OpenApiTestDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(oasOperationParams.oasDocument), false, openApiSpec, + OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, + openApiSpec, context))); } - private void setSpecifiedMessageType(OasOperationParams oasOperationParams) { + private void setSpecifiedMessageType(OperationPathAdapter operationPathAdapter) { Optional requestContentType = getRequestContentType( - oasOperationParams.operation); - if (requestContentType.isPresent() && APPLICATION_JSON_VALUE.equals(requestContentType.get())) { + operationPathAdapter.operation()); + if (requestContentType.isPresent() && APPLICATION_JSON_VALUE.equals( + requestContentType.get())) { httpMessage.setType(JSON); - } else if (requestContentType.isPresent() && APPLICATION_XML_VALUE.equals(requestContentType.get())) { + } else if (requestContentType.isPresent() && APPLICATION_XML_VALUE.equals( + requestContentType.get())) { httpMessage.setType(XML); } else { httpMessage.setType(PLAINTEXT); } } - private void setSpecifiedMethod(OasOperationParams oasOperationParams) { - httpMessage.method(oasOperationParams.method); + private void setSpecifiedMethod(OperationPathAdapter operationPathAdapter) { + httpMessage.method(HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase())); } } - private record OasOperationParams(OasDocument oasDocument, OasOperation operation, OasPathItem pathItem, HttpMethod method) { - } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index b285259cd0..473bc91907 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -16,26 +16,42 @@ package org.citrusframework.openapi.actions; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; +import static java.lang.Integer.parseInt; +import static java.util.Collections.singletonMap; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; -import io.apicurio.datamodels.openapi.models.OasPathItem; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpServerResponseActionBuilder; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; +import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.message.Message; +import org.citrusframework.message.MessageHeaderBuilder; +import org.citrusframework.message.builder.DefaultHeaderBuilder; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.OpenApiTestDataGenerator; +import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; -import org.springframework.http.HttpHeaders; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; import org.springframework.http.HttpStatus; /** @@ -43,99 +59,190 @@ */ public class OpenApiServerResponseActionBuilder extends HttpServerResponseActionBuilder { + private final OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + /** * Default constructor initializes http response message builder. */ - public OpenApiServerResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, String statusCode) { - this(new HttpMessage(), openApiSpec, operationId, statusCode); + public OpenApiServerResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, + String statusCode, String accept) { + this(new HttpMessage(), openApiSpec, operationId, statusCode, accept); + } + + public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId, String statusCode, String accept) { + super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpec, operationId, + statusCode, accept), httpMessage); + + openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, + operationId); + process(openApiResponseValidationProcessor); + } + + public OpenApiServerResponseActionBuilder disableOasValidation(boolean b) { + if (openApiResponseValidationProcessor != null) { + openApiResponseValidationProcessor.setEnabled(!b); + } + return this; } - public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId, String statusCode) { - super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpec, operationId, statusCode), httpMessage); + public OpenApiServerResponseActionBuilder enableRandomGeneration(boolean enable) { + ((OpenApiServerResponseMessageBuilder)getMessageBuilderSupport().getMessageBuilder()).enableRandomGeneration(enable); + return this; } private static class OpenApiServerResponseMessageBuilder extends HttpMessageBuilder { + private static final Pattern STATUS_CODE_PATTERN = Pattern.compile("\\d+"); + private final OpenApiSpecification openApiSpec; private final String operationId; private final String statusCode; + private final String accept; + private boolean randomGenerationEnabled = true; - private final HttpMessage httpMessage; - - public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId, String statusCode) { + public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, + OpenApiSpecification openApiSpec, + String operationId, String statusCode, String accept) { super(httpMessage); this.openApiSpec = openApiSpec; this.operationId = operationId; this.statusCode = statusCode; - this.httpMessage = httpMessage; + this.accept = accept; + } + + public OpenApiServerResponseMessageBuilder enableRandomGeneration(boolean enable) { + this.randomGenerationEnabled = enable; + return this; } @Override public Message build(TestContext context, String messageType) { - OasOperation operation = null; - OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); - - for (OasPathItem path : OasModelHelper.getPathItems(oasDocument.paths)) { - Optional> operationEntry = OasModelHelper.getOperationMap(path).entrySet().stream() - .filter(op -> operationId.equals(op.getValue().operationId)) - .findFirst(); - if (operationEntry.isPresent()) { - operation = operationEntry.get().getValue(); - break; - } + if (STATUS_CODE_PATTERN.matcher(statusCode).matches()) { + getMessage().status(HttpStatus.valueOf(parseInt(statusCode))); + } else { + getMessage().status(OK); } - if (operation == null) { - throw new CitrusRuntimeException(("Unable to locate operation with id '%s' " + - "in OpenAPI specification %s").formatted(operationId, openApiSpec.getSpecUrl())); + List initialHeaderBuilders = new ArrayList<>(getHeaderBuilders()); + getHeaderBuilders().clear(); + + if (randomGenerationEnabled) { + openApiSpec.getOperation(operationId, context) + .ifPresentOrElse(operationPathAdapter -> + fillRandomData(operationPathAdapter, context), () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpec.getSpecUrl())); + }); } - if (operation.responses != null) { - buildResponse(context, operation, oasDocument); - } + // Initial header builder need to be prepended, so that they can overwrite randomly generated headers. + getHeaderBuilders().addAll(initialHeaderBuilders); - OasModelHelper.getResponseContentTypeForRandomGeneration(oasDocument, operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + return super.build(context, messageType); + } - if (Pattern.compile("\\d+").matcher(statusCode).matches()) { - httpMessage.status(HttpStatus.valueOf(Integer.parseInt(statusCode))); - } else { - httpMessage.status(HttpStatus.OK); - } + private void fillRandomData(OperationPathAdapter operationPathAdapter, TestContext context) { + OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); - return super.build(context, messageType); + if (operationPathAdapter.operation().responses != null) { + buildResponse(context, operationPathAdapter.operation(), oasDocument); + } } private void buildResponse(TestContext context, OasOperation operation, OasDocument oasDocument) { - OasResponse response = Optional.ofNullable(operation.responses.getItem(statusCode)) - .orElse(operation.responses.default_); - - if (response != null) { - Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); - for (Map.Entry header : requiredHeaders.entrySet()) { - httpMessage.setHeader(header.getKey(), - OpenApiTestDataGenerator.createRandomValueExpression(header.getKey(), header.getValue(), - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, - context)); + + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + openApiSpec.getOpenApiDoc(context), operation, statusCode, null); + + if (responseForRandomGeneration.isPresent()) { + buildRandomHeaders(context, oasDocument, responseForRandomGeneration.get()); + buildRandomPayload(operation, oasDocument, responseForRandomGeneration.get()); + } + } + + private void buildRandomHeaders(TestContext context, OasDocument oasDocument, OasResponse response) { + Set filteredHeaders = new HashSet<>(getMessage().getHeaders().keySet()); + Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains( + entry.getKey()); + + Map requiredHeaders = OasModelHelper.getRequiredHeaders( + response); + requiredHeaders.entrySet().stream() + .filter(filteredHeadersPredicate) + .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( + singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), + entry.getValue(), + OasModelHelper.getSchemaDefinitions(oasDocument), false, + openApiSpec, + context)))) + ); + + // Also filter the required headers, as they have already been processed + filteredHeaders.addAll(requiredHeaders.keySet()); + + Map headers = OasModelHelper.getHeaders(response); + headers.entrySet().stream() + .filter(filteredHeadersPredicate) + .filter(entry -> context.getVariables().containsKey(entry.getKey())) + .forEach((entry -> addHeaderBuilder( + new DefaultHeaderBuilder(singletonMap(entry.getKey(), + CitrusSettings.VARIABLE_PREFIX + entry.getKey() + + CitrusSettings.VARIABLE_SUFFIX))))); + } + + private void buildRandomPayload(OasOperation operation, OasDocument oasDocument, + OasResponse response) { + + Optional> schemaForMediaTypeOptional; + if (statusCode.startsWith("2")) { + // if status code is good, and we have an accept, try to get the media type. Note that only json and plain text can be generated randomly. + schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, + response, accept != null ? List.of(accept) : null); + } else { + // In the bad case, we cannot expect, that the accept type is the type which we must generate. + // We request the type supported by the response and the random generator (json and plain text). + schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, null); + } + + if (schemaForMediaTypeOptional.isPresent()) { + OasAdapter schemaForMediaType = schemaForMediaTypeOptional.get(); + if (getMessage().getPayload() == null || ( + getMessage().getPayload() instanceof String string && string.isEmpty())) { + createRandomPayload(getMessage(), oasDocument, schemaForMediaType); } - Map headers = OasModelHelper.getHeaders(response); - for (Map.Entry header : headers.entrySet()) { - if (!requiredHeaders.containsKey(header.getKey()) && - context.getVariables().containsKey(header.getKey())) { - httpMessage.setHeader(header.getKey(), - CitrusSettings.VARIABLE_PREFIX + header.getKey() + CitrusSettings.VARIABLE_SUFFIX); - } + // If we have a schema and a media type and the content type has not yet been set, do it. + // If schema is null, we do not set the content type, as there is no content. + if (!getMessage().getHeaders().containsKey(HttpMessageHeaders.HTTP_CONTENT_TYPE) && schemaForMediaType.getAdapted() != null && schemaForMediaType.getNode() != null) { + addHeaderBuilder(new DefaultHeaderBuilder(singletonMap(HttpMessageHeaders.HTTP_CONTENT_TYPE, schemaForMediaType.getAdapted()))); } + } + } + + private void createRandomPayload(HttpMessage message, OasDocument oasDocument, OasAdapter schemaForMediaType) { - Optional responseSchema = OasModelHelper.getSchema(response); - responseSchema.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + if (schemaForMediaType.getNode() == null) { + // No schema means no payload, no type + message.setPayload(null); + } else { + if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.getAdapted())) { + // Schema but plain text + message.setPayload(createOutboundPayload(schemaForMediaType.getNode(), + OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); + message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); + } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.getAdapted())) { + // Json Schema + message.setPayload(createOutboundPayload(schemaForMediaType.getNode(), + OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); + message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); + } } } } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java new file mode 100644 index 0000000000..a3f6fa8c52 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java @@ -0,0 +1,24 @@ +package org.citrusframework.openapi.model; + +import io.apicurio.datamodels.core.models.Node; + +public class OasAdapter { + + private final S node; + + private final T adapted; + + public OasAdapter(S node, T adapted) { + this.node = node; + this.adapted = adapted; + } + + public S getNode() { + return node; + } + + public T getAdapted() { + return adapted; + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index 94f966901e..c15f6c3732 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,6 +16,9 @@ package org.citrusframework.openapi.model; +import static java.util.Collections.singletonList; + +import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; @@ -32,20 +35,34 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; import io.apicurio.datamodels.openapi.v3.models.Oas30Parameter; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; -import java.util.ArrayList; +import jakarta.annotation.Nullable; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Predicate; import org.citrusframework.openapi.model.v2.Oas20ModelHelper; import org.citrusframework.openapi.model.v3.Oas30ModelHelper; +import org.citrusframework.util.StringUtils; +import org.springframework.http.MediaType; public final class OasModelHelper { + public static final String DEFAULT_ = "default_"; + + /** + * List of preferred media types in the order of priority, + * used when no specific 'Accept' header is provided to determine the default response type. + */ + public static final List DEFAULT_ACCEPTED_MEDIA_TYPES = List.of(MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE); + private OasModelHelper() { // utility class } @@ -74,9 +91,11 @@ public static boolean isArrayType(@Nullable OasSchema schema) { * @return true if given schema is an object array. */ 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) { return isObjectType(oasSchema); @@ -106,7 +125,7 @@ public static List getSchemes(OasDocument openApiDoc) { public static OasSchema resolveSchema(OasDocument oasDocument, OasSchema schema) { if (isReferenceType(schema)) { - return getSchemaDefinitions(oasDocument).get(schema.$ref); + return getSchemaDefinitions(oasDocument).get(getReferenceName(schema.$ref)); } return schema; @@ -191,6 +210,16 @@ public static String getReferenceName(String reference) { public static Optional getSchema(OasResponse response) { return delegate(response, Oas20ModelHelper::getSchema, Oas30ModelHelper::getSchema); } + + public static Optional> getSchema(OasOperation oasOperation, OasResponse response, List acceptedMediaTypes) { + if (oasOperation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { + return Oas20ModelHelper.getSchema(oas20Operation, oas20Response, acceptedMediaTypes); + } else if (oasOperation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { + return Oas30ModelHelper.getSchema(oas30Operation, oas30Response, acceptedMediaTypes); + } + throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); + } + public static Optional getParameterSchema(OasParameter parameter) { return delegate(parameter, Oas20ModelHelper::getParameterSchema, Oas30ModelHelper::getParameterSchema); } @@ -216,22 +245,71 @@ public static Collection getResponseTypes(OasOperation operation, OasRes } /** - * Determines the appropriate response from an OAS (OpenAPI Specification) operation. - * The method looks for the response status code within the range 200 to 299 and returns - * the corresponding response if one is found. The first response in the list of responses, - * that satisfies the constraint will be returned. (TODO: see comment in Oas30ModelHelper) If none of the responses has a 2xx status code, - * the first response in the list will be returned. + * Determines the appropriate random response from an OpenAPI Specification operation based on the given status code. + * If a status code is specified, return the response for the specified status code. May be empty. + *

+ * If no exact match is found: + *

    + *
  • Fallback 1: Returns the 'default_' response if it exists.
  • + *
  • Fallback 2: Returns the first response object related to a 2xx status code that contains an acceptable schema for random message generation.
  • + *
  • Fallback 3: Returns the first response object related to a 2xx status code even without a schema. This is for operations that simply do not return anything else than a status code.
  • + *
  • Fallback 4: Returns the first response in the list of responses, no matter which schema.
  • + *
* + * Note that for Fallback 3 and 4, it is very likely, that there is no schema specified. It is expected, that an empty response is a viable response in these cases. + * + * @param openApiDoc The OpenAPI document containing the API specifications. + * @param operation The OAS operation for which to determine the response. + * @param statusCode The specific status code to match against responses, or {@code null} to search for any acceptable response. + * @param accept The mediatype accepted by the request + * @return An {@link Optional} containing the resolved {@link OasResponse} if found, or {@link Optional#empty()} otherwise. */ - public static Optional getResponseForRandomGeneration(OasDocument openApiDoc, OasOperation operation) { - return delegate(openApiDoc, operation, Oas20ModelHelper::getResponseForRandomGeneration, Oas30ModelHelper::getResponseForRandomGeneration); - } + public static Optional getResponseForRandomGeneration(OasDocument openApiDoc, OasOperation operation, @Nullable String statusCode, @Nullable String accept) { - /** - * Returns the response type used for random response generation. See specific helper implementations for detail. - */ - public static Optional getResponseContentTypeForRandomGeneration(OasDocument openApiDoc, OasOperation operation) { - return delegate(openApiDoc, operation, Oas20ModelHelper::getResponseContentTypeForRandomGeneration, Oas30ModelHelper::getResponseContentTypeForRandomGeneration); + if (operation.responses == null || operation.responses.getResponses().isEmpty()) { + return Optional.empty(); + } + + // Resolve all references + Map responseMap = OasModelHelper.resolveResponses(openApiDoc, + operation.responses); + + // For a given status code, do not fall back + if (statusCode != null) { + return Optional.ofNullable(responseMap.get(statusCode)); + } + + // Only accept responses that provide a schema for which we can actually provide a random message + Predicate acceptedSchemas = resp -> getSchema(operation, resp, accept != null ? singletonList(accept) : DEFAULT_ACCEPTED_MEDIA_TYPES).isPresent(); + + // Fallback 1: Pick the default if it exists + Optional response = Optional.ofNullable(responseMap.get(DEFAULT_)); + + if (response.isEmpty()) { + // Fallback 2: Pick the response object related to the first 2xx, providing an accepted schema + response = responseMap.values().stream() + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .filter(acceptedSchemas) + .findFirst(); + } + + if (response.isEmpty()) { + // Fallback 3: Pick the response object related to the first 2xx (even without schema) + response = responseMap.values().stream() + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .findFirst(); + } + + if (response.isEmpty()) { + // Fallback 4: Pick the first response no matter which schema + response = operation.responses.getResponses().stream() + .map(resp -> responseMap.get(resp.getStatusCode())) + .filter(Objects::nonNull).findFirst(); + } + + return response; } /** @@ -326,6 +404,8 @@ private static T delegate(OasOperation operation, FunctionThis method iterates over the responses contained in the {@link OasResponses} object. If a response has a reference - * (indicated by a non-null {@code $ref} field), the reference is resolved using the {@code responseResolver} function. Other responses - * will be added to the result list as is.

+ *

+ * This method iterates over the responses contained in the {@link OasResponses} object. If a response has a reference + * (indicated by a non-null {@code $ref} field), it resolves the reference and adds the resolved response to the result list. + * Non-referenced responses are added to the result list as-is. The resulting map includes the default response under + * the key {@link OasModelHelper#DEFAULT_}, if it exists. + *

* - * @param responses the {@link OasResponses} instance containing the responses to be resolved. - * @param responseResolver a {@link Function} that takes a reference string and returns the corresponding {@link OasResponse}. + * @param responses the {@link OasResponses} instance containing the responses to be resolved. * @return a {@link List} of {@link OasResponse} instances, where all references have been resolved. */ - public static List resolveResponses(OasResponses responses, Function responseResolver) { + private static Map resolveResponses(OasDocument openApiDoc, OasResponses responses) { + + Function responseResolver = getResponseResolver( + openApiDoc); - List responseList = new ArrayList<>(); + Map responseMap = new HashMap<>(); for (OasResponse response : responses.getResponses()) { if (response.$ref != null) { OasResponse resolved = responseResolver.apply(getReferenceName(response.$ref)); if (resolved != null) { - responseList.add(resolved); + // Note that we need to get the statusCode from the ref, as the referenced does not know about it. + responseMap.put(response.getStatusCode(), resolved); } } else { - responseList.add(response); + responseMap.put(response.getStatusCode(), response); } } - return responseList; + if (responses.default_ != null) { + if (responses.default_.$ref != null) { + OasResponse resolved = responseResolver.apply(responses.default_.$ref); + if (resolved != null) { + responseMap.put(DEFAULT_, resolved); + } + } else { + responseMap.put(DEFAULT_, responses.default_); + } + } + + return responseMap; + } + + private static Function getResponseResolver( + OasDocument openApiDoc) { + return delegate(openApiDoc, + (Function>) doc -> (responseRef -> doc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))), + (Function>) doc -> (responseRef -> doc.components.responses.get(OasModelHelper.getReferenceName(responseRef)))); + } + + /** + * Traverses the OAS document and applies the given visitor to each OAS operation found. + * This method uses the provided {@link OasOperationVisitor} to process each operation within the paths of the OAS document. + * + * @param oasDocument the OAS document to traverse + * @param visitor the visitor to apply to each OAS operation + */ + public static void visitOasOperations(OasDocument oasDocument, OasOperationVisitor visitor) { + if (oasDocument == null || visitor == null) { + return; + } + + oasDocument.paths.accept(new CombinedVisitorAdapter() { + + @Override + public void visitPaths(OasPaths oasPaths) { + oasPaths.getPathItems().forEach(oasPathItem -> oasPathItem.accept(this)); + } + + @Override + public void visitPathItem(OasPathItem oasPathItem) { + String path = oasPathItem.getPath(); + + if (StringUtils.isEmpty(path)) { + return; + } + + getOperationMap(oasPathItem).values() + .forEach(oasOperation -> visitor.visit(oasPathItem, oasOperation)); + + } + }); + } + + /** + * Resolves and normalizes a list of accepted media types. If the input list is null, + * returns null. Otherwise, splits each media type string by comma, trims whitespace, + * and collects them into a list of normalized types. + * + * @param acceptedMediaTypes List of accepted media types, may be null. + * @return Normalized list of media types, or null if input is null. + */ + public static List resolveAllTypes(@Nullable List acceptedMediaTypes) { + if (acceptedMediaTypes == null) { + return acceptedMediaTypes; + } + + return acceptedMediaTypes.stream() + .flatMap(types -> Arrays.stream(types.split(","))).map(String::trim).toList(); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasOperationVisitor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasOperationVisitor.java new file mode 100644 index 0000000000..85e4cfbb35 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasOperationVisitor.java @@ -0,0 +1,28 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.model; + +import io.apicurio.datamodels.openapi.models.OasOperation; +import io.apicurio.datamodels.openapi.models.OasPathItem; + +/** + * The {@code OasOperationVisitor} interface defines a visitor pattern for operations on OAS (OpenAPI Specification) path items and operations. + */ +public interface OasOperationVisitor { + + void visit(OasPathItem oasPathItem, OasOperation oasOperation); +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java new file mode 100644 index 0000000000..7d943af929 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -0,0 +1,39 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.model; + +import static java.lang.String.format; + +import io.apicurio.datamodels.openapi.models.OasOperation; +import org.citrusframework.openapi.OpenApiUtils; + +/** + * Adapts the different paths associated with an OpenAPI operation to the {@link OasOperation}. + * This record holds the API path, context path, full path, and the associated {@link OasOperation} object. + * + * @param apiPath The API path for the operation. + * @param contextPath The context path in which the API is rooted. + * @param fullPath The full path combining context path and API path. + * @param operation The {@link OasOperation} object representing the operation details. + */ +public record OperationPathAdapter(String apiPath, String contextPath, String fullPath, OasOperation operation) { + + @Override + public String toString() { + return format("%s (%s)",OpenApiUtils.getMethodPath(operation.getMethod(), apiPath), operation.operationId); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index 8cb66e20fc..34794a8f71 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -18,7 +18,6 @@ import io.apicurio.datamodels.openapi.models.OasHeader; import io.apicurio.datamodels.openapi.models.OasParameter; -import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; import io.apicurio.datamodels.openapi.v2.models.Oas20Header; @@ -27,6 +26,7 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition; +import java.util.Arrays; import jakarta.annotation.Nullable; import java.util.Collection; import java.util.Collections; @@ -34,8 +34,8 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; -import org.springframework.http.MediaType; public final class Oas20ModelHelper { @@ -53,12 +53,12 @@ public static List 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 getSchemaDefinitions(Oas20Document openApiDoc) { if (openApiDoc == null - || openApiDoc.definitions == null) { + || openApiDoc.definitions == null) { return Collections.emptyMap(); } @@ -69,6 +69,23 @@ public static Optional getSchema(Oas20Response response) { return Optional.ofNullable(response.schema); } + public static Optional> getSchema(Oas20Operation oas20Operation, Oas20Response response, List acceptedMediaTypes) { + + acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); + acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; + + OasSchema selectedSchema = response.schema; + String selectedMediaType = null; + if (oas20Operation.produces != null && !oas20Operation.produces.isEmpty()) { + selectedMediaType = acceptedMediaTypes.stream() + .filter(type -> !isFormDataMediaType(type)) + .filter(type -> oas20Operation.produces.contains(type)).findFirst() + .orElse(null); + } + + return selectedSchema == null && selectedMediaType == null ? Optional.empty() : Optional.of(new OasAdapter<>(selectedSchema, selectedMediaType)); + } + public static Optional getRequestBodySchema(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { if (operation.parameters == null) { return Optional.empty(); @@ -77,8 +94,8 @@ public static Optional getRequestBodySchema(@Nullable Oas20Document i final List operationParameters = operation.parameters; Optional 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); } @@ -91,67 +108,24 @@ public static Optional getRequestContentType(Oas20Operation operation) { return Optional.empty(); } - public static Collection getResponseTypes(Oas20Operation operation,@Nullable Oas20Response ignoredResponse) { + public static Collection getResponseTypes(Oas20Operation operation, @Nullable Oas20Response ignoredResponse) { if (operation == null) { return Collections.emptyList(); } return operation.produces; } - /** - * 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 ignoredOpenApiDoc required to implement quasi interface but ignored in this implementation. - * @param operation - * @return - */ - public static Optional getResponseContentTypeForRandomGeneration(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { - if (operation.produces != null) { - for (String mediaType : operation.produces) { - if (MediaType.APPLICATION_JSON_VALUE.equals(mediaType)) { - return Optional.of(mediaType); - } - } - } - - return Optional.empty(); - } - - public static Optional getResponseForRandomGeneration(Oas20Document openApiDoc, Oas20Operation operation) { - - if (operation.responses == null) { - return Optional.empty(); - } - - List responses = OasModelHelper.resolveResponses(operation.responses, - responseRef -> openApiDoc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))); - - // Pick the response object related to the first 2xx return code found - Optional response = responses.stream() - .filter(Oas20Response.class::isInstance) - .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) - .map(OasResponse.class::cast) - .filter(res -> OasModelHelper.getSchema(res).isPresent()) - .findFirst(); - - if (response.isEmpty()) { - // TODO: Although the Swagger specification states that at least one successful response SHOULD be specified in the responses, - // the Petstore API does not. It only specifies error responses. As a result, we currently only return a successful response if one is found. - // If no successful response is specified, we return an empty response instead, to be backwards compatible. - response = Optional.empty(); - } - - return response; - } - public static Map getHeaders(Oas20Response response) { if (response.headers == null) { return Collections.emptyMap(); } return response.headers.getHeaders().stream() - .collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema)); + .collect(Collectors.toMap(OasHeader::getName, Oas20ModelHelper::getHeaderSchema)); + } + + private static boolean isFormDataMediaType(String type) { + return Arrays.asList("application/x-www-form-urlencoded", "multipart/form-data").contains(type); } /** diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index cfc3dd1efe..1f56f4d4c5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -18,7 +18,6 @@ import io.apicurio.datamodels.core.models.common.Server; import io.apicurio.datamodels.core.models.common.ServerVariable; -import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Document; import io.apicurio.datamodels.openapi.v3.models.Oas30MediaType; @@ -26,6 +25,7 @@ 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 io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import java.net.MalformedURLException; import java.net.URL; import java.util.Arrays; @@ -37,10 +37,10 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.http.MediaType; public final class Oas30ModelHelper { @@ -75,17 +75,17 @@ public static List 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) { @@ -116,8 +116,8 @@ public static Map 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 getSchema(Oas30Response response) { @@ -127,11 +127,38 @@ public static Optional 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> getSchema( + Oas30Operation ignoredOas30Operation, Oas30Response response, List acceptedMediaTypes) { + + acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); + acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; + + Map content = response.content; + if (content == null) { + return Optional.empty(); + } + + String selectedMediaType = null; + Oas30Schema selectedSchema = null; + for (String type : acceptedMediaTypes) { + if (!isFormDataMediaType(type)) { + Oas30MediaType oas30MediaType = content.get(type); + if (oas30MediaType != null) { + selectedMediaType = type; + selectedSchema = oas30MediaType.schema; + break; + } + } + } + + return selectedSchema == null && selectedMediaType == null ? Optional.empty() : Optional.of(new OasAdapter<>(selectedSchema, selectedMediaType)); } public static Optional getRequestBodySchema(Oas30Document openApiDoc, Oas30Operation operation) { @@ -142,8 +169,8 @@ public static Optional 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)); } @@ -152,12 +179,12 @@ public static Optional 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 getRequestContentType(Oas30Operation operation) { @@ -166,10 +193,10 @@ public static Optional 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 getResponseTypes(Oas30Operation operation, Oas30Response response) { @@ -179,73 +206,15 @@ public static Collection getResponseTypes(Oas30Operation operation, Oas3 return response.content != null ? response.content.keySet() : Collections.emptyList(); } - /** - * 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 operation - * @return - */ - public static Optional getResponseContentTypeForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) { - Optional responseForRandomGeneration = getResponseForRandomGeneration( - openApiDoc, operation); - return responseForRandomGeneration.map( - 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()); - } - - public static Optional getResponseForRandomGeneration(Oas30Document openApiDoc, Oas30Operation operation) { - if (operation.responses == null) { - return Optional.empty(); - } - - List responses = OasModelHelper.resolveResponses(operation.responses, - responseRef -> openApiDoc.components.responses.get(OasModelHelper.getReferenceName(responseRef))); - - // Pick the response object related to the first 2xx return code found - Optional response = responses.stream() - .filter(Oas30Response.class::isInstance) - .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) - .map(OasResponse.class::cast) - .filter(res -> OasModelHelper.getSchema(res).isPresent()) - .findFirst(); - - // No 2xx response given so pick the first one no matter what status code - if (response.isEmpty()) { - // TODO: This behavior differs from OAS2 and is very likely a bug because it may result in returning error messages. - // According to the specification, there MUST be at least one response, which SHOULD be a successful response. - // If the response is NOT A SUCCESSFUL one, we encounter an error case, which is likely not the intended behavior. - // The specification likely does not intend to define operations that always fail. On the other hand, it is not - // against the spec to NOT document an OK response that is empty. - // For testing purposes, note that the difference between OAS2 and OAS3 is evident in the Petstore API. - // The Petstore API specifies successful response codes for OAS3 but lacks these definitions for OAS2. - // Therefore, while tests pass for OAS3, they fail for OAS2. - // I would suggest to return an empty response in case we fail to resolve a good response, as in Oas2. - // In case of absence of a response an OK response will be sent as default. - response = responses.stream() - .filter(Oas30Response.class::isInstance) - .map(OasResponse.class::cast) - .filter(res -> OasModelHelper.getSchema(res).isPresent()) - .findFirst(); - } - - return response; - } - public static Map getRequiredHeaders(Oas30Response response) { if (response.headers == null) { return Collections.emptyMap(); } 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 getHeaders(Oas30Response response) { @@ -254,8 +223,8 @@ public static Map 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) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java new file mode 100644 index 0000000000..b640adb365 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java @@ -0,0 +1,60 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.validation.ValidationProcessor; + +/** + * {@code ValidationProcessor} that facilitates the use of Atlassian's Swagger Request Validator, + * and delegates validation of OpenApi requests to instances of {@link OpenApiRequestValidator}. + */ +public class OpenApiRequestValidationProcessor implements + ValidationProcessor { + + private final OpenApiSpecification openApiSpecification; + + private final String operationId; + + private boolean enabled = true; + + public OpenApiRequestValidationProcessor(OpenApiSpecification openApiSpecification, + String operationId) { + this.operationId = operationId; + this.openApiSpecification = openApiSpecification; + } + + + @Override + public void validate(Message message, TestContext context) { + + if (!enabled || !(message instanceof HttpMessage httpMessage)) { + return; + } + openApiSpecification.getOperation( + operationId, context).ifPresent(operationPathAdapter -> + openApiSpecification.getRequestValidator().ifPresent(openApiRequestValidator -> + openApiRequestValidator.validateRequest(operationPathAdapter, httpMessage))); + } + + public void setEnabled(boolean b) { + this.enabled = b; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java new file mode 100644 index 0000000000..6948c793d8 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -0,0 +1,97 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.model.Request; +import com.atlassian.oai.validator.model.SimpleRequest; +import com.atlassian.oai.validator.report.ValidationReport; +import java.util.ArrayList; +import java.util.Collection; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.model.OperationPathAdapter; + +/** + * Specific validator that uses atlassian and is responsible for validating HTTP requests + * against an OpenAPI specification using the provided {@code OpenApiInteractionValidator}. + */ +public class OpenApiRequestValidator extends OpenApiValidator { + + public OpenApiRequestValidator(OpenApiInteractionValidator openApiInteractionValidator) { + super(openApiInteractionValidator, isRequestValidationEnabledlobally()); + } + + @Override + protected String getType() { + return "request"; + } + + public void validateRequest(OperationPathAdapter operationPathAdapter, + HttpMessage requestMessage) { + + if (enabled && openApiInteractionValidator != null) { + ValidationReport validationReport = openApiInteractionValidator.validateRequest( + createRequestFromMessage(operationPathAdapter, requestMessage)); + if (validationReport.hasErrors()) { + throw new ValidationException( + constructErrorMessage(operationPathAdapter, validationReport)); + } + } + } + + Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, + HttpMessage httpMessage) { + var payload = httpMessage.getPayload(); + + String contextPath = operationPathAdapter.contextPath(); + String requestUri = (String) httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI); + if (contextPath != null && requestUri.startsWith(contextPath)) { + requestUri = requestUri.substring(contextPath.length()); + } + + SimpleRequest.Builder requestBuilder = new SimpleRequest.Builder( + httpMessage.getRequestMethod().asHttpMethod().name(), requestUri + ); + + if (payload != null) { + requestBuilder = requestBuilder.withBody(payload.toString()); + } + + SimpleRequest.Builder finalRequestBuilder = requestBuilder; + finalRequestBuilder.withAccept(httpMessage.getAccept()); + + httpMessage.getQueryParams() + .forEach((key, value) -> finalRequestBuilder.withQueryParam(key, new ArrayList<>( + value))); + + httpMessage.getHeaders().forEach((key, value) -> { + if (value instanceof Collection) { + ((Collection) value).forEach( v -> finalRequestBuilder.withHeader(key, v != null ? v.toString() : null)); + } else { + finalRequestBuilder.withHeader(key, + value != null ? value.toString() : null); + } + }); + + return requestBuilder.build(); + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java new file mode 100644 index 0000000000..18754062f1 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java @@ -0,0 +1,58 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.validation.ValidationProcessor; + +/** + * {@code ValidationProcessor} that delegates validation of OpenApi responses to instances of {@link OpenApiResponseValidator}. + */ +public class OpenApiResponseValidationProcessor implements + ValidationProcessor { + + private final OpenApiSpecification openApiSpecification; + + private final String operationId; + + private boolean enabled = true; + + public OpenApiResponseValidationProcessor(OpenApiSpecification openApiSpecification, String operationId) { + this.operationId = operationId; + this.openApiSpecification = openApiSpecification; + } + + @Override + public void validate(Message message, TestContext context) { + + if (!enabled || !(message instanceof HttpMessage httpMessage)) { + return; + } + + openApiSpecification.getOperation( + operationId, context).ifPresent(operationPathAdapter -> + openApiSpecification.getResponseValidator().ifPresent(openApiResponseValidator -> + openApiResponseValidator.validateResponse(operationPathAdapter, httpMessage))); + } + + public void setEnabled(boolean b) { + this.enabled = b; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java new file mode 100644 index 0000000000..db4a41e375 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -0,0 +1,77 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.model.Request.Method; +import com.atlassian.oai.validator.model.Response; +import com.atlassian.oai.validator.model.SimpleResponse; +import com.atlassian.oai.validator.report.ValidationReport; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.springframework.http.HttpStatusCode; + +/** + * Specific validator, that facilitates the use of Atlassian's Swagger Request Validator, + * and delegates validation of OpenApi requests to instances of {@link OpenApiRequestValidator}. + */ +public class OpenApiResponseValidator extends OpenApiValidator { + + public OpenApiResponseValidator(OpenApiInteractionValidator openApiInteractionValidator) { + super(openApiInteractionValidator, isResponseValidationEnabledGlobally()); + } + + @Override + protected String getType() { + return "response"; + } + + public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { + + if (enabled && openApiInteractionValidator != null) { + HttpStatusCode statusCode = httpMessage.getStatusCode(); + Response response = createResponseFromMessage(httpMessage, + statusCode != null ? statusCode.value() : null); + + ValidationReport validationReport = openApiInteractionValidator.validateResponse( + operationPathAdapter.apiPath(), + Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), + response); + if (validationReport.hasErrors()) { + throw new ValidationException(constructErrorMessage(operationPathAdapter, validationReport)); + } + } + } + + Response createResponseFromMessage(HttpMessage message, Integer statusCode) { + var payload = message.getPayload(); + SimpleResponse.Builder responseBuilder = new SimpleResponse.Builder(statusCode); + + if (payload != null) { + responseBuilder = responseBuilder.withBody(payload.toString()); + } + + SimpleResponse.Builder finalResponseBuilder = responseBuilder; + message.getHeaders().forEach((key, value) -> finalResponseBuilder.withHeader(key, + value != null ? value.toString() : null)); + + return responseBuilder.build(); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java new file mode 100644 index 0000000000..a6bc2e98c8 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java @@ -0,0 +1,61 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.report.ValidationReport; +import org.citrusframework.openapi.model.OperationPathAdapter; + +public abstract class OpenApiValidator { + + protected final OpenApiInteractionValidator openApiInteractionValidator; + + protected boolean enabled; + + protected OpenApiValidator(OpenApiInteractionValidator openApiInteractionValidator, boolean enabled) { + this.openApiInteractionValidator = openApiInteractionValidator; + this.enabled = enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + protected abstract String getType(); + + /** + * Constructs the error message of a failed validation based on the processing report passed + * from {@link ValidationReport}. + * + * @param report The report containing the error message + * @return A string representation of all messages contained in the report + */ + protected String constructErrorMessage(OperationPathAdapter operationPathAdapter, + ValidationReport report) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("OpenApi "); + stringBuilder.append(getType()); + stringBuilder.append(" validation failed for operation: "); + stringBuilder.append(operationPathAdapter); + report.getMessages().forEach(message -> stringBuilder.append("\n\t").append(message)); + return stringBuilder.toString(); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java new file mode 100644 index 0000000000..9d811711f6 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java @@ -0,0 +1,171 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class OpenApiPathRegistryTest { + + private static final String[] SEGMENTS = {"api", "v1", "pet", "user", "order", "product", + "category", "service", "data"}; + private static final String VARIABLE_TEMPLATE = "{%s}"; + private static final String[] VARIABLES = {"id", "userId", "orderId", "productId", + "categoryId"}; + + public static List generatePaths(int numberOfPaths) { + List paths = new ArrayList<>(); + Random random = new Random(); + + Set allGenerated = new HashSet<>(); + while (allGenerated.size() < numberOfPaths) { + int numberOfSegments = 1 + random.nextInt(7); // 1 to 7 segments + StringBuilder pathBuilder = new StringBuilder("/api/v1"); + + int nids = 0; + for (int j = 0; j < numberOfSegments; j++) { + if (nids < 2 && nids < numberOfSegments - 1 && random.nextBoolean()) { + nids++; + // Add a segment with a variable + pathBuilder.append("/").append(String.format(VARIABLE_TEMPLATE, + VARIABLES[random.nextInt(VARIABLES.length)])); + } else { + // Add a fixed segment + pathBuilder.append("/").append(SEGMENTS[random.nextInt(SEGMENTS.length)]); + } + } + + String path = pathBuilder.toString(); + if (!allGenerated.contains(path)) { + paths.add(path); + allGenerated.add(path); + } + } + return paths; + } + + @Test + public void insertShouldSucceedOnSameValue() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2", "root")); + assertTrue(openApiPathRegistry.insert("/s1/s2", "root")); + assertEquals(openApiPathRegistry.search("/s1/s2"), "root"); + } + + @Test + public void insertShouldFailOnSamePathWithDifferentValue() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2", "root1")); + assertFalse(openApiPathRegistry.insert("/s1/s2", "root2")); + assertEquals(openApiPathRegistry.search("/s1/s2"), "root1"); + } + + @Test + public void searchShouldSucceedOnPartialPathMatchWithDifferentVariables() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id2}/s4/{id1}", "root2")); + assertEquals(openApiPathRegistry.search("/s1/s2/1111"), "root1"); + assertEquals(openApiPathRegistry.search("/s1/s2/123/s4/222"), "root2"); + + openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id2}", "root1")); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s4/{id2}", "root2")); + assertEquals(openApiPathRegistry.search("/s1/s2/1111"), "root1"); + assertEquals(openApiPathRegistry.search("/s1/s2/123/s4/222"), "root2"); + } + + @Test + public void insertShouldFailOnMatchingPathWithDifferentValue() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2", "root1")); + assertFalse(openApiPathRegistry.insert("/s1/{id1}", "root2")); + assertEquals(openApiPathRegistry.search("/s1/s2"), "root1"); + assertNull(openApiPathRegistry.search("/s1/111")); + + assertTrue(openApiPathRegistry.insert("/s1/s2/s3/{id2}", "root3")); + assertFalse(openApiPathRegistry.insert("/s1/{id1}/s3/{id2}", "root4")); + assertEquals(openApiPathRegistry.search("/s1/s2/s3/123"), "root3"); + assertEquals(openApiPathRegistry.search("/s1/s2/s3/456"), "root3"); + assertNull(openApiPathRegistry.search("/s1/111/s3/111")); + + openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/{id1}", "root2")); + assertFalse(openApiPathRegistry.insert("/s1/s2", "root1")); + assertEquals(openApiPathRegistry.search("/s1/111"), "root2"); + assertEquals(openApiPathRegistry.search("/s1/s2"), "root2"); + + assertTrue(openApiPathRegistry.insert("/s1/{id1}/s3/{id2}", "root3")); + assertFalse(openApiPathRegistry.insert("/s1/s2/s3/{id2}", "root4")); + assertEquals(openApiPathRegistry.search("/s1/5678/s3/1234"), "root3"); + assertEquals(openApiPathRegistry.search("/s1/s2/s3/1234"), "root3"); + } + + @Test + public void insertShouldNotOverwriteNested() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s3/{id2}", "root2")); + assertEquals(openApiPathRegistry.search("/s1/s2/123"), "root1"); + assertEquals(openApiPathRegistry.search("/s1/s2/1233/s3/121"), "root2"); + + openApiPathRegistry = new OpenApiPathRegistry<>(); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s3/{id2}", "root2")); + assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); + assertEquals(openApiPathRegistry.search("/s1/s2/123"), "root1"); + assertEquals(openApiPathRegistry.search("/s1/s2/1233/s3/121"), "root2"); + } + + @Test + public void randomAccess() { + OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); + + int numberOfPaths = 1000; // Specify the number of paths you want to generate + List paths = generatePaths(numberOfPaths); + + Map pathToValueMap = paths.stream() + .collect(Collectors.toMap(path -> path, k -> k.replaceAll("\\{[a-zA-Z]*}", "1111"))); + paths.removeIf(path -> !openApiPathRegistry.insert(path, pathToValueMap.get(path))); + + Random random = new Random(); + int[] indexes = new int[1000]; + for (int i = 0; i < 1000; i++) { + indexes[i] = random.nextInt(paths.size() - 1); + } + + for (int i = 0; i < 1000; i++) { + String path = paths.get(indexes[i]); + String realPath = pathToValueMap.get(path); + String result = openApiPathRegistry.search(realPath); + Assert.assertNotNull(result, + "No result for real path " + realPath + " expected a match by path " + path); + Assert.assertEquals(result, realPath); + } + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index 3c449ff5fe..9185cc6081 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -16,35 +16,105 @@ package org.citrusframework.openapi; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; import java.util.List; +import java.util.Optional; +import org.citrusframework.spi.Resource; import org.testng.annotations.Test; -@Test public class OpenApiRepositoryTest { - public static final String ROOT = "/root"; + private static final String ROOT = "/root"; - public void initializeOpenApiRepository() { + @Test + public void shouldInitializeOpenApiRepository() { OpenApiRepository openApiRepository = new OpenApiRepository(); openApiRepository.setRootContextPath(ROOT); - openApiRepository.setLocations(List.of("org/citrusframework/openapi/petstore/petstore**.json")); + openApiRepository.setLocations( + List.of("org/citrusframework/openapi/petstore/petstore**.json")); openApiRepository.initialize(); List openApiSpecifications = openApiRepository.getOpenApiSpecifications(); assertEquals(openApiRepository.getRootContextPath(), ROOT); assertNotNull(openApiSpecifications); - assertEquals(openApiSpecifications.size(),3); + assertEquals(openApiSpecifications.size(), 3); assertEquals(openApiSpecifications.get(0).getRootContextPath(), ROOT); assertEquals(openApiSpecifications.get(1).getRootContextPath(), ROOT); - assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); - assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); - assertTrue(SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); + assertTrue( + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); + assertTrue( + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); + assertTrue( + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); } + + @Test + public void shouldResolveResourceAliasFromFile() { + File fileMock = mock(); + doReturn("MyApi.json").when(fileMock).getName(); + Resource resourceMock = mock(); + doReturn(fileMock).when(resourceMock).getFile(); + + Optional alias = OpenApiRepository.determineResourceAlias(resourceMock); + assertTrue(alias.isPresent()); + assertEquals(alias.get(), "MyApi.json"); + } + + @Test + public void shouldResolveResourceAliasFromUrl() throws MalformedURLException { + URL urlMock = mock(); + doReturn("/C:/segment1/segment2/MyApi.json").when(urlMock).getPath(); + Resource resourceMock = mock(); + doThrow(new RuntimeException("Forced Exception")).when(resourceMock).getFile(); + doReturn(urlMock).when(resourceMock).getURL(); + + Optional alias = OpenApiRepository.determineResourceAlias(resourceMock); + assertTrue(alias.isPresent()); + assertEquals(alias.get(), "MyApi.json"); + } + + @Test + public void shouldSetAndProvideProperties() { + // Given + OpenApiRepository openApiRepository = new OpenApiRepository(); + + // When + openApiRepository.setResponseValidationEnabled(true); + openApiRepository.setRequestValidationEnabled(true); + openApiRepository.setRootContextPath("/root"); + openApiRepository.setLocations(List.of("l1", "l2")); + + // Then + assertTrue(openApiRepository.isResponseValidationEnabled()); + assertTrue(openApiRepository.isRequestValidationEnabled()); + assertEquals(openApiRepository.getRootContextPath(), "/root"); + assertEquals(openApiRepository.getLocations(), List.of("l1", "l2")); + + // When + openApiRepository.setResponseValidationEnabled(false); + openApiRepository.setRequestValidationEnabled(false); + openApiRepository.setRootContextPath("/otherRoot"); + openApiRepository.setLocations(List.of("l3", "l4")); + + // Then + assertFalse(openApiRepository.isResponseValidationEnabled()); + assertFalse(openApiRepository.isRequestValidationEnabled()); + assertEquals(openApiRepository.getRootContextPath(), "/otherRoot"); + assertEquals(openApiRepository.getLocations(), List.of("l3", "l4")); + + } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java new file mode 100644 index 0000000000..c96cd5f5b6 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -0,0 +1,196 @@ +package org.citrusframework.openapi; + +import static org.citrusframework.openapi.OpenApiSettings.GENERATE_OPTIONAL_FIELDS_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.REQUEST_VALIDATION_ENABLED_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_VALIDATION_ENABLED_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.VALIDATE_OPTIONAL_FIELDS_ENV; +import static org.citrusframework.openapi.OpenApiSettings.VALIDATE_OPTIONAL_FIELDS_PROPERTY; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; + +public class OpenApiSettingsTest { + + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); + + private static final boolean REQUEST_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isRequestValidationEnabledlobally(); + + private static final boolean RESPONSE_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isResponseValidationEnabledGlobally(); + + private static final boolean VALIDATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isValidateOptionalFieldsGlobally(); + + private static final boolean GENERATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isGenerateOptionalFieldsGlobally(); + + @BeforeMethod + public void beforeMethod() { + System.clearProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY); + System.clearProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY); + System.clearProperty(REQUEST_VALIDATION_ENABLED_PROPERTY); + System.clearProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY); + } + + @AfterMethod + public void afterMethod() throws Exception { + environmentVariables.teardown(); + + if (!GENERATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY) { + System.clearProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY); + } else { + System.setProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, "true"); + } + + if (!VALIDATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY) { + System.clearProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY); + } else { + System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "true"); + } + + if (!REQUEST_VALIDATION_ENABLED_GLOBALLY) { + System.clearProperty(REQUEST_VALIDATION_ENABLED_PROPERTY); + } else { + System.setProperty(REQUEST_VALIDATION_ENABLED_PROPERTY, "true"); + } + + if (!RESPONSE_VALIDATION_ENABLED_GLOBALLY) { + System.clearProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY); + } else { + System.setProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY, "true"); + } + } + + @Test + public void testRequestValidationEnabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(REQUEST_VALIDATION_ENABLED_PROPERTY, "true"); + assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + } + + @Test + public void testRequestValidationDisabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(REQUEST_VALIDATION_ENABLED_PROPERTY, "false"); + assertFalse(OpenApiSettings.isRequestValidationEnabledlobally()); + } + + @Test + public void testRequestValidationEnabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.REQUEST_VALIDATION_ENABLED_ENV, "true"); + environmentVariables.setup(); + assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + } + + @Test + public void testRequestValidationDisabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.REQUEST_VALIDATION_ENABLED_ENV, "false"); + environmentVariables.setup(); + assertFalse(OpenApiSettings.isRequestValidationEnabledlobally()); + } + + @Test + public void testRequestValidationEnabledByDefault() { + assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + } + + @Test + public void testResponseValidationEnabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY, "true"); + assertTrue(OpenApiSettings.isResponseValidationEnabledGlobally()); + } + + @Test + public void testResponseValidationDisabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY, "false"); + assertFalse(OpenApiSettings.isResponseValidationEnabledGlobally()); + } + + @Test + public void testResponseValidationEnabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.RESPONSE_VALIDATION_ENABLED_ENV, "true"); + environmentVariables.setup(); + assertTrue(OpenApiSettings.isResponseValidationEnabledGlobally()); + } + + @Test + public void testResponseValidationDisabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.RESPONSE_VALIDATION_ENABLED_ENV, "false"); + environmentVariables.setup(); + assertFalse(OpenApiSettings.isResponseValidationEnabledGlobally()); + } + + @Test + public void testResponseValidationEnabledByDefault() { + assertTrue(OpenApiSettings.isResponseValidationEnabledGlobally()); + } + + @Test + public void testGenerateOptionalFieldsEnabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, "true"); + assertTrue(OpenApiSettings.isGenerateOptionalFieldsGlobally()); + } + + @Test + public void testGenerateOptionalFieldsDisabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, "false"); + assertFalse(OpenApiSettings.isGenerateOptionalFieldsGlobally()); + } + + @Test + public void testGenerateOptionalFieldsEnabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.GENERATE_OPTIONAL_FIELDS_ENV, "true"); + environmentVariables.setup(); + assertTrue(OpenApiSettings.isGenerateOptionalFieldsGlobally()); + } + + @Test + public void testGenerateOptionalFieldsDisabledByEnvVar() throws Exception { + environmentVariables.set(OpenApiSettings.GENERATE_OPTIONAL_FIELDS_ENV, "false"); + environmentVariables.setup(); + assertFalse(OpenApiSettings.isGenerateOptionalFieldsGlobally()); + } + + @Test + public void testGenerateOptionalFieldsEnabledByDefault() { + assertTrue(OpenApiSettings.isGenerateOptionalFieldsGlobally()); + } + + @Test + public void testValidateOptionalFieldsEnabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "true"); + assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + } + + @Test + public void testValidateOptionalFieldsDisabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "false"); + assertFalse(OpenApiSettings.isValidateOptionalFieldsGlobally()); + } + + @Test + public void testValidateOptionalFieldsEnabledByEnvVar() throws Exception { + environmentVariables.set(VALIDATE_OPTIONAL_FIELDS_ENV, "true"); + environmentVariables.setup(); + assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + } + + @Test + public void testValidateOptionalFieldsDisabledByEnvVar() throws Exception { + environmentVariables.set(VALIDATE_OPTIONAL_FIELDS_ENV, "false"); + environmentVariables.setup(); + assertFalse(OpenApiSettings.isValidateOptionalFieldsGlobally()); + } + + @Test + public void testValidateOptionalFieldsEnabledByDefault() { + assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java new file mode 100644 index 0000000000..6693078ef2 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java @@ -0,0 +1,49 @@ +package org.citrusframework.openapi; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class OpenApiSpecificationAdapterTest { + + @Mock + private OpenApiSpecification openApiSpecificationMock; + + @Mock + private Object entityMock; + + private OpenApiSpecificationAdapter openApiSpecificationAdapter; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void setUp() { + mockCloseable = MockitoAnnotations.openMocks(this); + openApiSpecificationAdapter = new OpenApiSpecificationAdapter<>(openApiSpecificationMock, entityMock); + } + + @AfterMethod + public void tearDown() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldProvideOpenApiSpecification() { + OpenApiSpecification specification = openApiSpecificationAdapter.getOpenApiSpecification(); + assertNotNull(specification, "OpenApiSpecification should not be null"); + assertEquals(specification, openApiSpecificationMock, "OpenApiSpecification should match the mock"); + } + + @Test + public void shouldProvideEntity() { + Object entity = openApiSpecificationAdapter.getEntity(); + assertNotNull(entity, "Entity should not be null"); + assertEquals(entity, entityMock, "Entity should match the mock"); + } + +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java new file mode 100644 index 0000000000..5a8cb34c45 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -0,0 +1,387 @@ +package org.citrusframework.openapi; + +import io.apicurio.datamodels.openapi.models.OasDocument; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import javax.net.ssl.HttpsURLConnection; +import org.citrusframework.context.TestContext; +import org.citrusframework.endpoint.EndpointConfiguration; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources.ClasspathResource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.net.URL; +import java.util.Optional; + +import static org.citrusframework.util.FileUtils.readToString; +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; + +public class OpenApiSpecificationTest { + + + private static final String PING_API_HTTP_URL_STRING = "http://org.citrus.example.com/ping-api.yaml"; + + private static final String PING_API_HTTPS_URL_STRING = "https://org.citrus.example.com/ping-api.yaml"; + + private static final String PING_OPERATION_ID = "doPing"; + + private static final String PONG_OPERATION_ID = "doPong"; + + private static String PING_API_STRING; + + @Mock + private TestContext testContextMock; + + @Mock + private HttpClient httpClient; + + @Mock + private ReferenceResolver referenceResolverMock; + + @Mock + private HttpEndpointConfiguration endpointConfigurationMock; + + private AutoCloseable mockCloseable; + + @InjectMocks + private OpenApiSpecification openApiSpecification; + + @BeforeClass + public void beforeClass() throws IOException { + PING_API_STRING = readToString( + new ClasspathResource( + "classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + } + @BeforeMethod + public void setUp() { + + mockCloseable = MockitoAnnotations.openMocks(this); + + testContextMock.setReferenceResolver(referenceResolverMock); + } + + @AfterMethod + public void tearDown() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldInitializeFromSpecUrl() { + + // When + OpenApiSpecification specification = OpenApiSpecification.from(PING_API_HTTP_URL_STRING); + + // Then + assertNotNull(specification); + assertEquals(specification.getSpecUrl(), PING_API_HTTP_URL_STRING); + assertTrue(specification.getRequestValidator().isEmpty()); + assertTrue(specification.getResponseValidator().isEmpty()); + + } + + @DataProvider(name = "protocollDataProvider") + public static Object[][] protocolls() { + return new Object[][] {{PING_API_HTTP_URL_STRING}, {PING_API_HTTPS_URL_STRING}}; + } + + @Test(dataProvider = "protocollDataProvider") + public void shouldInitializeFromUrl(String urlString) throws Exception { + // Given + URL urlMock = mockUrlConnection(urlString); + + // When + OpenApiSpecification specification = OpenApiSpecification.from(urlMock); + + // Then + assertEquals(specification.getSpecUrl(), urlString); + assertPingApi(specification); + } + + private void assertPingApi(OpenApiSpecification specification) { + assertNotNull(specification); + assertTrue(specification.getRequestValidator().isPresent()); + assertTrue(specification.getResponseValidator().isPresent()); + Optional pingOperationPathAdapter = specification.getOperation( + PING_OPERATION_ID, + testContextMock); + assertTrue(pingOperationPathAdapter.isPresent()); + assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); + assertNull(pingOperationPathAdapter.get().contextPath()); + assertEquals(pingOperationPathAdapter.get().fullPath(), "/ping/{id}"); + + Optional pongOperationPathAdapter = specification.getOperation( + PONG_OPERATION_ID, + testContextMock); + assertTrue(pongOperationPathAdapter.isPresent()); + assertEquals(pongOperationPathAdapter.get().apiPath(), "/pong/{id}"); + assertNull(pongOperationPathAdapter.get().contextPath()); + assertEquals(pongOperationPathAdapter.get().fullPath(), "/pong/{id}"); + } + + @Test + public void shouldInitializeFromResource() { + // Given + Resource resource= new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml"); + + // When + OpenApiSpecification specification = OpenApiSpecification.from(resource); + + // Then + assertNotNull(specification); + assertEquals(specification.getSpecUrl(), resource.getLocation()); + assertPingApi(specification); + } + + @Test + public void shouldReturnOpenApiDocWhenInitialized() { + //Given + OpenApiSpecification specification = OpenApiSpecification.from(new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + OasDocument openApiDoc = specification.getOpenApiDoc(testContextMock); + + //When + OpenApiSpecification otherSpecification = new OpenApiSpecification(); + otherSpecification.setOpenApiDoc(openApiDoc); + OasDocument doc = otherSpecification.getOpenApiDoc(testContextMock); + + // Then + assertNotNull(doc); + assertEquals(doc, openApiDoc); + } + + @Test + public void shouldReturnEmptyOptionalWhenOperationIdIsNull() { + // When + Optional result = openApiSpecification.getOperation(null, + testContextMock); + + // Then + assertTrue(result.isEmpty()); + } + + @Test + public void shouldReturnOperationWhenExists() { + // Given/When + OpenApiSpecification specification = OpenApiSpecification.from(new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + + // Then + assertPingApi(specification); + } + + @Test + public void shouldInitializeDocumentWhenRequestingOperation() { + // Given/When + when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(answer-> + answer.getArgument(0) + ); + OpenApiSpecification specification = OpenApiSpecification.from("classpath:org/citrusframework/openapi/ping/ping-api.yaml"); + + // Then + Optional pingOperationPathAdapter = specification.getOperation( + PING_OPERATION_ID, + testContextMock); + assertTrue(pingOperationPathAdapter.isPresent()); + assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); + assertNull(pingOperationPathAdapter.get().contextPath()); + assertEquals(pingOperationPathAdapter.get().fullPath(), "/ping/{id}"); + } + + @DataProvider(name = "lazyInitializationDataprovider") + public static Object[][] specSources() { + return new Object[][]{ + {null, "classpath:org/citrusframework/openapi/ping/ping-api.yaml"}, + {null, PING_API_HTTP_URL_STRING}, + {null, PING_API_HTTPS_URL_STRING}, + {null, "/ping-api.yaml"}, + {"http://org.citrus.sample", "/ping-api.yaml"} + }; + } + + @Test(dataProvider = "lazyInitializationDataprovider") + public void shouldDisableEnableRequestValidationWhenSet(String requestUrl, String specSource) throws IOException { + + // Given + OpenApiSpecification specification = new OpenApiSpecification() { + @Override + URL toSpecUrl(String resolvedSpecUrl) { + return mockUrlConnection(resolvedSpecUrl); + } + }; + specification.setRequestUrl(requestUrl); + specification.setHttpClient("sampleHttpClient"); + specification.setSpecUrl(specSource); + when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(answer-> + answer.getArgument(0) + ); + + when(testContextMock.getReferenceResolver()).thenReturn(referenceResolverMock); + when(referenceResolverMock.isResolvable("sampleHttpClient", HttpClient.class)).thenReturn(true); + when(referenceResolverMock.resolve("sampleHttpClient", HttpClient.class)).thenReturn(httpClient); + when(httpClient.getEndpointConfiguration()).thenReturn(endpointConfigurationMock); + when(endpointConfigurationMock.getRequestUrl()).thenReturn("http://org.citrus.sample"); + + boolean sampleHttpCient = testContextMock.getReferenceResolver() + .isResolvable("sampleHttpClient", HttpClient.class); + + // When + specification.setRequestValidationEnabled(false); + + // Then (not yet initialized) + assertFalse(specification.isRequestValidationEnabled()); + assertFalse(specification.getRequestValidator().isPresent()); + + // When (initialize) + specification.getOpenApiDoc(testContextMock); + + // Then + assertFalse(specification.isRequestValidationEnabled()); + assertTrue(specification.getRequestValidator().isPresent()); + assertTrue(specification.getRequestValidator().isPresent()); + + // When + specification.setRequestValidationEnabled(true); + + // Then + assertTrue(specification.isRequestValidationEnabled()); + assertTrue(specification.getRequestValidator().isPresent()); + assertTrue(specification.getRequestValidator().get().isEnabled()); + + } + + private static URL mockUrlConnection(String urlString) { + try { + HttpsURLConnection httpsURLConnectionMock = mock(); + when(httpsURLConnectionMock.getResponseCode()).thenReturn(200); + when(httpsURLConnectionMock.getInputStream()).thenAnswer( + invocation -> new ByteArrayInputStream(PING_API_STRING.getBytes( + StandardCharsets.UTF_8))); + + URL urlMock = mock(); + when(urlMock.getProtocol()).thenReturn(urlString.substring(0,urlString.indexOf(":"))); + when(urlMock.toString()).thenReturn(urlString); + when(urlMock.openConnection()).thenReturn(httpsURLConnectionMock); + return urlMock; + } catch (Exception e) { + throw new CitrusRuntimeException("Unable to mock spec url!", e); + } + } + + @Test + public void shouldDisableEnableResponseValidationWhenSet() { + // Given + OpenApiSpecification specification = OpenApiSpecification.from(new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + + // When + specification.setResponseValidationEnabled(false); + + // Then + assertFalse(specification.isResponseValidationEnabled()); + assertTrue(specification.getResponseValidator().isPresent()); + assertFalse(specification.getResponseValidator().get().isEnabled()); + + // When + specification.setResponseValidationEnabled(true); + + // Then + assertTrue(specification.isResponseValidationEnabled()); + assertTrue(specification.getResponseValidator().isPresent()); + assertTrue(specification.getResponseValidator().get().isEnabled()); + + } + + @Test + public void shouldAddAlias() { + String alias = "alias1"; + openApiSpecification.addAlias(alias); + + assertTrue(openApiSpecification.getAliases().contains(alias)); + } + + @Test + public void shouldReturnSpecUrl() { + URL url = openApiSpecification.toSpecUrl(PING_API_HTTP_URL_STRING); + + assertNotNull(url); + + assertEquals(url.toString(), PING_API_HTTP_URL_STRING); + } + + @Test + public void shouldSetRootContextPathAndReinitialize() { + // Given/When + OpenApiSpecification specification = OpenApiSpecification.from(new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + + // Then + assertNull(openApiSpecification.getRootContextPath()); + + assertPingApi(specification); + + // When + specification.setRootContextPath("/root"); + + Optional pingOperationPathAdapter = specification.getOperation( + PING_OPERATION_ID, + testContextMock); + assertTrue(pingOperationPathAdapter.isPresent()); + assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); + assertEquals(pingOperationPathAdapter.get().contextPath(), "/root"); + assertEquals(pingOperationPathAdapter.get().fullPath(), "/root/ping/{id}"); + + Optional pongOperationPathAdapter = specification.getOperation( + PONG_OPERATION_ID, + testContextMock); + assertTrue(pongOperationPathAdapter.isPresent()); + assertEquals(pongOperationPathAdapter.get().apiPath(), "/pong/{id}"); + assertEquals(pongOperationPathAdapter.get().contextPath(), "/root"); + assertEquals(pongOperationPathAdapter.get().fullPath(), "/root/pong/{id}"); + + // Verify initPathLookups is called, which would require a spy + } + + @Test + public void shouldSeAndProvideProperties() { + + openApiSpecification.setValidateOptionalFields(true); + openApiSpecification.setGenerateOptionalFields(true); + + assertTrue(openApiSpecification.isValidateOptionalFields()); + assertTrue(openApiSpecification.isGenerateOptionalFields()); + + openApiSpecification.setValidateOptionalFields(false); + openApiSpecification.setGenerateOptionalFields(false); + + assertFalse(openApiSpecification.isValidateOptionalFields()); + assertFalse(openApiSpecification.isGenerateOptionalFields()); + + } + + @Test + public void shouldReturnSpecUrlInAbsenceOfRequestUrl() { + + openApiSpecification.setSpecUrl(PING_API_HTTP_URL_STRING); + + assertEquals(openApiSpecification.getSpecUrl(), PING_API_HTTP_URL_STRING); + assertEquals(openApiSpecification.getRequestUrl(), PING_API_HTTP_URL_STRING); + + openApiSpecification.setSpecUrl("/ping-api.yaml"); + openApiSpecification.setRequestUrl("http://or.citrus.sample"); + + assertEquals(openApiSpecification.getSpecUrl(), "/ping-api.yaml"); + assertEquals(openApiSpecification.getRequestUrl(), "http://or.citrus.sample"); + + } + +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java new file mode 100644 index 0000000000..89d19ac670 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -0,0 +1,49 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.Map; +import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.spi.Resources; +import org.testng.Assert; +import org.testng.annotations.Test; + +// TODO: Add more tests +public class OpenApiTestDataGeneratorTest { + + private final OpenApiSpecification pingSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + + // TODO: fix this by introducing mature validation + @Test + public void failsToValidateAnyOf() throws JsonProcessingException { + + Map schemaDefinitions = OasModelHelper.getSchemaDefinitions( + pingSpec.getOpenApiDoc(null)); + assertNotNull(schemaDefinitions); + assertFalse(schemaDefinitions.isEmpty()); + Assert.assertEquals(schemaDefinitions.size(), 15); + + Assert.assertThrows(() -> OpenApiTestDataGenerator.createValidationExpression( + schemaDefinitions.get("PingRespType"), schemaDefinitions, true, pingSpec)); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java new file mode 100644 index 0000000000..2c411b1179 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java @@ -0,0 +1,80 @@ +package org.citrusframework.openapi; + +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageHeaders; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; + +public class OpenApiUtilsTest { + + @Mock + private HttpMessage httpMessageMock; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void beforeMethod() { + mockCloseable = MockitoAnnotations.openMocks(this); + } + + @AfterMethod + public void afterMethod() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldReturnFormattedMethodPathWhenHttpMessageHasMethodAndPath() { + // Given + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD)).thenReturn("GET"); + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/path"); + + // When + String methodPath = OpenApiUtils.getMethodPath(httpMessageMock); + + // Then + assertEquals(methodPath, "/get/api/path"); + } + + @Test + public void shouldReturnDefaultMethodPathWhenHttpMessageHasNoMethodAndPath() { + // Given + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD)).thenReturn(null); + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn(null); + + // When + String methodPath = OpenApiUtils.getMethodPath(httpMessageMock); + + // Then + assertEquals(methodPath, "/null/null"); + } + + @Test + public void shouldReturnFormattedMethodPathWhenMethodAndPathAreProvided() { + // When + String methodPath = OpenApiUtils.getMethodPath("POST", "/api/path"); + // Then + assertEquals(methodPath, "/post/api/path"); + } + + @Test + public void shouldReturnFormattedMethodPathWhenMethodIsEmptyAndPathIsProvided() { + // When + String methodPath = OpenApiUtils.getMethodPath("", "/api/path"); + // Then + assertEquals(methodPath, "//api/path"); + } + + @Test + public void shouldReturnFormattedMethodPathWhenMethodAndPathAreEmpty() { + // When + String methodPath = OpenApiUtils.getMethodPath("", ""); + // Then + assertEquals(methodPath, "//"); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java index 151687da4d..6a1ad5bb02 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java @@ -47,6 +47,9 @@ import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; public class OpenApiServerTest extends AbstractGroovyActionDslTest { @@ -111,89 +114,90 @@ public void shouldLoadOpenApiServerActions() { testLoader.load(); TestCase result = testLoader.getTestCase(); - Assert.assertEquals(result.getName(), "OpenApiServerTest"); - Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); - Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); - Assert.assertEquals(result.getActionCount(), 4L); - Assert.assertEquals(result.getTestAction(0).getClass(), ReceiveMessageAction.class); - Assert.assertEquals(result.getTestAction(0).getName(), "openapi:receive-request"); + assertEquals(result.getName(), "OpenApiServerTest"); + assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + assertEquals(result.getActionCount(), 4L); + assertEquals(result.getTestAction(0).getClass(), ReceiveMessageAction.class); + assertEquals(result.getTestAction(0).getName(), "openapi:receive-request"); - Assert.assertEquals(result.getTestAction(1).getClass(), SendMessageAction.class); - Assert.assertEquals(result.getTestAction(1).getName(), "openapi:send-response"); + assertEquals(result.getTestAction(1).getClass(), SendMessageAction.class); + assertEquals(result.getTestAction(1).getName(), "openapi:send-response"); int actionIndex = 0; ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); - Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); + assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); - Assert.assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); + assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet/${petId}"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet/${petId}"); + assertNotNull(httpMessageBuilder); + assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); + assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet/${petId}"); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet/${petId}"); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); - Assert.assertEquals(receiveMessageAction.getEndpoint(), httpServer); - Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); + assertEquals(receiveMessageAction.getEndpoint(), httpServer); + assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - - Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); + assertNotNull(httpMessageBuilder); + + assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); + assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertNull(sendMessageAction.getEndpoint()); - Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); - Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 0); + assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); + assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); - Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); + assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), + assertNotNull(httpMessageBuilder); + assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Map requestHeaders = httpMessageBuilder.buildMessageHeaders(context); - Assert.assertEquals(requestHeaders.size(), 4L); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); - Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "@startsWith(application/json)@"); + assertEquals(requestHeaders.size(), 4L); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); + assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet"); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet"); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "@startsWith(application/json)@"); Assert.assertNull(receiveMessageAction.getEndpointUri()); - Assert.assertEquals(receiveMessageAction.getEndpoint(), httpServer); + assertEquals(receiveMessageAction.getEndpoint(), httpServer); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex); httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertNotNull(httpMessageBuilder); + assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Map responseHeaders = httpMessageBuilder.buildMessageHeaders(context); - Assert.assertEquals(responseHeaders.size(), 2L); - Assert.assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_STATUS_CODE), 201); - Assert.assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_REASON_PHRASE), "CREATED"); + assertEquals(responseHeaders.size(), 2L); + assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_STATUS_CODE), 201); + assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_REASON_PHRASE), "CREATED"); Assert.assertNull(sendMessageAction.getEndpoint()); - Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); + assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index 2c7e8b8f49..42aadd18d8 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -17,11 +17,15 @@ package org.citrusframework.openapi.integration; import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.exceptions.TestCaseFailedException; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiActionBuilder; +import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; @@ -31,10 +35,15 @@ import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.fail; @Test public class OpenApiClientIT extends TestNGCitrusSpringSupport { + public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; + public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; + private final int port = SocketUtils.findAvailableTcpPort(8080); @BindToRegistry @@ -50,14 +59,23 @@ public class OpenApiClientIT extends TestNGCitrusSpringSupport { .requestUrl("http://localhost:%d".formatted(port)) .build(); + /** + * Directly loaded open api. + */ private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); @CitrusTest - public void getPetById() { + @Test + public void shouldExecuteGetPetByIdFromDirectSpec() { + shouldExecuteGetPetById(openapi(petstoreSpec), VALID_PET_PATH, true); + } + + private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String responseFile, boolean valid) { + variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi .client(httpClient) .send("getPetById") .fork(true)); @@ -72,19 +90,87 @@ public void getPetById() { .send() .response(HttpStatus.OK) .message() - .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) + .body(Resources.create(responseFile)) .contentType("application/json")); - then(openapi(petstoreSpec) - .client(httpClient) - .receive("getPetById", HttpStatus.OK)); + OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi + .client(httpClient).receive("getPetById", HttpStatus.OK); + if (valid) { + then(clientResponseActionBuilder); + } else { + assertThrows(() -> then(clientResponseActionBuilder)); + } + } + + @CitrusTest + @Test + public void shouldProperlyExecuteGetAndAddPetFromDirectSpec() { + shouldExecuteGetAndAddPet(openapi(petstoreSpec)); + } + + @CitrusTest + @Test + public void shouldProperlyExecuteGetAndAddPetFromRepository() { + shouldExecuteGetAndAddPet(openapi(petstoreSpec)); + } + + @CitrusTest + @Test + public void shouldFailOnMissingNameInResponse() { + shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, false); } @CitrusTest - public void getAddPet() { + @Test + public void shouldFailOnMissingNameInRequest() { + variable("petId", "1001"); + + HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + .client(httpClient) + .send("addPet") + .message().body(Resources.create(INVALID_PET_PATH)) + .fork(true); + + assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); + } + + @CitrusTest + @Test + public void shouldFailOnWrongQueryIdType() { + variable("petId", "xxxx"); + HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + .client(httpClient) + .send("addPet") + .message().body(Resources.create(VALID_PET_PATH)) + .fork(true); + + assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); + } + + @CitrusTest + @Test + public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { + variable("petId", "xxxx"); + HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + .client(httpClient) + .send("addPet") + .disableOasValidation(true) + .message().body(Resources.create(VALID_PET_PATH)) + .fork(true); + + try { + when(addPetBuilder); + } catch (Exception e) { + fail("Method threw an exception: " + e.getMessage()); + } + + } + + private void shouldExecuteGetAndAddPet(OpenApiActionBuilder openapi) { + variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi .client(httpClient) .send("addPet") .fork(true)); @@ -113,7 +199,7 @@ public void getAddPet() { .response(HttpStatus.CREATED) .message()); - then(openapi(petstoreSpec) + then(openapi .client(httpClient) .receive("addPet", HttpStatus.CREATED)); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 0d2c7bcc05..03bca16cd3 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -17,11 +17,15 @@ package org.citrusframework.openapi.integration; import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.exceptions.TestCaseFailedException; import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiActionBuilder; +import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; +import org.citrusframework.openapi.actions.OpenApiServerResponseActionBuilder; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; @@ -31,10 +35,15 @@ import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.fail; @Test public class OpenApiServerIT extends TestNGCitrusSpringSupport { + public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; + public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; + private final int port = SocketUtils.findAvailableTcpPort(8080); @BindToRegistry @@ -50,11 +59,19 @@ public class OpenApiServerIT extends TestNGCitrusSpringSupport { .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) .build(); + /** + * Directly loaded open api. + */ private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); @CitrusTest - public void getPetById() { + public void shouldExecuteGetPetById() { + shouldExecuteGetPetById(openapi(petstoreSpec)); + } + + + private void shouldExecuteGetPetById(OpenApiActionBuilder openapi) { variable("petId", "1001"); when(http() @@ -65,11 +82,11 @@ public void getPetById() { .accept("application/json") .fork(true)); - then(openapi(petstoreSpec) + then(openapi .server(httpServer) .receive("getPetById")); - then(openapi(petstoreSpec) + then(openapi .server(httpServer) .send("getPetById", HttpStatus.OK)); @@ -94,7 +111,86 @@ public void getPetById() { } @CitrusTest - public void getAddPet() { + public void shouldExecuteAddPet() { + shouldExecuteAddPet(openapi(petstoreSpec), VALID_PET_PATH, true); + } + + @CitrusTest + public void shouldFailOnMissingNameInRequest() { + shouldExecuteAddPet(openapi(petstoreSpec), INVALID_PET_PATH, false); + } + + @CitrusTest + public void shouldFailOnMissingNameInResponse() { + variable("petId", "1001"); + + when(http() + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept("application/json") + .fork(true)); + + then(openapi(petstoreSpec) + .server(httpServer) + .receive("getPetById")); + + OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi(petstoreSpec) + .server(httpServer) + .send("getPetById", HttpStatus.OK); + sendMessageActionBuilder.message().body(Resources.create(INVALID_PET_PATH)); + + assertThrows(TestCaseFailedException.class, () -> then(sendMessageActionBuilder)); + + } + + @CitrusTest + public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { + variable("petId", "xxx"); + + when(http() + .client(httpClient) + .send() + .post("/pet") + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType("application/json") + .fork(true)); + + OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) + .server(httpServer) + .receive("addPet"); + + assertThrows(TestCaseFailedException.class, () -> then(addPetBuilder)); + } + + @CitrusTest + public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { + variable("petId", "xxx"); + + when(http() + .client(httpClient) + .send() + .post("/pet") + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType("application/json") + .fork(true)); + + OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) + .server(httpServer) + .receive("addPet") + .disableOasValidation(true); + + try { + when(addPetBuilder); + } catch (Exception e) { + fail("Method threw an exception: " + e.getMessage()); + } + } + + private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFile, boolean valid) { variable("petId", "1001"); when(http() @@ -102,15 +198,20 @@ public void getAddPet() { .send() .post("/pet") .message() - .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) + .body(Resources.create(requestFile)) .contentType("application/json") .fork(true)); - then(openapi(petstoreSpec) - .server(httpServer) - .receive("addPet")); + OpenApiServerRequestActionBuilder receiveActionBuilder = openapi + .server(httpServer) + .receive("addPet"); + if (valid) { + then(receiveActionBuilder); + } else { + assertThrows(() -> then(receiveActionBuilder)); + } - then(openapi(petstoreSpec) + then(openapi .server(httpServer) .send("addPet", HttpStatus.CREATED)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java new file mode 100644 index 0000000000..cec2e46744 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java @@ -0,0 +1,34 @@ +package org.citrusframework.openapi.model; + +import io.apicurio.datamodels.openapi.models.OasOperation; +import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; +import org.citrusframework.openapi.OpenApiUtils; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static java.lang.String.format; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; + +public class OperationPathAdapterTest { + + + @Test + public void shouldReturnFormattedStringWhenToStringIsCalled() { + // Given + Oas30Operation oas30Operation = new Oas30Operation("get"); + oas30Operation.operationId = "operationId"; + + OperationPathAdapter adapter = new OperationPathAdapter("/api/path", "/context/path", "/full/path", oas30Operation); + + // When + String expectedString = format("%s (%s)", OpenApiUtils.getMethodPath("GET", "/api/path"), "operationId"); + + // Then + assertEquals(adapter.toString(), expectedString); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java index 742641ad6c..f57d3c46ce 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java @@ -14,12 +14,13 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import java.util.List; import java.util.Optional; +import org.citrusframework.openapi.model.OasModelHelper; import org.testng.annotations.Test; public class Oas20ModelHelperTest { @Test - public void shouldFindRandomResponse() { + public void shouldFindRandomResponseWithGoodStatusCode() { Oas20Document document = new Oas20Document(); Oas20Operation operation = new Oas20Operation("GET"); @@ -35,29 +36,55 @@ public void shouldFindRandomResponse() { operation.responses.addResponse("403", nokResponse); operation.responses.addResponse("200", okResponse); - Optional responseForRandomGeneration = Oas20ModelHelper.getResponseForRandomGeneration( - document, operation); + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(okResponse, responseForRandomGeneration.get()); } @Test - public void shouldNotFindAnyResponse() { + public void shouldFindFirstResponseInAbsenceOfAGoodOne() { Oas20Document document = new Oas20Document(); Oas20Operation operation = new Oas20Operation("GET"); operation.responses = new Oas20Responses(); Oas20Response nokResponse403 = new Oas20Response("403"); + nokResponse403.schema = new Oas20Schema(); Oas20Response nokResponse407 = new Oas20Response("407"); + nokResponse407.schema = new Oas20Schema(); operation.responses = new Oas20Responses(); operation.responses.addResponse("403", nokResponse403); operation.responses.addResponse("407", nokResponse407); - Optional responseForRandomGeneration = Oas20ModelHelper.getResponseForRandomGeneration( - document, operation); - assertTrue(responseForRandomGeneration.isEmpty()); + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(responseForRandomGeneration.get().getStatusCode(), "403"); + } + + @Test + public void shouldFindDefaultResponseInAbsenceOfAGoodOne() { + Oas20Document document = new Oas20Document(); + Oas20Operation operation = new Oas20Operation("GET"); + + operation.responses = new Oas20Responses(); + + Oas20Response nokResponse403 = new Oas20Response("403"); + nokResponse403.schema = new Oas20Schema(); + Oas20Response nokResponse407 = new Oas20Response("407"); + nokResponse407.schema = new Oas20Schema(); + + operation.responses = new Oas20Responses(); + operation.responses.default_ = nokResponse407; + operation.responses.addResponse("403", nokResponse403); + operation.responses.addResponse("407", nokResponse407); + + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(responseForRandomGeneration.get().getStatusCode(), "407"); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java index 8735ecd083..9feee74a1a 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java @@ -17,6 +17,7 @@ import java.util.Collection; import java.util.Map; import java.util.Optional; +import org.citrusframework.openapi.model.OasModelHelper; import org.springframework.http.MediaType; import org.testng.annotations.Test; @@ -26,7 +27,7 @@ public class Oas30ModelHelperTest { public void shouldNotFindRequiredHeadersWithoutRequiredAttribute() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = null; // explicitly assigned because this is test case + header.required = null; var response = new Oas30Response("200"); response.headers.put(header.getName(), header); @@ -39,7 +40,7 @@ public void shouldNotFindRequiredHeadersWithoutRequiredAttribute() { public void shouldFindRequiredHeaders() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = Boolean.TRUE; // explicitly assigned because this is test case + header.required = Boolean.TRUE; var response = new Oas30Response("200"); response.headers.put(header.getName(), header); @@ -53,7 +54,7 @@ public void shouldFindRequiredHeaders() { public void shouldNotFindOptionalHeaders() { var header = new Oas30Header("X-TEST"); header.schema = new Oas30Schema(); - header.required = Boolean.FALSE; // explicitly assigned because this is test case + header.required = Boolean.FALSE; var response = new Oas30Response("200"); response.headers.put(header.getName(), header); @@ -83,7 +84,7 @@ public void shouldFindAllRequestTypesForOperation() { } @Test - public void shouldFindRandomResponse() { + public void shouldFindRandomResponseWithGoodStatusCode() { Oas30Document document = new Oas30Document(); Oas30Operation operation = new Oas30Operation("GET"); @@ -108,14 +109,14 @@ public void shouldFindRandomResponse() { operation.responses.addResponse("403", nokResponse); operation.responses.addResponse("200", okResponse); - Optional responseForRandomGeneration = Oas30ModelHelper.getResponseForRandomGeneration( - document, operation); + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(okResponse, responseForRandomGeneration.get()); } @Test - public void shouldFindAnyResponse() { + public void shouldFindFirstResponseInAbsenceOfAGoodOne() { Oas30Document document = new Oas30Document(); Oas30Operation operation = new Oas30Operation("GET"); @@ -133,10 +134,37 @@ public void shouldFindAnyResponse() { operation.responses.addResponse("403", nokResponse403); operation.responses.addResponse("407", nokResponse407); - Optional responseForRandomGeneration = Oas30ModelHelper.getResponseForRandomGeneration( - document, operation); + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); - assertEquals(nokResponse403, responseForRandomGeneration.get()); + assertEquals(responseForRandomGeneration.get().getStatusCode(), "403"); + + } + + @Test + public void shouldFindDefaultResponseInAbsenceOfAGoodOne() { + Oas30Document document = new Oas30Document(); + Oas30Operation operation = new Oas30Operation("GET"); + + operation.responses = new Oas30Responses(); + + Oas30Response nokResponse403 = new Oas30Response("403"); + Oas30MediaType plainTextMediaType = new Oas30MediaType(MediaType.TEXT_PLAIN_VALUE); + plainTextMediaType.schema = new Oas30Schema(); + nokResponse403.content = Map.of(MediaType.TEXT_PLAIN_VALUE, plainTextMediaType); + + Oas30Response nokResponse407 = new Oas30Response("407"); + nokResponse407.content = Map.of(MediaType.TEXT_PLAIN_VALUE, plainTextMediaType); + + operation.responses = new Oas30Responses(); + operation.responses.default_ = nokResponse407; + operation.responses.addResponse("403", nokResponse403); + operation.responses.addResponse("407", nokResponse407); + + Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( + document, operation, null, null); + assertTrue(responseForRandomGeneration.isPresent()); + assertEquals(responseForRandomGeneration.get().getStatusCode(), "407"); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java new file mode 100644 index 0000000000..fc72cd5ade --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java @@ -0,0 +1,118 @@ +package org.citrusframework.openapi.validation; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Optional; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class OpenApiRequestValidationProcessorTest { + + @Mock + private OpenApiSpecification openApiSpecificationMock; + + @Mock + private OpenApiRequestValidator requestValidatorMock; + + @Mock + private OperationPathAdapter operationPathAdapterMock; + + @InjectMocks + private OpenApiRequestValidationProcessor processor; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void beforeMethod() { + mockCloseable = MockitoAnnotations.openMocks(this); + processor = new OpenApiRequestValidationProcessor(openApiSpecificationMock, "operationId"); + } + + @AfterMethod + public void afterMethod() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldNotValidateWhenDisabled() { + processor.setEnabled(false); + HttpMessage messageMock = mock(); + + processor.validate(messageMock, mock()); + + verify(openApiSpecificationMock, never()).getOperation(any(), any()); + } + + @Test + public void shouldNotValidateNonHttpMessage() { + Message messageMock = mock(); + + processor.validate(messageMock, mock()); + + verify(openApiSpecificationMock, never()).getOperation(any(), any()); + } + + @Test + public void shouldValidateHttpMessage() { + processor.setEnabled(true); + HttpMessage httpMessageMock = mock(); + TestContext contextMock = mock(); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.of(operationPathAdapterMock)); + when(openApiSpecificationMock.getRequestValidator()) + .thenReturn(Optional.of(requestValidatorMock)); + + processor.validate(httpMessageMock, contextMock); + + verify(requestValidatorMock, times(1)).validateRequest(operationPathAdapterMock, httpMessageMock); + } + + @Test + public void shouldNotValidateWhenNoOperation() { + processor.setEnabled(true); + HttpMessage httpMessage = mock(HttpMessage.class); + TestContext context = mock(TestContext.class); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.empty()); + + processor.validate(httpMessage, context); + + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); + verify(openApiSpecificationMock, never()).getRequestValidator(); + } + + @Test + public void shouldNotValidateWhenNoValidator() { + processor.setEnabled(true); + HttpMessage httpMessage = mock(HttpMessage.class); + TestContext context = mock(TestContext.class); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.of(operationPathAdapterMock)); + when(openApiSpecificationMock.getRequestValidator()) + .thenReturn(Optional.empty()); + + processor.validate(httpMessage, context); + + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); + verify(openApiSpecificationMock, times(1)).getRequestValidator(); + verify(requestValidatorMock, never()).validateRequest(any(), any()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java new file mode 100644 index 0000000000..d1decc05a3 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -0,0 +1,148 @@ +package org.citrusframework.openapi.validation; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.model.Request; +import com.atlassian.oai.validator.model.Request.Method; +import com.atlassian.oai.validator.report.ValidationReport; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.validation.OpenApiRequestValidator; +import org.mockito.*; +import org.springframework.web.bind.annotation.RequestMethod; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; + +public class OpenApiRequestValidatorTest { + + @Mock + private OpenApiInteractionValidator openApiInteractionValidatorMock; + + @Mock + private OperationPathAdapter operationPathAdapterMock; + + @Mock + private HttpMessage httpMessageMock; + + @Mock + private ValidationReport validationReportMock; + + @InjectMocks + private OpenApiRequestValidator openApiRequestValidator; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void beforeMethod() { + mockCloseable = MockitoAnnotations.openMocks(this); + openApiRequestValidator = new OpenApiRequestValidator(openApiInteractionValidatorMock); + } + + @AfterMethod + public void afterMethod() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldNotValidateWhenDisabled() { + // Given + openApiRequestValidator.setEnabled(false); + // When + openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); + // Then + Assert.assertFalse(openApiRequestValidator.isEnabled()); + verify(openApiInteractionValidatorMock, never()).validateRequest(any(Request.class)); + } + + @Test + public void shouldValidateRequestWithNoErrors() { + // Given + openApiRequestValidator.setEnabled(true); + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); + when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) + .thenReturn(validationReportMock); + when(validationReportMock.hasErrors()).thenReturn(false); + + // When + openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); + + // Then + verify(openApiInteractionValidatorMock, times(1)).validateRequest(any(Request.class)); + verify(validationReportMock, times(1)).hasErrors(); + } + + @Test(expectedExceptions = ValidationException.class) + public void shouldValidateRequestWithErrors() { + // Given + openApiRequestValidator.setEnabled(true); + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); + when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) + .thenReturn(validationReportMock); + when(validationReportMock.hasErrors()).thenReturn(true); + + // When + openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); + + // Then + verify(openApiInteractionValidatorMock, times(1)).validateRequest(any(Request.class)); + verify(validationReportMock, times(1)).hasErrors(); + } + + @Test + public void shouldCreateRequestFromMessage() throws IOException { + // Given + when(httpMessageMock.getPayload()).thenReturn("payload"); + + Map headers = new HashMap<>(); + headers.put("array", List.of("e1", "e2")); + headers.put("nullarray", null); + headers.put("simple", "s1"); + + when(httpMessageMock.getHeaders()).thenReturn(headers); + when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); + when(httpMessageMock.getAccept()).thenReturn("application/json"); + when(operationPathAdapterMock.contextPath()).thenReturn("/api"); + + // When + Request request = openApiRequestValidator.createRequestFromMessage(operationPathAdapterMock, httpMessageMock); + + // Then + assertNotNull(request); + assertEquals(request.getPath(), "/test"); + assertEquals(request.getMethod(), Method.GET); + assertEquals(request.getHeaders().get("array"), List.of("e1", "e2")); + assertEquals(request.getHeaders().get("simple"), List.of("s1")); + List nullList = new ArrayList<>(); + nullList.add(null); + assertEquals(request.getHeaders().get("nullarray"), nullList); + assertTrue(request.getRequestBody().isPresent()); + + assertEquals(request.getRequestBody().get().toString(StandardCharsets.UTF_8), "payload"); + } + + private Request callCreateRequestFromMessage(OpenApiRequestValidator validator, OperationPathAdapter adapter, HttpMessage message) { + try { + var method = OpenApiRequestValidator.class.getDeclaredMethod("createRequestFromMessage", OperationPathAdapter.class, HttpMessage.class); + method.setAccessible(true); + return (Request) method.invoke(validator, adapter, message); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java new file mode 100644 index 0000000000..a7aabba892 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java @@ -0,0 +1,114 @@ +package org.citrusframework.openapi.validation; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +public class OpenApiResponseValidationProcessorTest { + + @Mock + private OpenApiSpecification openApiSpecificationMock; + + @Mock + private OpenApiResponseValidator responseValidatorMock; + + @Mock + private OperationPathAdapter operationPathAdapterMock; + + @InjectMocks + private OpenApiResponseValidationProcessor processor; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void beforeMethod() { + mockCloseable = MockitoAnnotations.openMocks(this); + processor = new OpenApiResponseValidationProcessor(openApiSpecificationMock, "operationId"); + } + + @AfterMethod + public void afterMethod() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldNotValidateWhenDisabled() { + processor.setEnabled(false); + HttpMessage messageMock = mock(); + + processor.validate(messageMock, mock()); + + verify(openApiSpecificationMock, never()).getOperation(any(), any()); + } + + @Test + public void shouldNotValidateNonHttpMessage() { + Message messageMock = mock(); + + processor.validate(messageMock, mock()); + + verify(openApiSpecificationMock, never()).getOperation(any(), any()); + } + + @Test + public void shouldValidateHttpMessage() { + processor.setEnabled(true); + HttpMessage httpMessageMock = mock(); + TestContext contextMock = mock(); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.of(operationPathAdapterMock)); + when(openApiSpecificationMock.getResponseValidator()) + .thenReturn(Optional.of(responseValidatorMock)); + + processor.validate(httpMessageMock, contextMock); + + verify(responseValidatorMock, times(1)).validateResponse(operationPathAdapterMock, httpMessageMock); + } + + @Test + public void shouldNotValidateWhenNoOperation() { + processor.setEnabled(true); + HttpMessage httpMessage = mock(HttpMessage.class); + TestContext context = mock(TestContext.class); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.empty()); + + processor.validate(httpMessage, context); + + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); + verify(openApiSpecificationMock, never()).getResponseValidator(); + } + + @Test + public void shouldNotValidateWhenNoValidator() { + processor.setEnabled(true); + HttpMessage httpMessage = mock(HttpMessage.class); + TestContext context = mock(TestContext.class); + + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) + .thenReturn(Optional.of(operationPathAdapterMock)); + when(openApiSpecificationMock.getResponseValidator()) + .thenReturn(Optional.empty()); + + processor.validate(httpMessage, context); + + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); + verify(openApiSpecificationMock, times(1)).getResponseValidator(); + verify(responseValidatorMock, never()).validateResponse(any(), any()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java new file mode 100644 index 0000000000..d8d4433447 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -0,0 +1,128 @@ +package org.citrusframework.openapi.validation; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.model.Request.Method; +import com.atlassian.oai.validator.model.Response; +import com.atlassian.oai.validator.report.ValidationReport; +import io.apicurio.datamodels.core.models.common.Operation; +import io.apicurio.datamodels.openapi.models.OasOperation; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.mockito.*; +import org.springframework.http.HttpStatusCode; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; + +public class OpenApiResponseValidatorTest { + + @Mock + private OpenApiInteractionValidator openApiInteractionValidatorMock; + + @Mock + private OasOperation operationMock; + + @Mock + private OperationPathAdapter operationPathAdapterMock; + + @Mock + private HttpMessage httpMessageMock; + + @Mock + private ValidationReport validationReportMock; + + @InjectMocks + private OpenApiResponseValidator openApiResponseValidator; + + private AutoCloseable mockCloseable; + + @BeforeMethod + public void beforeMethod() { + mockCloseable = MockitoAnnotations.openMocks(this); + openApiResponseValidator = new OpenApiResponseValidator(openApiInteractionValidatorMock); + } + + @AfterMethod + public void afterMethod() throws Exception { + mockCloseable.close(); + } + + @Test + public void shouldNotValidateWhenDisabled() { + // Given + openApiResponseValidator.setEnabled(false); + // When + openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); + // Then + Assert.assertFalse(openApiResponseValidator.isEnabled()); + verify(openApiInteractionValidatorMock, never()).validateResponse(anyString(), any(Method.class), any(Response.class)); + } + + @Test + public void shouldValidateWithNoErrors() { + // Given + openApiResponseValidator.setEnabled(true); + when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) + .thenReturn(validationReportMock); + when(validationReportMock.hasErrors()).thenReturn(false); + + when(operationPathAdapterMock.operation()).thenReturn(operationMock); + when(operationPathAdapterMock.apiPath()).thenReturn("/api/path"); + when(operationMock.getMethod()).thenReturn("get"); + when(httpMessageMock.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); + + // When + openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); + + // Then + verify(openApiInteractionValidatorMock, times(1)).validateResponse(anyString(), any(Method.class), any(Response.class)); + verify(validationReportMock, times(1)).hasErrors(); + } + + @Test(expectedExceptions = ValidationException.class) + public void shouldValidateWithErrors() { + // Given + openApiResponseValidator.setEnabled(true); + when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) + .thenReturn(validationReportMock); + when(validationReportMock.hasErrors()).thenReturn(true); + + when(operationPathAdapterMock.operation()).thenReturn(operationMock); + when(operationPathAdapterMock.apiPath()).thenReturn("/api/path"); + when(operationMock.getMethod()).thenReturn("get"); + when(httpMessageMock.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); + + // When + openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); + + // Then + verify(openApiInteractionValidatorMock, times(1)).validateResponse(anyString(), any(Method.class), any(Response.class)); + verify(validationReportMock, times(1)).hasErrors(); + } + + @Test + public void shouldCreateResponseMessage() throws IOException { + // Given + when(httpMessageMock.getPayload()).thenReturn("payload"); + when(httpMessageMock.getHeaders()).thenReturn(Map.of("Content-Type", "application/json")); + when(httpMessageMock.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); + + // When + Response response = openApiResponseValidator.createResponseFromMessage(httpMessageMock, 200); + + // Then + assertNotNull(response); + assertEquals(response.getResponseBody().get().toString(StandardCharsets.UTF_8), "payload"); + assertEquals(response.getHeaderValue("Content-Type").get(), "application/json"); + assertEquals(response.getStatus(), Integer.valueOf(200)); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index 101e604c6e..69805ac452 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -124,7 +124,9 @@ public void shouldLoadOpenApiClientActions() throws IOException { context.getReferenceResolver().bind("httpClient", httpClient); context.getReferenceResolver().bind("httpServer", httpServer); - responses.add(new HttpMessage(FileUtils.readToString(Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.yaml")))); + String apiAsString = FileUtils.readToString(Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.yaml")); + responses.add(new HttpMessage(apiAsString)); + responses.add(new HttpMessage(apiAsString)); responses.add(new HttpMessage(""" { "id": 1000, diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java index 4f49613c96..9e9a832291 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java @@ -156,9 +156,10 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); - Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 0); + Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java index d8dac9eb1d..2171fac921 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java @@ -156,9 +156,10 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); - Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 0); + Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/pet_invalid.json b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/pet_invalid.json new file mode 100644 index 0000000000..c265dff5be --- /dev/null +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/pet_invalid.json @@ -0,0 +1,15 @@ +{ + "id": ${petId}, + "category": { + "id": ${petId}, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ "http://localhost:8080/photos/${petId}" ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" +} diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml new file mode 100644 index 0000000000..f5e8f95b1a --- /dev/null +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml @@ -0,0 +1,244 @@ +openapi: 3.0.1 +info: + title: Ping API + description: 'A simple OpenApi defining schemas for testing purposes' + version: 1.0 + +servers: + - url: http://localhost:9000/services/rest/ping/v1 + - url: http://localhost:9000/ping/v1 + +paths: + /ping/{id}: + put: + tags: + - ping + summary: Do the ping + operationId: doPing + parameters: + - name: id + in: path + description: Id to ping + required: true + schema: + type: integer + format: int64 + - name: q1 + in: query + description: Some queryParameter + required: true + schema: + type: integer + format: int64 + - name: api-key + in: header + description: Some header + required: true + schema: + type: string + requestBody: + description: Ping data + content: + application/json: + schema: + $ref: '#/components/schemas/PingReqType' + required: true + responses: + 200: + description: successful operation + headers: + ping-time: + required: false + description: response time + schema: + type: integer + format: int64 + content: + application/json: + schema: + $ref: '#/components/schemas/PingRespType' + plain/text: + schema: + type: string + 405: + description: Some error + content: + text/plain: + schema: + type: string + /pong/{id}: + get: + tags: + - pong + summary: Do the pong + operationId: doPong + parameters: + - name: id + in: path + description: Id to pong + required: true + explode: true + schema: + type: integer + format: int64 + responses: + 200: + description: successful operation without a response +components: + schemas: + Ipv6Type: + required: + - ipv6 + type: object + properties: + ipv6: + type: string + format: ipv6 + Ipv4Type: + required: + - ipv4 + type: object + properties: + ipv4: + type: string + format: ipv4 + DateType: + required: + - date + type: object + properties: + date: + type: string + format: date + DateTimeType: + required: + - dateTime + type: object + properties: + dateTime: + type: string + format: date-time + EmailType: + required: + - email + type: object + properties: + email: + type: string + format: email + ByteType: + required: + - byte + type: object + properties: + byte: + type: string + format: byte + BinaryType: + required: + - binary + type: object + properties: + binary: + type: string + format: binary + UriType: + required: + - uri + type: object + properties: + uri: + type: string + format: uri + UriReferenceType: + required: + - uriReference + type: object + properties: + uriReference: + type: string + format: uri-refence + HostnameType: + required: + - hostname + type: object + properties: + hostname: + type: string + format: hostname + AllTypes: + required: + - email + - ipv6 + - ipv4 + - date + - dateTime + - binary + - byte + - uri + - uriReference + - hostname + type: object + properties: + ipv6: + type: string + format: ipv6 + ipv4: + type: string + format: ipv4 + date: + type: string + format: date + dateTime: + type: string + format: date-time + email: + type: string + format: email + binary: + type: string + format: binary + byte: + type: string + format: byte + uri: + type: string + format: uri + uriReference: + type: string + format: uri-reference + hostname: + type: string + format: hostname + PingReqType: + type: object + properties: + id: + type: integer + format: int64 + Detail1: + type: object + properties: + host: + $ref: '#/components/schemas/HostnameType' + uri: + $ref: '#/components/schemas/UriType' + Detail2: + type: object + properties: + ipv4: + $ref: '#/components/schemas/Ipv4Type' + uriReference: + $ref: '#/components/schemas/UriReferenceType' + PingRespType: + type: object + properties: + id: + type: integer + format: int64 + value: + type: string + other: + anyOf: + - $ref: '#/components/schemas/Detail1' + - $ref: '#/components/schemas/Detail2' diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java index cdb38f5ee0..0b56ce8c7c 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java @@ -67,6 +67,7 @@ public DefaultMessage() { * @param message */ public DefaultMessage(Message message) { + this(message.getPayload(), message.getHeaders()); this.setName(message.getName()); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 33b94a02ef..3fbc64c812 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -21,6 +21,8 @@ */ public class StringUtils { + public static final String URL_PATH_SEPARATOR = "/"; + private StringUtils() { //prevent instantiation of utility class } @@ -39,7 +41,7 @@ public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } - public static String appendSegmentToPath(String path, String segment) { + public static String appendSegmentToUrlPath(String path, String segment) { if (path == null) { return segment; @@ -49,14 +51,14 @@ public static String appendSegmentToPath(String path, String segment) { return path; } - if (!path.endsWith("/")) { - path = path +"/"; + if (!path.endsWith(URL_PATH_SEPARATOR)) { + path = path + URL_PATH_SEPARATOR; } - if (segment.startsWith("/")) { + if (segment.startsWith(URL_PATH_SEPARATOR)) { segment = segment.substring(1); } - return path+segment; + return path + segment; } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java index 345d9ee2d8..9add503998 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java @@ -368,7 +368,11 @@ public String getContentType() { * @return The accept header value */ public String getAccept() { - final Object accept = getHeader("Accept"); + Object accept = getHeader("Accept"); + + if (accept == null) { + accept = getHeader("accept"); + } if (accept != null) { return accept.toString(); diff --git a/pom.xml b/pom.xml index 5b51a4e602..c007ae01ac 100644 --- a/pom.xml +++ b/pom.xml @@ -192,6 +192,7 @@ 1.10.15 4.9.0 1.1.27 + com.atlassian.oai 1.8.0 3.27.2 4.2.2 @@ -518,15 +519,21 @@ - org.springframework - spring-test - ${spring.version} + org.awaitility + awaitility + ${awaitility.version} org.testng testng ${testng.version} + + org.springframework + spring-test + ${spring.version} + + junit @@ -696,9 +703,15 @@ - org.awaitility - awaitility - ${awaitility.version} + com.atlassian.oai + swagger-request-validator-core + ${swagger-request-validator.version} + + + commons-logging + commons-logging + + @@ -1323,6 +1336,12 @@ mockito-junit-jupiter test + + uk.org.webcompere + system-stubs-core + 2.1.6 + test + diff --git a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java index 213a08c22d..fd7ab07395 100644 --- a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java +++ b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java @@ -115,7 +115,8 @@ public void run(final IHookCallBack callBack, ITestResult testResult) { * @param methodTestLoaders * @param invocationCount */ - protected void run(ITestResult testResult, Method method, List methodTestLoaders, int invocationCount) { + protected void run(ITestResult testResult, Method method, List methodTestLoaders, + int invocationCount) { if (citrus == null) { citrus = Citrus.newInstance(new CitrusSpringContextProvider(applicationContext)); CitrusAnnotations.injectCitrusFramework(this, citrus); @@ -163,6 +164,9 @@ protected void run(ITestResult testResult, Method method, List metho @BeforeClass(alwaysRun = true) public final void before() { + // We need to consider the possibility, that one test has meanwhile modified the current citrus instance, + // as there can be plenty of tests running between @BeforeSuite and the execution of an actual subclass of + // this support. The citrus instance may even have a mocked context. if (citrus == null) { citrus = Citrus.newInstance(new CitrusSpringContextProvider(applicationContext)); CitrusAnnotations.injectCitrusFramework(this, citrus); @@ -205,7 +209,7 @@ public final void beforeSuite() { CitrusAnnotations.injectCitrusFramework(this, citrus); beforeSuite(citrus.getCitrusContext()); citrus.beforeSuite(Reporter.getCurrentTestResult().getTestContext().getSuite().getName(), - Reporter.getCurrentTestResult().getTestContext().getIncludedGroups()); + Reporter.getCurrentTestResult().getTestContext().getIncludedGroups()); } /** From 99f448450e5740b179dadb6f7e019b6e59f5ad5f Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Mon, 24 Jun 2024 19:22:06 +0200 Subject: [PATCH 04/47] chore(#1175): minor adjustments on imports and code style --- .../openapi/OpenApiPathRegistry.java | 10 ++-- .../openapi/OpenApiRepository.java | 12 ++--- .../openapi/OpenApiResourceLoader.java | 45 ++++++----------- .../openapi/OpenApiSpecification.java | 37 +++++++------- .../openapi/OpenApiSpecificationAdapter.java | 18 +------ .../OpenApiSpecificationProcessor.java | 3 +- .../openapi/OpenApiSupport.java | 6 +-- .../openapi/OpenApiTestDataGenerator.java | 49 +++---------------- .../citrusframework/openapi/OpenApiUtils.java | 6 +-- .../openapi/actions/OpenApiActionBuilder.java | 2 - .../OpenApiClientRequestActionBuilder.java | 9 ++-- .../OpenApiClientResponseActionBuilder.java | 10 ++-- .../OpenApiServerRequestActionBuilder.java | 28 +++++------ .../OpenApiServerResponseActionBuilder.java | 49 ++++++++++--------- .../openapi/model/OasAdapter.java | 19 +------ .../openapi/model/OasModelHelper.java | 16 +++--- .../openapi/model/OpenApiVersion.java | 4 +- .../openapi/model/OperationPathAdapter.java | 4 +- .../openapi/model/v2/Oas20ModelHelper.java | 7 +-- .../openapi/model/v3/Oas30ModelHelper.java | 25 ++++------ .../validation/OpenApiRequestValidator.java | 13 ++--- .../validation/OpenApiResponseValidator.java | 4 +- .../citrusframework/openapi/xml/OpenApi.java | 8 +-- .../citrusframework/openapi/yaml/OpenApi.java | 10 ++-- .../openapi/OpenApiPathRegistryTest.java | 13 ++--- .../openapi/OpenApiRepositoryTest.java | 17 ++++--- .../openapi/OpenApiSettingsTest.java | 10 ++-- .../OpenApiSpecificationAdapterTest.java | 10 ++-- .../openapi/OpenApiSpecificationTest.java | 32 ++++++------ .../openapi/OpenApiTestDataGeneratorTest.java | 9 ++-- .../openapi/groovy/OpenApiClientTest.java | 10 ++-- .../openapi/groovy/OpenApiServerTest.java | 4 +- .../openapi/integration/OpenApiServerIT.java | 2 +- .../model/OperationPathAdapterTest.java | 8 --- .../model/v2/Oas20ModelHelperTest.java | 11 +++-- .../model/v3/Oas30ModelHelperTest.java | 15 +++--- ...OpenApiRequestValidationProcessorTest.java | 19 +++---- .../OpenApiRequestValidatorTest.java | 27 ++++++---- ...penApiResponseValidationProcessorTest.java | 7 ++- .../OpenApiResponseValidatorTest.java | 21 +++++--- .../openapi/xml/OpenApiClientTest.java | 10 ++-- .../openapi/xml/OpenApiServerTest.java | 4 +- .../openapi/yaml/OpenApiClientTest.java | 10 ++-- .../openapi/yaml/OpenApiServerTest.java | 4 +- 44 files changed, 283 insertions(+), 354 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java index 1c05877806..6218baaceb 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java @@ -16,16 +16,17 @@ package org.citrusframework.openapi; -import static java.lang.String.format; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; + +import static java.lang.String.format; /** * A registry to store objects by OpenApi paths. The registry uses a digital tree data structure @@ -187,5 +188,4 @@ class RegistryNode { String path; T value = null; } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 36f113ea83..083da342ca 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -16,6 +16,11 @@ package org.citrusframework.openapi; +import org.citrusframework.repository.BaseRepository; +import org.citrusframework.spi.Resource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.net.MalformedURLException; import java.net.URL; @@ -24,10 +29,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import org.citrusframework.repository.BaseRepository; -import org.citrusframework.spi.Resource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * OpenApi repository holding a set of {@link OpenApiSpecification} known in the test scope. @@ -140,7 +141,4 @@ static Optional determineResourceAlias(Resource openApiResource) { public List getOpenApiSpecifications() { return openApiSpecifications; } - - - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java index 47fe703e7a..39efffc101 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java @@ -21,15 +21,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.apicurio.datamodels.Library; import io.apicurio.datamodels.openapi.models.OasDocument; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.util.Objects; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.TrustAllStrategy; import org.apache.hc.core5.http.HttpHeaders; @@ -40,6 +31,16 @@ import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; + /** * Loads Open API specifications from different locations like file resource or web resource. */ @@ -47,7 +48,6 @@ public final class OpenApiResourceLoader { static final RawResolver RAW_RESOLVER = new RawResolver(); - static final OasResolver OAS_RESOLVER = new OasResolver(); /** @@ -59,8 +59,6 @@ private OpenApiResourceLoader() { /** * Loads the specification from a file resource. Either classpath or file system resource path is supported. - * @param resource - * @return */ public static OasDocument fromFile(String resource) { return fromFile(FileUtils.getFileResource(resource), OAS_RESOLVER); @@ -68,8 +66,6 @@ public static OasDocument fromFile(String resource) { /** * Loads the raw specification from a file resource. Either classpath or file system resource path is supported. - * @param resource - * @return */ public static String rawFromFile(String resource) { return fromFile(FileUtils.getFileResource(resource), @@ -78,8 +74,6 @@ public static String rawFromFile(String resource) { /** * Loads the specification from a resource. - * @param resource - * @return */ public static OasDocument fromFile(Resource resource) { return fromFile(resource, OAS_RESOLVER); @@ -87,8 +81,6 @@ public static OasDocument fromFile(Resource resource) { /** * Loads the raw specification from a resource. - * @param resource - * @return */ public static String rawFromFile(Resource resource) { return fromFile(resource, RAW_RESOLVER); @@ -104,8 +96,6 @@ private static T fromFile(Resource resource, Resolver resolver) { /** * Loads specification from given web URL location. - * @param url - * @return */ public static OasDocument fromWebResource(URL url) { return fromWebResource(url, OAS_RESOLVER); @@ -113,8 +103,6 @@ public static OasDocument fromWebResource(URL url) { /** * Loads raw specification from given web URL location. - * @param url - * @return */ public static String rawFromWebResource(URL url) { return fromWebResource(url, RAW_RESOLVER); @@ -129,13 +117,13 @@ private static T fromWebResource(URL url, Resolver resolver) { int status = con.getResponseCode(); if (status > 299) { - throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), + throw new IllegalStateException("Failed to retrieve Open API specification: " + url, new IOException(FileUtils.readToString(con.getErrorStream()))); } else { return resolve(FileUtils.readToString(con.getInputStream()), resolver); } } catch (IOException e) { - throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), e); + throw new IllegalStateException("Failed to retrieve Open API specification: " + url, e); } finally { if (con != null) { con.disconnect(); @@ -145,8 +133,6 @@ private static T fromWebResource(URL url, Resolver resolver) { /** * Loads specification from given web URL location using secured Http connection. - * @param url - * @return */ public static OasDocument fromSecuredWebResource(URL url) { return fromSecuredWebResource(url, OAS_RESOLVER); @@ -154,8 +140,6 @@ public static OasDocument fromSecuredWebResource(URL url) { /** * Loads raw specification from given web URL location using secured Http connection. - * @param url - * @return */ public static String rawFromSecuredWebResource(URL url) { return fromSecuredWebResource(url, RAW_RESOLVER); @@ -180,7 +164,7 @@ private static T fromSecuredWebResource(URL url, Resolver resolver) { int status = con.getResponseCode(); if (status > 299) { - throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), + throw new IllegalStateException("Failed to retrieve Open API specification: " + url, new IOException(FileUtils.readToString(con.getErrorStream()))); } else { return resolve(FileUtils.readToString(con.getInputStream()), resolver); @@ -188,7 +172,7 @@ private static T fromSecuredWebResource(URL url, Resolver resolver) { } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { throw new IllegalStateException("Failed to create https client for ssl connection", e); } catch (IOException e) { - throw new IllegalStateException("Failed to retrieve Open API specification: " + url.toString(), e); + throw new IllegalStateException("Failed to retrieve Open API specification: " + url, e); } finally { if (con != null) { con.disconnect(); @@ -255,5 +239,4 @@ public String resolveFromNode(JsonNode node) { } } } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index 918aee6f6c..cd70694f74 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -16,26 +16,11 @@ package org.citrusframework.openapi; -import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.OpenApiInteractionValidator.Builder; import io.apicurio.datamodels.core.models.common.Info; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.client.HttpClient; @@ -49,6 +34,23 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; + /** * OpenApi specification resolves URL or local file resources to a specification document. *

@@ -209,7 +211,6 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { } if (resolvedSpecUrl.startsWith(HTTP)) { - URL specWebResource = toSpecUrl(resolvedSpecUrl); if (resolvedSpecUrl.startsWith(HTTPS)) { initApiDoc( @@ -257,10 +258,10 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { // provided for testing URL toSpecUrl(String resolvedSpecUrl) { try { - return new URL(resolvedSpecUrl); + return URI.create(resolvedSpecUrl).toURL(); } catch (MalformedURLException e) { throw new IllegalStateException( - "Failed to retrieve Open API specification as web resource: " + specUrl, e); + "Failed to retrieve Open API specification as web resource: " + resolvedSpecUrl, e); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java index fa3eaca62c..011a2dc7fd 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java @@ -22,22 +22,6 @@ * * @param the type to which the specification is adapted. */ -public class OpenApiSpecificationAdapter { - - private final OpenApiSpecification openApiSpecification; +public record OpenApiSpecificationAdapter(OpenApiSpecification openApiSpecification, T entity) { - private final T entity; - - public OpenApiSpecificationAdapter(OpenApiSpecification openApiSpecification, T entity) { - this.openApiSpecification = openApiSpecification; - this.entity = entity; - } - - public OpenApiSpecification getOpenApiSpecification() { - return openApiSpecification; - } - - public T getEntity() { - return entity; - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java index b7ca0b5bdc..ceeb9286d5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java @@ -16,12 +16,13 @@ package org.citrusframework.openapi; -import java.util.Map; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; + /** * Interface for processing OpenAPI specifications. *

diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSupport.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSupport.java index e966960fdf..9020d555e3 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSupport.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSupport.java @@ -16,9 +16,6 @@ package org.citrusframework.openapi; -import java.util.Collection; -import java.util.Map; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; @@ -33,6 +30,9 @@ import org.yaml.snakeyaml.nodes.Tag; import org.yaml.snakeyaml.representer.Representer; +import java.util.Collection; +import java.util.Map; + public class OpenApiSupport { private static final ObjectMapper OBJECT_MAPPER; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index a09be519ea..497676cb5c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -17,8 +17,7 @@ package org.citrusframework.openapi; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.Map; -import java.util.stream.Collectors; +import jakarta.annotation.Nullable; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -26,6 +25,9 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; +import java.util.Map; +import java.util.stream.Collectors; + /** * Generates proper payloads and validation expressions based on Open API specification rules. Creates outbound payloads * with generated random test data according to specification and creates inbound payloads with proper validation expressions to @@ -36,9 +38,6 @@ public class OpenApiTestDataGenerator { /** * Creates payload from schema for outbound message. - * @param schema - * @param definitions - * @return */ public static String createOutboundPayload(OasSchema schema, Map definitions, OpenApiSpecification specification) { @@ -81,10 +80,6 @@ public static String createOutboundPayload(OasSchema schema, Map definitions, boolean quotes, OpenApiSpecification specification, TestContext context) { @@ -106,10 +101,6 @@ public static T createRawRandomValueExpression(String name, OasSchema schema /** * Create payload from schema with random values. - * @param schema - * @param definitions - * @param quotes - * @return */ public static String createRandomValueExpression(OasSchema schema, Map definitions, boolean quotes, OpenApiSpecification specification) { @@ -179,9 +170,6 @@ public static T createRawRandomValueExpression(OasSchema schema, Map definitions, OpenApiSpecification specification) { @@ -224,9 +212,6 @@ public static String createInboundPayload(OasSchema schema, Map definitions, boolean quotes, OpenApiSpecification specification, @@ -257,10 +236,6 @@ public static String createValidationExpression(String name, OasSchema schema, M /** * Create validation expression using functions according to schema type and format. - * @param schema - * @param definitions - * @param quotes - * @return */ public static String createValidationExpression(OasSchema schema, Map definitions, boolean quotes, OpenApiSpecification specification) { @@ -307,8 +282,6 @@ public static String createValidationExpression(OasSchema schema, Map schemaForMediaType) { - if (schemaForMediaType.getNode() == null) { + if (schemaForMediaType.node() == null) { // No schema means no payload, no type message.setPayload(null); } else { - if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.getAdapted())) { + if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { // Schema but plain text - message.setPayload(createOutboundPayload(schemaForMediaType.getNode(), + message.setPayload(createOutboundPayload(schemaForMediaType.node(), OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); - } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.getAdapted())) { + } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.adapted())) { // Json Schema - message.setPayload(createOutboundPayload(schemaForMediaType.getNode(), + message.setPayload(createOutboundPayload(schemaForMediaType.node(), OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java index a3f6fa8c52..9933ecebc8 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasAdapter.java @@ -2,23 +2,6 @@ import io.apicurio.datamodels.core.models.Node; -public class OasAdapter { - - private final S node; - - private final T adapted; - - public OasAdapter(S node, T adapted) { - this.node = node; - this.adapted = adapted; - } - - public S getNode() { - return node; - } - - public T getAdapted() { - return adapted; - } +public record OasAdapter(S node, T adapted) { } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index c15f6c3732..55b03f84f1 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,8 +16,6 @@ package org.citrusframework.openapi.model; -import static java.util.Collections.singletonList; - import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; @@ -36,6 +34,11 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Parameter; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import jakarta.annotation.Nullable; +import org.citrusframework.openapi.model.v2.Oas20ModelHelper; +import org.citrusframework.openapi.model.v3.Oas30ModelHelper; +import org.citrusframework.util.StringUtils; +import org.springframework.http.MediaType; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -48,10 +51,8 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; -import org.citrusframework.openapi.model.v2.Oas20ModelHelper; -import org.citrusframework.openapi.model.v3.Oas30ModelHelper; -import org.citrusframework.util.StringUtils; -import org.springframework.http.MediaType; + +import static java.util.Collections.singletonList; public final class OasModelHelper { @@ -306,7 +307,8 @@ public static Optional getResponseForRandomGeneration(OasDocument o // Fallback 4: Pick the first response no matter which schema response = operation.responses.getResponses().stream() .map(resp -> responseMap.get(resp.getStatusCode())) - .filter(Objects::nonNull).findFirst(); + .filter(Objects::nonNull) + .findFirst(); } return response; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java index 13e4a74008..f9b9727b4c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java @@ -16,12 +16,12 @@ package org.citrusframework.openapi.model; -import java.util.Arrays; - import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; import io.apicurio.datamodels.openapi.v3.models.Oas30Document; +import java.util.Arrays; + /** * List of supported OpenAPI specification versions and their corresponding model document types. */ diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java index 7d943af929..987ed05c90 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -16,11 +16,11 @@ package org.citrusframework.openapi.model; -import static java.lang.String.format; - import io.apicurio.datamodels.openapi.models.OasOperation; import org.citrusframework.openapi.OpenApiUtils; +import static java.lang.String.format; + /** * Adapts the different paths associated with an OpenAPI operation to the {@link OasOperation}. * This record holds the API path, context path, full path, and the associated {@link OasOperation} object. diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index 34794a8f71..90cdadacf2 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -26,16 +26,17 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition; -import java.util.Arrays; import jakarta.annotation.Nullable; +import org.citrusframework.openapi.model.OasAdapter; +import org.citrusframework.openapi.model.OasModelHelper; + +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import org.citrusframework.openapi.model.OasAdapter; -import org.citrusframework.openapi.model.OasModelHelper; public final class Oas20ModelHelper { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 1f56f4d4c5..6775c5ad8b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -26,8 +26,13 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30RequestBody; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.model.OasAdapter; +import org.citrusframework.openapi.model.OasModelHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -37,10 +42,6 @@ import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; -import org.citrusframework.openapi.model.OasAdapter; -import org.citrusframework.openapi.model.OasModelHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public final class Oas30ModelHelper { @@ -59,11 +60,7 @@ public static String getHost(Oas30Document openApiDoc) { String serverUrl = resolveUrl(openApiDoc.servers.get(0)); if (serverUrl.startsWith("http")) { - try { - return new URL(serverUrl).getHost(); - } catch (MalformedURLException e) { - throw new IllegalStateException(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); - } + return URI.create(serverUrl).getHost(); } return "localhost"; @@ -78,7 +75,7 @@ public static List getSchemes(Oas30Document openApiDoc) { .map(Oas30ModelHelper::resolveUrl) .map(serverUrl -> { try { - return new URL(serverUrl).getProtocol(); + return URI.create(serverUrl).toURL().getProtocol(); } catch (MalformedURLException e) { LOG.warn(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); return null; @@ -98,11 +95,7 @@ public static String getBasePath(Oas30Document openApiDoc) { String serverUrl = resolveUrl(server); if (serverUrl.startsWith("http")) { - try { - basePath = new URL(serverUrl).getPath(); - } catch (MalformedURLException e) { - throw new IllegalStateException(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); - } + basePath = URI.create(serverUrl).getPath(); } else { basePath = serverUrl; } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java index 6948c793d8..bef2c35230 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -16,19 +16,20 @@ package org.citrusframework.openapi.validation; -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.SimpleRequest; import com.atlassian.oai.validator.report.ValidationReport; -import java.util.ArrayList; -import java.util.Collection; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.model.OperationPathAdapter; +import java.util.ArrayList; +import java.util.Collection; + +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; + /** * Specific validator that uses atlassian and is responsible for validating HTTP requests * against an OpenAPI specification using the provided {@code OpenApiInteractionValidator}. @@ -83,8 +84,8 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, value))); httpMessage.getHeaders().forEach((key, value) -> { - if (value instanceof Collection) { - ((Collection) value).forEach( v -> finalRequestBuilder.withHeader(key, v != null ? v.toString() : null)); + if (value instanceof Collection collection) { + collection.forEach( v -> finalRequestBuilder.withHeader(key, v != null ? v.toString() : null)); } else { finalRequestBuilder.withHeader(key, value != null ? value.toString() : null); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java index db4a41e375..9aba9b0764 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -16,8 +16,6 @@ package org.citrusframework.openapi.validation; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.model.Response; @@ -28,6 +26,8 @@ import org.citrusframework.openapi.model.OperationPathAdapter; import org.springframework.http.HttpStatusCode; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; + /** * Specific validator, that facilitates the use of Atlassian's Swagger Request Validator, * and delegates validation of OpenApi requests to instances of {@link OpenApiRequestValidator}. diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java index f7a12adc9d..41eed4a77e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java @@ -16,10 +16,6 @@ package org.citrusframework.openapi.xml; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - import jakarta.xml.bind.annotation.XmlAccessType; import jakarta.xml.bind.annotation.XmlAccessorType; import jakarta.xml.bind.annotation.XmlAttribute; @@ -46,6 +42,10 @@ import org.citrusframework.xml.actions.Receive; import org.citrusframework.xml.actions.Send; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + @XmlRootElement(name = "openapi") public class OpenApi implements TestActionBuilder, ReferenceResolverAware { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java index 4958fddc26..4a67110219 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java @@ -16,10 +16,6 @@ package org.citrusframework.openapi.yaml; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - import org.citrusframework.TestAction; import org.citrusframework.TestActionBuilder; import org.citrusframework.actions.ReceiveMessageAction; @@ -36,9 +32,13 @@ import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.spi.ReferenceResolverAware; +import org.citrusframework.yaml.actions.Message; import org.citrusframework.yaml.actions.Receive; import org.citrusframework.yaml.actions.Send; -import org.citrusframework.yaml.actions.Message; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; public class OpenApi implements TestActionBuilder, ReferenceResolverAware { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java index 9d811711f6..d837f1f0ee 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java @@ -16,10 +16,8 @@ package org.citrusframework.openapi; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; +import org.testng.Assert; +import org.testng.annotations.Test; import java.util.ArrayList; import java.util.HashSet; @@ -28,8 +26,11 @@ import java.util.Random; import java.util.Set; import java.util.stream.Collectors; -import org.testng.Assert; -import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; public class OpenApiPathRegistryTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index 9185cc6081..fe61791bf2 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -16,6 +16,15 @@ package org.citrusframework.openapi; +import org.citrusframework.spi.Resource; +import org.testng.annotations.Test; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Optional; + import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -24,14 +33,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import java.util.Optional; -import org.citrusframework.spi.Resource; -import org.testng.annotations.Test; - public class OpenApiRepositoryTest { private static final String ROOT = "/root"; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java index c96cd5f5b6..d4e448ec26 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -1,5 +1,10 @@ package org.citrusframework.openapi; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; + import static org.citrusframework.openapi.OpenApiSettings.GENERATE_OPTIONAL_FIELDS_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.REQUEST_VALIDATION_ENABLED_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_VALIDATION_ENABLED_PROPERTY; @@ -8,11 +13,6 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; - public class OpenApiSettingsTest { private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java index 6693078ef2..65c1433bc4 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java @@ -1,14 +1,14 @@ package org.citrusframework.openapi; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + public class OpenApiSpecificationAdapterTest { @Mock @@ -34,14 +34,14 @@ public void tearDown() throws Exception { @Test public void shouldProvideOpenApiSpecification() { - OpenApiSpecification specification = openApiSpecificationAdapter.getOpenApiSpecification(); + OpenApiSpecification specification = openApiSpecificationAdapter.openApiSpecification(); assertNotNull(specification, "OpenApiSpecification should not be null"); assertEquals(specification, openApiSpecificationMock, "OpenApiSpecification should match the mock"); } @Test public void shouldProvideEntity() { - Object entity = openApiSpecificationAdapter.getEntity(); + Object entity = openApiSpecificationAdapter.entity(); assertNotNull(entity, "Entity should not be null"); assertEquals(entity, entityMock, "Entity should match the mock"); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index 5a8cb34c45..05f22c522a 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -1,12 +1,7 @@ package org.citrusframework.openapi; import io.apicurio.datamodels.openapi.models.OasDocument; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import javax.net.ssl.HttpsURLConnection; import org.citrusframework.context.TestContext; -import org.citrusframework.endpoint.EndpointConfiguration; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpEndpointConfiguration; @@ -23,12 +18,23 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import javax.net.ssl.HttpsURLConnection; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.Optional; import static org.citrusframework.util.FileUtils.readToString; -import static org.mockito.Mockito.*; -import static org.testng.Assert.*; +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; public class OpenApiSpecificationTest { @@ -211,21 +217,21 @@ public static Object[][] specSources() { } @Test(dataProvider = "lazyInitializationDataprovider") - public void shouldDisableEnableRequestValidationWhenSet(String requestUrl, String specSource) throws IOException { + public void shouldDisableEnableRequestValidationWhenSet(String requestUrl, String specSource) { // Given OpenApiSpecification specification = new OpenApiSpecification() { + @Override URL toSpecUrl(String resolvedSpecUrl) { return mockUrlConnection(resolvedSpecUrl); } }; + specification.setRequestUrl(requestUrl); specification.setHttpClient("sampleHttpClient"); specification.setSpecUrl(specSource); - when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(answer-> - answer.getArgument(0) - ); + when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(returnsFirstArg()); when(testContextMock.getReferenceResolver()).thenReturn(referenceResolverMock); when(referenceResolverMock.isResolvable("sampleHttpClient", HttpClient.class)).thenReturn(true); @@ -233,9 +239,6 @@ URL toSpecUrl(String resolvedSpecUrl) { when(httpClient.getEndpointConfiguration()).thenReturn(endpointConfigurationMock); when(endpointConfigurationMock.getRequestUrl()).thenReturn("http://org.citrus.sample"); - boolean sampleHttpCient = testContextMock.getReferenceResolver() - .isResolvable("sampleHttpClient", HttpClient.class); - // When specification.setRequestValidationEnabled(false); @@ -383,5 +386,4 @@ public void shouldReturnSpecUrlInAbsenceOfRequestUrl() { assertEquals(openApiSpecification.getRequestUrl(), "http://or.citrus.sample"); } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index 89d19ac670..ab063e27c9 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -16,17 +16,18 @@ package org.citrusframework.openapi; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; - import com.fasterxml.jackson.core.JsonProcessingException; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.Map; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.spi.Resources; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.Map; + +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; + // TODO: Add more tests public class OpenApiTestDataGeneratorTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index b65e3f9ed7..607d1b3c54 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -16,11 +16,6 @@ package org.citrusframework.openapi.groovy; -import java.io.IOException; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -57,6 +52,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; public class OpenApiClientTest extends AbstractGroovyActionDslTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java index 6a1ad5bb02..61023c6dcd 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java @@ -16,8 +16,6 @@ package org.citrusframework.openapi.groovy; -import java.util.Map; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -45,6 +43,8 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.Map; + import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; import static org.testng.Assert.assertEquals; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 03bca16cd3..d29a11f75a 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -165,7 +165,7 @@ public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { assertThrows(TestCaseFailedException.class, () -> then(addPetBuilder)); } - @CitrusTest + @CitrusTest public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { variable("petId", "xxx"); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java index cec2e46744..7846daf42b 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java @@ -1,22 +1,14 @@ package org.citrusframework.openapi.model; -import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; import org.citrusframework.openapi.OpenApiUtils; -import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import static java.lang.String.format; -import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; public class OperationPathAdapterTest { - @Test public void shouldReturnFormattedStringWhenToStringIsCalled() { // Given diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java index f57d3c46ce..501c497f7c 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java @@ -1,8 +1,5 @@ package org.citrusframework.openapi.model.v2; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; @@ -12,11 +9,15 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v2.models.Oas20Responses; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; -import java.util.List; -import java.util.Optional; import org.citrusframework.openapi.model.OasModelHelper; import org.testng.annotations.Test; +import java.util.List; +import java.util.Optional; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + public class Oas20ModelHelperTest { @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java index 9feee74a1a..b26f2f7780 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java @@ -1,9 +1,5 @@ package org.citrusframework.openapi.model.v3; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertSame; -import static org.testng.Assert.assertTrue; - import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Document; @@ -14,13 +10,18 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Responses; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; import org.citrusframework.openapi.model.OasModelHelper; import org.springframework.http.MediaType; import org.testng.annotations.Test; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + public class Oas30ModelHelperTest { @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java index fc72cd5ade..7c7a578106 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java @@ -1,14 +1,5 @@ package org.citrusframework.openapi.validation; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Optional; import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; @@ -21,6 +12,16 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + public class OpenApiRequestValidationProcessorTest { @Mock diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java index d1decc05a3..9b97d42b78 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -4,27 +4,34 @@ import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.report.ValidationReport; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiRequestValidator; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.springframework.web.bind.annotation.RequestMethod; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.testng.Assert.*; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; public class OpenApiRequestValidatorTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java index a7aabba892..bd60fd55b6 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java @@ -15,7 +15,12 @@ import java.util.Optional; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class OpenApiResponseValidationProcessorTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java index d8d4433447..5bfef2eacb 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -4,24 +4,31 @@ import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.model.Response; import com.atlassian.oai.validator.report.ValidationReport; -import io.apicurio.datamodels.core.models.common.Operation; import io.apicurio.datamodels.openapi.models.OasOperation; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.*; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.springframework.http.HttpStatusCode; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; -import static org.testng.Assert.*; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; public class OpenApiResponseValidatorTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index 69805ac452..30ad30e4eb 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -16,11 +16,6 @@ package org.citrusframework.openapi.xml; -import java.io.IOException; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -60,6 +55,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; public class OpenApiClientTest extends AbstractXmlActionTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java index 9e9a832291..b151699c66 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java @@ -16,8 +16,6 @@ package org.citrusframework.openapi.xml; -import java.util.Map; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -45,6 +43,8 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.Map; + import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index 0b09fa9c52..b5b152d559 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -16,11 +16,6 @@ package org.citrusframework.openapi.yaml; -import java.io.IOException; -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ArrayBlockingQueue; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -58,6 +53,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.IOException; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ArrayBlockingQueue; + import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; public class OpenApiClientTest extends AbstractYamlActionTest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java index 2171fac921..723609e773 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java @@ -16,8 +16,6 @@ package org.citrusframework.openapi.yaml; -import java.util.Map; - import org.citrusframework.TestActor; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -45,6 +43,8 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.Map; + import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; From 01f362091b4388e2d050806367385a27ae86ade8 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Tue, 25 Jun 2024 08:36:15 +0200 Subject: [PATCH 05/47] feat(#1175): Add OpenApiRepository and Validation --- .../openapi/OpenApiResourceLoader.java | 4 +- .../openapi/OpenApiTestDataGenerator.java | 9 +++ .../openapi/model/OasModelHelper.java | 25 ++++++++ .../openapi/model/v2/Oas20ModelHelper.java | 12 +++- .../openapi/model/v3/Oas30ModelHelper.java | 5 ++ .../openapi/OpenApiTestDataGeneratorTest.java | 62 ++++++++++++------- 6 files changed, 91 insertions(+), 26 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java index 39efffc101..df39c8a2f5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java @@ -46,9 +46,9 @@ */ public final class OpenApiResourceLoader { - static final RawResolver RAW_RESOLVER = new RawResolver(); + private static final RawResolver RAW_RESOLVER = new RawResolver(); - static final OasResolver OAS_RESOLVER = new OasResolver(); + private static final OasResolver OAS_RESOLVER = new OasResolver(); /** * Prevent instantiation of utility class. diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index 497676cb5c..e2d3d1feeb 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -284,6 +284,15 @@ public static String createValidationExpression(OasSchema schema, Map T delegate(OasParameter parameter, Function generic return value + * @return + */ + private static T delegate(OasSchema schema, Function oas20Function, Function oas30Function) { + if (schema instanceof Oas20Schema oas20Schema) { + return oas20Function.apply(oas20Schema); + } else if (schema instanceof Oas30Schema oas30Schema) { + return oas30Function.apply(oas30Schema); + } + + throw new IllegalArgumentException(String.format("Unsupported operation parameter type: %s", schema.getClass())); + } + /** * Delegate method to version specific model helpers for Open API v2 or v3. * @param operation @@ -534,4 +558,5 @@ public static List resolveAllTypes(@Nullable List acceptedMediaT return acceptedMediaTypes.stream() .flatMap(types -> Arrays.stream(types.split(","))).map(String::trim).toList(); } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index 90cdadacf2..e454faef53 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -25,11 +25,9 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Parameter; import io.apicurio.datamodels.openapi.v2.models.Oas20Response; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition; import jakarta.annotation.Nullable; -import org.citrusframework.openapi.model.OasAdapter; -import org.citrusframework.openapi.model.OasModelHelper; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -37,6 +35,8 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import org.citrusframework.openapi.model.OasAdapter; +import org.citrusframework.openapi.model.OasModelHelper; public final class Oas20ModelHelper { @@ -87,6 +87,11 @@ public static Optional> getSchema(Oas20Operation o return selectedSchema == null && selectedMediaType == null ? Optional.empty() : Optional.of(new OasAdapter<>(selectedSchema, selectedMediaType)); } + public static boolean isCompositeSchema(Oas20Schema schema) { + // Note that oneOf and anyOf is not supported by Oas20. + return schema instanceof Oas20AllOfSchema; + } + public static Optional getRequestBodySchema(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { if (operation.parameters == null) { return Optional.empty(); @@ -201,4 +206,5 @@ public static Optional getParameterSchema(Oas20Parameter parameter) { return Optional.of(schema); } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 6775c5ad8b..746f97f1e5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -85,6 +85,10 @@ public static List getSchemes(Oas30Document openApiDoc) { .toList(); } + public static boolean isCompositeSchema(Oas30Schema schema) { + return schema.anyOf != null || schema.oneOf != null || schema.allOf != null; + } + public static String getBasePath(Oas30Document openApiDoc) { if (openApiDoc.servers == null || openApiDoc.servers.isEmpty()) { return "/"; @@ -245,4 +249,5 @@ private static String resolveUrl(Server server) { public static Optional getParameterSchema(Oas30Parameter parameter) { return Optional.ofNullable((OasSchema) parameter.schema); } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index ab063e27c9..a16ea69d09 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -16,35 +16,55 @@ package org.citrusframework.openapi; -import com.fasterxml.jackson.core.JsonProcessingException; -import io.apicurio.datamodels.openapi.models.OasSchema; -import org.citrusframework.openapi.model.OasModelHelper; -import org.citrusframework.spi.Resources; -import org.testng.Assert; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertEquals; + +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.HashMap; +import java.util.List; import org.testng.annotations.Test; -import java.util.Map; +public class OpenApiTestDataGeneratorTest { -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; + @Test + public void anyOfIsIgnoredForOas3() { -// TODO: Add more tests -public class OpenApiTestDataGeneratorTest { + Oas30Schema anyOfSchema = new Oas30Schema(); + anyOfSchema.anyOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(OpenApiTestDataGenerator.createValidationExpression( + anyOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void allOfIsIgnoredForOas3() { - private final OpenApiSpecification pingSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + Oas30Schema allOfSchema = new Oas30Schema(); + allOfSchema.allOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(OpenApiTestDataGenerator.createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void oneOfIsIgnoredForOas3() { + + Oas30Schema oneOfSchema = new Oas30Schema(); + oneOfSchema.oneOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(OpenApiTestDataGenerator.createValidationExpression( + oneOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } - // TODO: fix this by introducing mature validation @Test - public void failsToValidateAnyOf() throws JsonProcessingException { + public void allOfIsIgnoredForOas2() { - Map schemaDefinitions = OasModelHelper.getSchemaDefinitions( - pingSpec.getOpenApiDoc(null)); - assertNotNull(schemaDefinitions); - assertFalse(schemaDefinitions.isEmpty()); - Assert.assertEquals(schemaDefinitions.size(), 15); + Oas20AllOfSchema allOfSchema = new Oas20AllOfSchema(); + allOfSchema.allOf = List.of(new Oas20Schema(), new Oas20Schema()); - Assert.assertThrows(() -> OpenApiTestDataGenerator.createValidationExpression( - schemaDefinitions.get("PingRespType"), schemaDefinitions, true, pingSpec)); + assertEquals(OpenApiTestDataGenerator.createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); } } From 634ce32f7d67211f6013d30ff922ca4fddc21d82 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Fri, 5 Jul 2024 08:43:29 +0200 Subject: [PATCH 06/47] feat(#1175): improve random data generation for test data generator --- .../openapi/OpenApiConstants.java | 41 + .../openapi/OpenApiRepository.java | 4 +- .../openapi/OpenApiSettings.java | 18 +- .../openapi/OpenApiSpecification.java | 154 ++-- .../openapi/OpenApiTestDataGenerator.java | 725 ++++++++++++------ .../OpenApiTestValidationDataGenerator.java | 246 ++++++ .../OpenApiClientRequestActionBuilder.java | 42 +- .../OpenApiClientResponseActionBuilder.java | 56 +- .../OpenApiServerRequestActionBuilder.java | 64 +- .../OpenApiServerResponseActionBuilder.java | 65 +- .../openapi/model/OasModelHelper.java | 35 +- .../openapi/model/OperationPathAdapter.java | 2 +- .../openapi/{ => util}/OpenApiUtils.java | 18 +- .../openapi/util/RandomElement.java | 116 +++ .../openapi/util/RandomModelBuilder.java | 109 +++ .../openapi/util/RandomModelWriter.java | 115 +++ .../OpenApiRequestValidationProcessor.java | 15 +- .../validation/OpenApiRequestValidator.java | 17 +- .../OpenApiResponseValidationProcessor.java | 17 +- .../validation/OpenApiResponseValidator.java | 9 +- .../openapi/validation/OpenApiValidator.java | 12 +- .../SwaggerOpenApiValidationContext.java | 77 ++ ...SwaggerOpenApiValidationContextLoader.java | 78 ++ .../openapi/OpenApiSettingsTest.java | 28 +- .../openapi/OpenApiSpecificationTest.java | 69 +- .../openapi/OpenApiTestDataGeneratorTest.java | 487 +++++++++++- ...penApiTestValidationDataGeneratorTest.java | 71 ++ .../openapi/OpenApiUtilsTest.java | 17 + .../openapi/integration/OpenApiClientIT.java | 69 +- .../openapi/integration/OpenApiServerIT.java | 105 ++- .../model/OperationPathAdapterTest.java | 18 +- .../openapi/util/RandomElementTest.java | 89 +++ .../openapi/util/RandomModelBuilderTest.java | 127 +++ ...OpenApiRequestValidationProcessorTest.java | 104 +-- .../OpenApiRequestValidatorTest.java | 70 +- ...penApiResponseValidationProcessorTest.java | 104 +-- .../OpenApiResponseValidatorTest.java | 33 +- .../openapi/xml/OpenApiClientTest.java | 1 + .../openapi/petstore/petstore-v3.json | 6 +- .../openapi/ping/ping-api.yaml | 407 +++++++--- core/citrus-base/pom.xml | 6 +- .../functions/DefaultFunctionLibrary.java | 4 + .../core/AdvancedRandomNumberFunction.java | 144 ++++ .../functions/core/RandomPatternFunction.java | 60 ++ .../org/citrusframework/util/StringUtils.java | 27 + .../core/RandomDoubleFunctionTest.java | 246 ++++++ .../core/RandomPatternFunctionTest.java | 75 ++ .../http/message/HttpMessageUtils.java | 39 +- .../http/message/HttpMessageUtilsTest.java | 126 ++- 49 files changed, 3758 insertions(+), 809 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/{ => util}/OpenApiUtils.java (79%) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java create mode 100644 core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java create mode 100644 core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java create mode 100644 core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java create mode 100644 core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java new file mode 100644 index 0000000000..d6802ed996 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java @@ -0,0 +1,41 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +public abstract class OpenApiConstants { + + public static final String TYPE_ARRAY = "array"; + public static final String TYPE_BOOLEAN = "boolean"; + public static final String TYPE_INTEGER = "integer"; + public static final String TYPE_NUMBER = "number"; + public static final String TYPE_OBJECT = "object"; + public static final String TYPE_STRING = "string"; + + public static final String FORMAT_INT32 = "int32"; + public static final String FORMAT_INT64 = "int64"; + public static final String FORMAT_FLOAT = "float"; + public static final String FORMAT_DOUBLE = "double"; + public static final String FORMAT_DATE = "date"; + public static final String FORMAT_DATE_TIME = "date-time"; + public static final String FORMAT_UUID = "uuid"; + + /** + * Prevent instantiation. + */ + private OpenApiConstants() { + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 083da342ca..20f845d604 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -94,8 +94,8 @@ public void setResponseValidationEnabled(boolean responseValidationEnabled) { public void addRepository(Resource openApiResource) { OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); - openApiSpecification.setRequestValidationEnabled(requestValidationEnabled); - openApiSpecification.setResponseValidationEnabled(responseValidationEnabled); + openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); + openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); openApiSpecification.setRootContextPath(rootContextPath); this.openApiSpecifications.add(openApiSpecification); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java index ea99928985..02441f1115 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi; import static java.lang.Boolean.parseBoolean; @@ -35,7 +51,7 @@ public static boolean isValidateOptionalFieldsGlobally() { System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) : "true")); } - public static boolean isRequestValidationEnabledlobally() { + public static boolean isRequestValidationEnabledGlobally() { return parseBoolean(System.getProperty( REQUEST_VALIDATION_ENABLED_PROPERTY, System.getenv(REQUEST_VALIDATION_ENABLED_ENV) != null ? System.getenv(REQUEST_VALIDATION_ENABLED_ENV) : "true")); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index cd70694f74..f27f1bed48 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -16,24 +16,14 @@ package org.citrusframework.openapi; -import com.atlassian.oai.validator.OpenApiInteractionValidator; -import com.atlassian.oai.validator.OpenApiInteractionValidator.Builder; +import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; + import io.apicurio.datamodels.core.models.common.Info; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.openapi.model.OasModelHelper; -import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiRequestValidator; -import org.citrusframework.openapi.validation.OpenApiResponseValidator; -import org.citrusframework.spi.Resource; -import org.citrusframework.spi.Resources; -import org.citrusframework.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -45,11 +35,19 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; - -import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.util.OpenApiUtils; +import org.citrusframework.openapi.validation.SwaggerOpenApiValidationContext; +import org.citrusframework.openapi.validation.SwaggerOpenApiValidationContextLoader; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * OpenApi specification resolves URL or local file resources to a specification document. @@ -97,33 +95,41 @@ public class OpenApiSpecification { private OasDocument openApiDoc; + private SwaggerOpenApiValidationContext swaggerOpenApiValidationContext; + private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); private boolean validateOptionalFields = isValidateOptionalFieldsGlobally(); - private boolean requestValidationEnabled = isRequestValidationEnabledlobally(); + /** + * Flag to indicate, whether request validation is enabled on api level. Api level overrules global + * level and may be overruled by request level. + */ + private boolean apiRequestValidationEnabled = isRequestValidationEnabledGlobally(); - private boolean responseValidationEnabled = isResponseValidationEnabledGlobally(); + /** + * Flag to indicate, whether response validation is enabled on api level. Api level overrules global + * level and may be overruled by request level. + */ + private boolean apiResponseValidationEnabled = isResponseValidationEnabledGlobally(); private final Set aliases = Collections.synchronizedSet(new HashSet<>()); /** - * Maps the identifier (id) of an operation to OperationPathAdapters. Two different keys may be used for each operation. - * Refer to {@link org.citrusframework.openapi.OpenApiSpecification#storeOperationPathAdapter} for more details. + * Maps the identifier (id) of an operation to OperationPathAdapters. Two different keys may be + * used for each operation. Refer to + * {@link org.citrusframework.openapi.OpenApiSpecification#storeOperationPathAdapter} for more + * details. */ private final Map operationIdToOperationPathAdapter = new ConcurrentHashMap<>(); /** - * Stores the unique identifier (uniqueId) of an operation, derived from its HTTP method and path. - * This identifier can always be determined and is therefore safe to use, even for operations without - * an optional operationId defined. + * Stores the unique identifier (uniqueId) of an operation, derived from its HTTP method and + * path. This identifier can always be determined and is therefore safe to use, even for + * operations without an optional operationId defined. */ private final Map operationToUniqueId = new ConcurrentHashMap<>(); - private OpenApiRequestValidator openApiRequestValidator; - - private OpenApiResponseValidator openApiResponseValidator; - public static OpenApiSpecification from(String specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); specification.setSpecUrl(specUrl); @@ -134,21 +140,19 @@ public static OpenApiSpecification from(String specUrl) { public static OpenApiSpecification from(URL specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc; - OpenApiInteractionValidator validator; + SwaggerOpenApiValidationContext swaggerOpenApiValidationContext; if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); - validator = new OpenApiInteractionValidator.Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromSecuredWebResource(specUrl)).build(); + swaggerOpenApiValidationContext = SwaggerOpenApiValidationContextLoader.fromSecuredWebResource(specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); - validator = new OpenApiInteractionValidator.Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromWebResource(specUrl)).build(); + swaggerOpenApiValidationContext = SwaggerOpenApiValidationContextLoader.fromWebResource(specUrl); } specification.setSpecUrl(specUrl.toString()); specification.initPathLookups(); specification.setOpenApiDoc(openApiDoc); - specification.setValidator(validator); + specification.setSwaggerOpenApiValidationContext(swaggerOpenApiValidationContext); specification.setRequestUrl( String.format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", @@ -160,11 +164,9 @@ public static OpenApiSpecification from(URL specUrl) { public static OpenApiSpecification from(Resource resource) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); - OpenApiInteractionValidator validator = new Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromFile(resource)).build(); specification.setOpenApiDoc(openApiDoc); - specification.setValidator(validator); + specification.setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromFile(resource)); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) .orElse(Collections.singletonList(HTTP)) @@ -215,12 +217,11 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { if (resolvedSpecUrl.startsWith(HTTPS)) { initApiDoc( () -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); - setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromSecuredWebResource(specWebResource)).build()); + + setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromSecuredWebResource(specWebResource)); } else { initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); - setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromWebResource(specWebResource)).build()); + setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromWebResource(specWebResource)); } if (requestUrl == null) { @@ -234,8 +235,7 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { Resource resource = Resources.create(resolvedSpecUrl); initApiDoc( () -> OpenApiResourceLoader.fromFile(resource)); - setValidator(new OpenApiInteractionValidator.Builder().withInlineApiSpecification( - OpenApiResourceLoader.rawFromFile(resource)).build()); + setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromFile(resource)); if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -255,6 +255,11 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { return openApiDoc; } + public SwaggerOpenApiValidationContext getSwaggerOpenApiValidationContext() { + return swaggerOpenApiValidationContext; + } + + // provided for testing URL toSpecUrl(String resolvedSpecUrl) { try { @@ -269,12 +274,10 @@ void setOpenApiDoc(OasDocument openApiDoc) { initApiDoc(() -> openApiDoc); } - private void setValidator(OpenApiInteractionValidator openApiInteractionValidator) { - openApiRequestValidator = new OpenApiRequestValidator(openApiInteractionValidator); - openApiRequestValidator.setEnabled(requestValidationEnabled); - - openApiResponseValidator = new OpenApiResponseValidator(openApiInteractionValidator); - openApiRequestValidator.setEnabled(responseValidationEnabled); + private void setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContext swaggerOpenApiValidationContext) { + this.swaggerOpenApiValidationContext = swaggerOpenApiValidationContext; + this.swaggerOpenApiValidationContext.setResponseValidationEnabled(apiResponseValidationEnabled); + this.swaggerOpenApiValidationContext.setRequestValidationEnabled(apiRequestValidationEnabled); } private void initApiDoc(Supplier openApiDocSupplier) { @@ -306,12 +309,14 @@ private void initPathLookups() { } /** - * Stores an {@link OperationPathAdapter} in {@link org.citrusframework.openapi.OpenApiSpecification#operationIdToOperationPathAdapter}. - * The adapter is stored using two keys: the operationId (optional) and the full path of the operation, including the method. - * The full path is always determinable and thus can always be safely used. + * Stores an {@link OperationPathAdapter} in + * {@link org.citrusframework.openapi.OpenApiSpecification#operationIdToOperationPathAdapter}. + * The adapter is stored using two keys: the operationId (optional) and the full path of the + * operation, including the method. The full path is always determinable and thus can always be + * safely used. * * @param operation The {@link OperationPathAdapter} to store. - * @param path The full path of the operation, including the method. + * @param path The full path of the operation, including the method. */ private void storeOperationPathAdapter(OasOperation operation, String path) { @@ -319,9 +324,10 @@ private void storeOperationPathAdapter(OasOperation operation, String path) { String fullOperationPath = StringUtils.appendSegmentToUrlPath(basePath, path); OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, - StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation); + StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation); - String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(fullOperationPath, operation); + String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(fullOperationPath, + operation); operationToUniqueId.put(operation, uniqueOperationId); operationIdToOperationPathAdapter.put(uniqueOperationId, operationPathAdapter); @@ -358,25 +364,25 @@ public void setRequestUrl(String requestUrl) { this.requestUrl = requestUrl; } - public boolean isRequestValidationEnabled() { - return requestValidationEnabled; + public boolean isApiRequestValidationEnabled() { + return apiRequestValidationEnabled; } - public void setRequestValidationEnabled(boolean enabled) { - this.requestValidationEnabled = enabled; - if (this.openApiRequestValidator != null) { - this.openApiRequestValidator.setEnabled(enabled); + public void setApiRequestValidationEnabled(boolean enabled) { + this.apiRequestValidationEnabled = enabled; + if (this.swaggerOpenApiValidationContext != null) { + this.swaggerOpenApiValidationContext.setRequestValidationEnabled(enabled); } } - public boolean isResponseValidationEnabled() { - return responseValidationEnabled; + public boolean isApiResponseValidationEnabled() { + return apiResponseValidationEnabled; } - public void setResponseValidationEnabled(boolean enabled) { - this.responseValidationEnabled = enabled; - if (this.openApiResponseValidator != null) { - this.openApiResponseValidator.setEnabled(enabled); + public void setApiResponseValidationEnabled(boolean enabled) { + this.apiResponseValidationEnabled = enabled; + if (this.swaggerOpenApiValidationContext != null) { + this.swaggerOpenApiValidationContext.setResponseValidationEnabled(enabled); } } @@ -449,14 +455,6 @@ public Optional getOperation(String operationId, TestConte return Optional.ofNullable(operationIdToOperationPathAdapter.get(operationId)); } - public Optional getRequestValidator() { - return Optional.ofNullable(openApiRequestValidator); - } - - public Optional getResponseValidator() { - return Optional.ofNullable(openApiResponseValidator); - } - public OpenApiSpecification withRootContext(String rootContextPath) { setRootContextPath(rootContextPath); return this; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index e2d3d1feeb..74deef213f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -17,72 +17,125 @@ package org.citrusframework.openapi; import io.apicurio.datamodels.openapi.models.OasSchema; -import jakarta.annotation.Nullable; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.model.OasModelHelper; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - +import org.citrusframework.openapi.util.OpenApiUtils; +import org.citrusframework.openapi.util.RandomModelBuilder; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import static java.lang.Boolean.TRUE; +import static java.lang.String.format; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; +import static org.citrusframework.util.StringUtils.hasText; +import static org.citrusframework.util.StringUtils.quote; +import static org.springframework.util.CollectionUtils.isEmpty; + /** - * Generates proper payloads and validation expressions based on Open API specification rules. Creates outbound payloads - * with generated random test data according to specification and creates inbound payloads with proper validation expressions to - * enforce the specification rules. - * + * Generates proper payloads and validation expressions based on Open API specification rules. */ -public class OpenApiTestDataGenerator { +public abstract class OpenApiTestDataGenerator { + + public static final BigDecimal THOUSAND = new BigDecimal(1000); + public static final BigDecimal HUNDRED = BigDecimal.valueOf(100); + public static final BigDecimal MINUS_THOUSAND = new BigDecimal(-1000); + + private OpenApiTestDataGenerator() { + // Static access only + } + + private static final Map SPECIAL_FORMATS = Map.of( + "email", "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}", + "uri", + "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})", + "hostname", + "(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])", + "ipv4", + "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)", + "ipv6", + "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"); + + /** + * Creates payload from schema for outbound message. + */ + public static String createOutboundPayload(OasSchema schema, + OpenApiSpecification specification) { + return createOutboundPayload(schema, + OasModelHelper.getSchemaDefinitions(specification.getOpenApiDoc(null)), specification); + } /** * Creates payload from schema for outbound message. */ public static String createOutboundPayload(OasSchema schema, Map definitions, - OpenApiSpecification specification) { + OpenApiSpecification specification) { + return createOutboundPayload(schema, definitions, specification, new HashSet<>()); + } + + /** + * Creates payload from schema for outbound message. + */ + private static String createOutboundPayload(OasSchema schema, + Map definitions, + OpenApiSpecification specification, Set visitedRefSchemas) { + RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); + createOutboundPayloadAsMap(randomModelBuilder, schema, definitions, specification, + visitedRefSchemas); + return randomModelBuilder.toString(); + } + + private static void createOutboundPayloadAsMap(RandomModelBuilder randomModelBuilder, + OasSchema schema, + Map definitions, + OpenApiSpecification specification, Set visitedRefSchemas) { + + if (hasText(schema.$ref) && visitedRefSchemas.contains(schema)) { + // Avoid recursion + return; + } + if (OasModelHelper.isReferenceType(schema)) { OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createOutboundPayload(resolved, definitions, specification); + createOutboundPayloadAsMap(randomModelBuilder, resolved, definitions, specification, + visitedRefSchemas); + return; } - StringBuilder payload = new StringBuilder(); - if (OasModelHelper.isObjectType(schema)) { - payload.append("{"); - - if (schema.properties != null) { - for (Map.Entry entry : schema.properties.entrySet()) { - if (specification.isGenerateOptionalFields() || isRequired(schema, entry.getKey())) { - payload.append("\"") - .append(entry.getKey()) - .append("\": ") - .append(createRandomValueExpression(entry.getValue(), definitions, true, specification)) - .append(","); - } - } - } - - if (payload.toString().endsWith(",")) { - payload.replace(payload.length() - 1, payload.length(), ""); - } - - payload.append("}"); - } else if (OasModelHelper.isArrayType(schema)) { - payload.append("["); - payload.append(createRandomValueExpression((OasSchema) schema.items, definitions, true, specification)); - payload.append("]"); - } else { - payload.append(createRandomValueExpression(schema, definitions, true, specification)); + if (OasModelHelper.isCompositeSchema(schema)) { + createComposedSchema(randomModelBuilder, schema, true, specification, + visitedRefSchemas); + return; } - return payload.toString(); + switch (schema.type) { + case OpenApiConstants.TYPE_OBJECT -> + createRandomObjectSchemeMap(randomModelBuilder, schema, specification, + visitedRefSchemas); + case OpenApiConstants.TYPE_ARRAY -> + createRandomArrayValueMap(randomModelBuilder, schema, specification, + visitedRefSchemas); + case OpenApiConstants.TYPE_STRING, TYPE_INTEGER, OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_BOOLEAN -> + createRandomValueExpressionMap(randomModelBuilder, schema, true); + default -> randomModelBuilder.appendSimple("\"\""); + } } /** * Use test variable with given name if present or create value from schema with random values */ - public static String createRandomValueExpression(String name, OasSchema schema, Map definitions, - boolean quotes, OpenApiSpecification specification, TestContext context) { + public static String createRandomValueExpression(String name, OasSchema schema, + Map definitions, + boolean quotes, OpenApiSpecification specification, TestContext context) { if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } @@ -90,20 +143,12 @@ public static String createRandomValueExpression(String name, OasSchema schema, return createRandomValueExpression(schema, definitions, quotes, specification); } - public static T createRawRandomValueExpression(String name, OasSchema schema, Map definitions, - boolean quotes, OpenApiSpecification specification, TestContext context) { - if (context.getVariables().containsKey(name)) { - return (T)context.getVariables().get(CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX); - } - - return createRawRandomValueExpression(schema, definitions, quotes, specification, context); - } - /** * Create payload from schema with random values. */ - public static String createRandomValueExpression(OasSchema schema, Map definitions, boolean quotes, - OpenApiSpecification specification) { + public static String createRandomValueExpression(OasSchema schema, + Map definitions, boolean quotes, + OpenApiSpecification specification) { if (OasModelHelper.isReferenceType(schema)) { OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); return createRandomValueExpression(resolved, definitions, quotes, specification); @@ -112,31 +157,44 @@ public static String createRandomValueExpression(OasSchema schema, Map "'" + value + "'").collect(Collectors.joining(","))).append(")"); - } else if (schema.format != null && schema.format.equals("uuid")) { + } else if (!isEmpty(schema.enum_)) { + payload.append("citrus:randomEnumValue(").append( + schema.enum_.stream().map(value -> "'" + value + "'") + .collect(Collectors.joining(","))).append(")"); + } else if (OpenApiConstants.FORMAT_UUID.equals(schema.format)) { payload.append("citrus:randomUUID()"); } else { - payload.append("citrus:randomString(").append(schema.maxLength != null && schema.maxLength.intValue() > 0 ? schema.maxLength : (schema.minLength != null && schema.minLength.intValue() > 0 ? schema.minLength : 10)).append(")"); + if (schema.format != null && SPECIAL_FORMATS.containsValue(schema.format)) { + payload.append("citrus:randomValue('") + .append(SPECIAL_FORMATS.get(schema.format)).append("')"); + } else { + int length = 10; + if (schema.maxLength != null && schema.maxLength.intValue() > 0) { + length = schema.maxLength.intValue(); + } else if (schema.minLength != null && schema.minLength.intValue() > 0) { + length = schema.minLength.intValue(); + } + + payload.append("citrus:randomString(").append(length).append(")"); + } } if (quotes) { payload.append("\""); } - } else if ("integer".equals(schema.type) || "number".equals(schema.type)) { + } else if (OpenApiUtils.isAnyNumberScheme(schema)) { payload.append("citrus:randomNumber(8)"); - } else if ("boolean".equals(schema.type)) { + } else if (OpenApiConstants.TYPE_BOOLEAN.equals(schema.type)) { payload.append("citrus:randomEnumValue('true', 'false')"); } else if (quotes) { payload.append("\"\""); @@ -145,69 +203,33 @@ public static String createRandomValueExpression(OasSchema schema, Map T createRawRandomValueExpression(OasSchema schema, Map definitions, boolean quotes, + public static T createRawRandomValueExpression(OasSchema schema, + Map definitions, boolean quotes, OpenApiSpecification specification, TestContext context) { if (OasModelHelper.isReferenceType(schema)) { OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createRawRandomValueExpression(resolved, definitions, quotes, specification, context); + return createRawRandomValueExpression(resolved, definitions, quotes, specification, + context); } StringBuilder payload = new StringBuilder(); - if ("string".equals(schema.type) || OasModelHelper.isObjectType(schema) || OasModelHelper.isArrayType(schema)) { - return (T)createRandomValueExpression(schema, definitions, quotes, specification); - } else if ("number".equals(schema.type)) { - return (T)Double.valueOf(context.replaceDynamicContentInString("citrus:randomNumber(8,2)")); + if (OpenApiConstants.TYPE_STRING.equals(schema.type) || OasModelHelper.isObjectType(schema) + || OasModelHelper.isArrayType(schema)) { + return (T) createRandomValueExpression(schema, definitions, quotes, specification); + } else if (OpenApiConstants.TYPE_NUMBER.equals(schema.type)) { + return (T) Double.valueOf( + context.replaceDynamicContentInString("citrus:randomNumber(8,2)")); } else if ("integer".equals(schema.type)) { - return (T)Double.valueOf(context.replaceDynamicContentInString("citrus:randomNumber(8)")); + return (T) Double.valueOf( + context.replaceDynamicContentInString("citrus:randomNumber(8)")); } else if ("boolean".equals(schema.type)) { - return (T)Boolean.valueOf(context.replaceDynamicContentInString("citrus:randomEnumValue('true', 'false')")); + return (T) Boolean.valueOf( + context.replaceDynamicContentInString("citrus:randomEnumValue('true', 'false')")); } else if (quotes) { payload.append("\"\""); } - return (T)payload.toString(); - } - - /** - * Creates control payload from schema for validation. - */ - public static String createInboundPayload(OasSchema schema, Map definitions, - OpenApiSpecification specification) { - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createInboundPayload(resolved, definitions, specification); - } - - StringBuilder payload = new StringBuilder(); - if (OasModelHelper.isObjectType(schema)) { - payload.append("{"); - - if (schema.properties != null) { - for (Map.Entry entry : schema.properties.entrySet()) { - if (specification.isValidateOptionalFields() || isRequired(schema, entry.getKey())) { - payload.append("\"") - .append(entry.getKey()) - .append("\": ") - .append(createValidationExpression(entry.getValue(), definitions, true, specification)) - .append(","); - } - } - } - - if (payload.toString().endsWith(",")) { - payload.replace(payload.length() - 1, payload.length(), ""); - } - - payload.append("}"); - } else if (OasModelHelper.isArrayType(schema)) { - payload.append("["); - payload.append(createValidationExpression((OasSchema) schema.items, definitions, true, specification)); - payload.append("]"); - } else { - payload.append(createValidationExpression(schema, definitions, false, specification)); - } - - return payload.toString(); + return (T) payload.toString(); } /** @@ -222,182 +244,403 @@ private static boolean isRequired(OasSchema schema, String field) { } /** - * Use test variable with given name if present or create validation expression using functions according to schema type and format. + * Use test variable with given name (if present) or create random value expression using + * functions according to schema type and format. */ - public static String createValidationExpression(String name, OasSchema schema, Map definitions, - boolean quotes, OpenApiSpecification specification, - TestContext context) { + public static String createRandomValueExpression(String name, OasSchema schema, + TestContext context) { if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } - return createValidationExpression(schema, definitions, quotes, specification); + RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); + createRandomValueExpressionMap(randomModelBuilder, schema, false); + return randomModelBuilder.toString(); + } + + public static String createRandomValueExpression(OasSchema schema, boolean quotes) { + RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); + createRandomValueExpressionMap(randomModelBuilder, schema, quotes); + return randomModelBuilder.toString(); } /** - * Create validation expression using functions according to schema type and format. + * Create random value expression using functions according to schema type and format. */ - public static String createValidationExpression(OasSchema schema, Map definitions, boolean quotes, - OpenApiSpecification specification) { - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createValidationExpression(resolved, definitions, quotes, specification); - } + private static void createRandomValueExpressionMap(RandomModelBuilder randomModelBuilder, + OasSchema schema, boolean quotes) { - StringBuilder payload = new StringBuilder(); - if (OasModelHelper.isObjectType(schema)) { - payload.append("{"); - - if (schema.properties != null) { - for (Map.Entry entry : schema.properties.entrySet()) { - if (specification.isValidateOptionalFields() || isRequired(schema, entry.getKey())) { - payload.append("\"") - .append(entry.getKey()) - .append("\": ") - .append(createValidationExpression(entry.getValue(), definitions, quotes, specification)) - .append(","); + switch (schema.type) { + case OpenApiConstants.TYPE_STRING -> { + if (OpenApiConstants.FORMAT_DATE.equals(schema.format)) { + randomModelBuilder.appendSimple( + quote("citrus:currentDate('yyyy-MM-dd')", quotes)); + } else if (OpenApiConstants.FORMAT_DATE_TIME.equals(schema.format)) { + randomModelBuilder.appendSimple( + quote("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')", quotes)); + } else if (hasText(schema.pattern)) { + randomModelBuilder.appendSimple( + quote("citrus:randomValue('" + schema.pattern + "')", quotes)); + } else if (!isEmpty(schema.enum_)) { + randomModelBuilder.appendSimple( + quote("citrus:randomEnumValue(" + (java.lang.String.join(",", schema.enum_)) + + ")", quotes)); + } else if (OpenApiConstants.FORMAT_UUID.equals(schema.format)) { + randomModelBuilder.appendSimple(quote("citrus:randomUUID()", quotes)); + } else { + + if (schema.format != null && SPECIAL_FORMATS.containsKey(schema.format)) { + randomModelBuilder.appendSimple(quote( + "citrus:randomValue('" + SPECIAL_FORMATS.get(schema.format) + "')", + quotes)); + } else { + long minLength = + schema.minLength != null && schema.minLength.longValue() > 0 + ? schema.minLength.longValue() : 10L; + long maxLength = + schema.maxLength != null && schema.maxLength.longValue() > 0 + ? schema.maxLength.longValue() : 10L; + long length = ThreadLocalRandom.current() + .nextLong(minLength, maxLength + 1); + randomModelBuilder.appendSimple( + quote("citrus:randomString(%s)".formatted(length), quotes)); } } } + case OpenApiConstants.TYPE_NUMBER, TYPE_INTEGER -> + // No quotes for numbers + randomModelBuilder.appendSimple(createRandomNumber(schema)); + case OpenApiConstants.TYPE_BOOLEAN -> + // No quotes for boolean + randomModelBuilder.appendSimple("citrus:randomEnumValue('true', 'false')"); + default -> randomModelBuilder.appendSimple(""); + } + } - if (payload.toString().endsWith(",")) { - payload.replace(payload.length() - 1, payload.length(), ""); - } + private static String createRandomNumber(OasSchema schema) { + Number multipleOf = schema.multipleOf; - payload.append("}"); - } else { - if (quotes) { - payload.append("\""); - } + boolean exclusiveMaximum = TRUE.equals(schema.exclusiveMaximum); + boolean exclusiveMinimum = TRUE.equals(schema.exclusiveMinimum); - payload.append(createValidationExpression(schema)); + BigDecimal[] bounds = determineBounds(schema); - if (quotes) { - payload.append("\""); + BigDecimal minimum = bounds[0]; + BigDecimal maximum = bounds[1]; + + if (multipleOf != null) { + minimum = exclusiveMinimum ? incrementToExclude(minimum) : minimum; + maximum = exclusiveMaximum ? decrementToExclude(maximum) : maximum; + return createMultipleOf(minimum, maximum, new BigDecimal(multipleOf.toString())); + } + + return format( + "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s')", + determineDecimalPlaces(schema, minimum, maximum), + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum + ); + } + + /** + * Determines the number of decimal places to use based on the given schema and minimum/maximum values. + * For integer types, it returns 0. For other types, it returns the maximum number of decimal places + * found between the minimum and maximum values, with a minimum of 2 decimal places. + */ + private static int determineDecimalPlaces(OasSchema schema, BigDecimal minimum, + BigDecimal maximum) { + if (TYPE_INTEGER.equals(schema.type)) { + return 0; + } else { + return + Math.max(2, Math.max(findLeastSignificantDecimalPlace(minimum), + findLeastSignificantDecimalPlace(maximum))); + } + } + + /** + * Determine some reasonable bounds for a random number + */ + private static BigDecimal[] determineBounds(OasSchema schema) { + Number maximum = schema.maximum; + Number minimum = schema.minimum; + Number multipleOf = schema.multipleOf; + + BigDecimal bdMinimum; + BigDecimal bdMaximum; + if (minimum == null && maximum == null) { + bdMinimum = MINUS_THOUSAND; + bdMaximum = THOUSAND; + } else if (minimum == null) { + // Determine min relative to max + bdMaximum = new BigDecimal(maximum.toString()); + + if (multipleOf != null) { + bdMinimum = bdMaximum.subtract(new BigDecimal(multipleOf.toString()).abs().multiply( + HUNDRED)); + } else { + bdMinimum = bdMaximum.subtract(bdMaximum.multiply(BigDecimal.valueOf(2)).max( + THOUSAND)); + } + } else if (maximum == null) { + // Determine max relative to min + bdMinimum = new BigDecimal(minimum.toString()); + if (multipleOf != null) { + bdMaximum = bdMinimum.add(new BigDecimal(multipleOf.toString()).abs().multiply( + HUNDRED)); + } else { + bdMaximum = bdMinimum.add(bdMinimum.multiply(BigDecimal.valueOf(2)).max(THOUSAND)); } + } else { + bdMaximum = new BigDecimal(maximum.toString()); + bdMinimum = new BigDecimal(minimum.toString()); } - return payload.toString(); + return new BigDecimal[]{bdMinimum, bdMaximum}; } /** - * Create validation expression using functions according to schema type and format. + * Create a random schema value + * + * @param schema the type to create + * @param visitedRefSchemas the schemas already created during descent, used to avoid recursion */ - private static String createValidationExpression(OasSchema schema) { + private static void createRandomValue(RandomModelBuilder randomModelBuilder, OasSchema schema, + boolean quotes, + OpenApiSpecification specification, Set visitedRefSchemas) { + if (hasText(schema.$ref) && visitedRefSchemas.contains(schema)) { + // Avoid recursion + return; + } + + if (OasModelHelper.isReferenceType(schema)) { + OasSchema resolved = OasModelHelper.getSchemaDefinitions( + specification.getOpenApiDoc(null)) + .get(OasModelHelper.getReferenceName(schema.$ref)); + createRandomValue(randomModelBuilder, resolved, quotes, specification, + visitedRefSchemas); + return; + } if (OasModelHelper.isCompositeSchema(schema)) { - /* - * Currently these schemas are not supported by validation expressions. They are supported - * by {@link org.citrusframework.openapi.validation.OpenApiValidator} though. - */ - return "@ignore@"; + createComposedSchema(randomModelBuilder, schema, quotes, specification, + visitedRefSchemas); + return; } switch (schema.type) { - case "string": - if (schema.format != null && schema.format.equals("date")) { - return "@matchesDatePattern('yyyy-MM-dd')@"; - } else if (schema.format != null && schema.format.equals("date-time")) { - return "@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ssZ')@"; - } else if (StringUtils.hasText(schema.pattern)) { - return String.format("@matches(%s)@", schema.pattern); - } else if (!CollectionUtils.isEmpty(schema.enum_)) { - return String.format("@matches(%s)@", String.join("|", schema.enum_)); + case OpenApiConstants.TYPE_OBJECT -> + createRandomObjectSchemeMap(randomModelBuilder, schema, specification, + visitedRefSchemas); + case OpenApiConstants.TYPE_ARRAY -> + createRandomArrayValueMap(randomModelBuilder, schema, specification, + visitedRefSchemas); + case OpenApiConstants.TYPE_STRING, TYPE_INTEGER, OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_BOOLEAN -> + createRandomValueExpressionMap(randomModelBuilder, schema, quotes); + default -> { + if (quotes) { + randomModelBuilder.appendSimple("\"\""); } else { - return "@notEmpty()@"; + randomModelBuilder.appendSimple(""); } - case "number": - case "integer": - return "@isNumber()@"; - case "boolean": - return "@matches(true|false)@"; - default: - return "@ignore@"; + } } } - /** - * Use test variable with given name (if present) or create random value expression using functions according to - * schema type and format. - */ - public static String createRandomValueExpression(String name, OasSchema schema, TestContext context) { - if (context.getVariables().containsKey(name)) { - return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; + private static void createRandomObjectSchemeMap(RandomModelBuilder randomModelBuilder, + OasSchema objectSchema, + OpenApiSpecification specification, Set visitedRefSchemas) { + + randomModelBuilder.object(() -> { + if (objectSchema.properties != null) { + for (Map.Entry entry : objectSchema.properties.entrySet()) { + if (specification.isGenerateOptionalFields() || isRequired(objectSchema, + entry.getKey())) { + randomModelBuilder.property(entry.getKey(), () -> + createRandomValue(randomModelBuilder, entry.getValue(), true, + specification, + visitedRefSchemas)); + } + } + } + }); + } + + private static void createComposedSchema(RandomModelBuilder randomModelBuilder, + OasSchema schema, boolean quotes, + OpenApiSpecification specification, Set visitedRefSchemas) { + + if (!isEmpty(schema.allOf)) { + createAllOff(randomModelBuilder, schema, quotes, specification, visitedRefSchemas); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.anyOf)) { + createAnyOf(randomModelBuilder, oas30Schema, quotes, specification, visitedRefSchemas); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.oneOf)) { + createOneOf(randomModelBuilder, oas30Schema.oneOf, quotes, specification, + visitedRefSchemas); } + } - return createRandomValueExpression(schema); + private static void createOneOf(RandomModelBuilder randomModelBuilder, List schemas, + boolean quotes, + OpenApiSpecification specification, Set visitedRefSchemas) { + int schemaIndex = ThreadLocalRandom.current().nextInt(schemas.size()); + randomModelBuilder.object(() -> + createRandomValue(randomModelBuilder, schemas.get(schemaIndex), quotes, specification, + visitedRefSchemas)); } - /** - * Create random value expression using functions according to schema type and format. - */ - public static String createRandomValueExpression(OasSchema schema) { - switch (schema.type) { - case "string": - if (schema.format != null && schema.format.equals("date")) { - return "\"citrus:currentDate('yyyy-MM-dd')\""; - } else if (schema.format != null && schema.format.equals("date-time")) { - return "\"citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')\""; - } else if (StringUtils.hasText(schema.pattern)) { - return "\"citrus:randomValue(" + schema.pattern + ")\""; - } else if (!CollectionUtils.isEmpty(schema.enum_)) { - return "\"citrus:randomEnumValue(" + (String.join(",", schema.enum_)) + ")\""; - } else if (schema.format != null && schema.format.equals("uuid")){ - return "citrus:randomUUID()"; - } else { - return "citrus:randomString(10)"; + private static void createAnyOf(RandomModelBuilder randomModelBuilder, Oas30Schema schema, + boolean quotes, + OpenApiSpecification specification, Set visitedRefSchemas) { + + randomModelBuilder.object(() -> { + boolean anyAdded = false; + for (OasSchema oneSchema : schema.anyOf) { + if (ThreadLocalRandom.current().nextBoolean()) { + createRandomValue(randomModelBuilder, oneSchema, quotes, specification, + visitedRefSchemas); + anyAdded = true; } - case "number": - case "integer": - return "citrus:randomNumber(8)"; - case "boolean": - return "citrus:randomEnumValue('true', 'false')"; - default: - return ""; + } + + // Add at least one + if (!anyAdded) { + createOneOf(randomModelBuilder, schema.anyOf, quotes, specification, + visitedRefSchemas); + } + }); + } + + private static Map createAllOff(RandomModelBuilder randomModelBuilder, + OasSchema schema, boolean quotes, + OpenApiSpecification specification, Set visitedRefSchemas) { + Map allOf = new HashMap<>(); + + randomModelBuilder.object(() -> { + for (OasSchema oneSchema : schema.allOf) { + createRandomValue(randomModelBuilder, oneSchema, quotes, specification, + visitedRefSchemas); + } + }); + + return allOf; + } + + private static String createMultipleOf( + BigDecimal minimum, + BigDecimal maximum, + BigDecimal multipleOf + ) { + + BigDecimal lowestMultiple = lowestMultipleOf(minimum, multipleOf); + BigDecimal largestMultiple = largestMultipleOf(maximum, multipleOf); + + // Check if there are no valid multiples in the range + if (lowestMultiple.compareTo(largestMultiple) > 0) { + return null; + } + + BigDecimal range = largestMultiple.subtract(lowestMultiple) + .divide(multipleOf, RoundingMode.DOWN); + + // Don't go for incredible large numbers + if (range.compareTo(BigDecimal.valueOf(11)) > 0) { + range = BigDecimal.valueOf(10); + } + + long factor = 0; + if (range.compareTo(BigDecimal.ZERO) != 0) { + factor = ThreadLocalRandom.current().nextLong(1, range.longValue() + 1); } + BigDecimal randomMultiple = lowestMultiple.add( + multipleOf.multiply(BigDecimal.valueOf(factor))); + randomMultiple = randomMultiple.setScale(findLeastSignificantDecimalPlace(multipleOf), + RoundingMode.HALF_UP); + + return randomMultiple.toString(); } /** - * Create validation expression using regex according to schema type and format. + * Create a random array value. + * + * @param schema the type to create + * @param visitedRefSchemas the schemas already created during descent, used to avoid recursion */ - public static String createValidationRegex(String name, @Nullable OasSchema oasSchema) { - - if (oasSchema != null && (OasModelHelper.isReferenceType(oasSchema) || OasModelHelper.isObjectType(oasSchema))) { - throw new CitrusRuntimeException(String.format("Unable to create a validation regex for an reference of object schema '%s'!", name)); + @SuppressWarnings("rawtypes") + private static void createRandomArrayValueMap(RandomModelBuilder randomModelBuilder, + OasSchema schema, + OpenApiSpecification specification, Set visitedRefSchemas) { + Object items = schema.items; + + if (items instanceof OasSchema itemsSchema) { + createRandomArrayValueWithSchemaItem(randomModelBuilder, schema, itemsSchema, + specification, + visitedRefSchemas); + } else { + throw new UnsupportedOperationException( + "Random array creation for an array with items having different schema is currently not supported!"); } + } - return createValidationRegex(oasSchema); + private static void createRandomArrayValueWithSchemaItem(RandomModelBuilder randomModelBuilder, + OasSchema schema, + OasSchema itemsSchema, OpenApiSpecification specification, + Set visitedRefSchemas) { + Number minItems = schema.minItems; + minItems = minItems != null ? minItems : 1; + Number maxItems = schema.maxItems; + maxItems = maxItems != null ? maxItems : 9; + + int nItems = ThreadLocalRandom.current() + .nextInt(minItems.intValue(), maxItems.intValue() + 1); + + randomModelBuilder.array(() -> { + for (int i = 0; i < nItems; i++) { + createRandomValue(randomModelBuilder, itemsSchema, true, specification, + visitedRefSchemas); + } + }); } - public static String createValidationRegex(@Nullable OasSchema schema) { + static BigDecimal largestMultipleOf(BigDecimal highest, BigDecimal multipleOf) { + RoundingMode roundingMode = + highest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.UP : RoundingMode.DOWN; + BigDecimal factor = highest.divide(multipleOf, 0, roundingMode); + return multipleOf.multiply(factor); + } - if (schema == null) { - return ""; - } + static BigDecimal lowestMultipleOf(BigDecimal lowest, BigDecimal multipleOf) { + RoundingMode roundingMode = + lowest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.DOWN : RoundingMode.UP; + BigDecimal factor = lowest.divide(multipleOf, 0, roundingMode); + return multipleOf.multiply(factor); + } - switch (schema.type) { - case "string": - if (schema.format != null && schema.format.equals("date")) { - return "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"; - } else if (schema.format != null && schema.format.equals("date-time")) { - return "\\d{4}-\\d{2}-\\d{2}T[01]\\d:[0-5]\\d:[0-5]\\dZ"; - } else if (StringUtils.hasText(schema.pattern)) { - return schema.pattern; - } else if (!CollectionUtils.isEmpty(schema.enum_)) { - return "(" + (String.join("|", schema.enum_)) + ")"; - } else if (schema.format != null && schema.format.equals("uuid")){ - return "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; - } else { - return ".*"; - } - case "number": - return "[0-9]+\\.?[0-9]*"; - case "integer": - return "[0-9]+"; - case "boolean": - return "(true|false)"; - default: - return ""; + static BigDecimal incrementToExclude(BigDecimal val) { + return val.add(determineIncrement(val)) + .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); + } + + static BigDecimal decrementToExclude(BigDecimal val) { + return val.subtract(determineIncrement(val)) + .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); + } + + static BigDecimal determineIncrement(BigDecimal number) { + return BigDecimal.valueOf(1.0d / (Math.pow(10d, findLeastSignificantDecimalPlace(number)))); + } + + static int findLeastSignificantDecimalPlace(BigDecimal number) { + number = number.stripTrailingZeros(); + + String[] parts = number.toPlainString().split("\\."); + + if (parts.length == 1) { + return 0; } + + return parts[1].length(); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java new file mode 100644 index 0000000000..3f9e123679 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java @@ -0,0 +1,246 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static org.citrusframework.util.StringUtils.hasText; +import static org.springframework.util.CollectionUtils.isEmpty; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import jakarta.annotation.Nullable; +import java.util.Map; +import org.citrusframework.CitrusSettings; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.openapi.model.OasModelHelper; + +/** + * Generates proper payloads and validation expressions based on Open API specification rules. + * Creates outbound payloads with generated random test data according to specification and creates + * inbound payloads with proper validation expressions to enforce the specification rules. + * + * @author Christoph Deppisch + */ +public abstract class OpenApiTestValidationDataGenerator { + + private OpenApiTestValidationDataGenerator() { + // Static access only + } + + /** + * Creates control payload from schema for validation. + */ + public static String createInboundPayload(OasSchema schema, Map definitions, + OpenApiSpecification specification) { + if (OasModelHelper.isReferenceType(schema)) { + OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); + return createInboundPayload(resolved, definitions, specification); + } + + StringBuilder payload = new StringBuilder(); + if (OasModelHelper.isObjectType(schema)) { + payload.append("{"); + + if (schema.properties != null) { + for (Map.Entry entry : schema.properties.entrySet()) { + if (specification.isValidateOptionalFields() || isRequired(schema, + entry.getKey())) { + payload.append("\"") + .append(entry.getKey()) + .append("\": ") + .append(createValidationExpression(entry.getValue(), definitions, true, + specification)) + .append(","); + } + } + } + + if (payload.toString().endsWith(",")) { + payload.replace(payload.length() - 1, payload.length(), ""); + } + + payload.append("}"); + } else if (OasModelHelper.isArrayType(schema)) { + payload.append("["); + payload.append(createValidationExpression((OasSchema) schema.items, definitions, true, + specification)); + payload.append("]"); + } else { + payload.append(createValidationExpression(schema, definitions, false, specification)); + } + + return payload.toString(); + } + + /** + * Checks if given field name is in list of required fields for this schema. + */ + private static boolean isRequired(OasSchema schema, String field) { + if (schema.required == null) { + return true; + } + + return schema.required.contains(field); + } + + /** + * Use test variable with given name if present or create validation expression using functions + * according to schema type and format. + */ + public static String createValidationExpression(String name, OasSchema schema, + Map definitions, + boolean quotes, OpenApiSpecification specification, + TestContext context) { + if (context.getVariables().containsKey(name)) { + return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; + } + + return createValidationExpression(schema, definitions, quotes, specification); + } + + /** + * Create validation expression using functions according to schema type and format. + */ + public static String createValidationExpression(OasSchema schema, + Map definitions, boolean quotes, + OpenApiSpecification specification) { + if (OasModelHelper.isReferenceType(schema)) { + OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); + return createValidationExpression(resolved, definitions, quotes, specification); + } + + StringBuilder payload = new StringBuilder(); + if (OasModelHelper.isObjectType(schema)) { + payload.append("{"); + + if (schema.properties != null) { + for (Map.Entry entry : schema.properties.entrySet()) { + if (specification.isValidateOptionalFields() || isRequired(schema, + entry.getKey())) { + payload.append("\"") + .append(entry.getKey()) + .append("\": ") + .append( + createValidationExpression(entry.getValue(), definitions, quotes, + specification)) + .append(","); + } + } + } + + if (payload.toString().endsWith(",")) { + payload.replace(payload.length() - 1, payload.length(), ""); + } + + payload.append("}"); + } else { + if (quotes) { + payload.append("\""); + } + + payload.append(createValidationExpression(schema)); + + if (quotes) { + payload.append("\""); + } + } + + return payload.toString(); + } + + /** + * Create validation expression using functions according to schema type and format. + */ + private static String createValidationExpression(OasSchema schema) { + + if (OasModelHelper.isCompositeSchema(schema)) { + /* + * Currently these schemas are not supported by validation expressions. They are supported + * by {@link org.citrusframework.openapi.validation.OpenApiValidator} though. + */ + return "@ignore@"; + } + + switch (schema.type) { + case "string" : + if (schema.format != null && schema.format.equals("date")) { + return "@matchesDatePattern('yyyy-MM-dd')@"; + } else if (schema.format != null && schema.format.equals("date-time")) { + return "@matchesDatePattern('yyyy-MM-dd'T'hh:mm:ssZ')@"; + } else if (hasText(schema.pattern)) { + return String.format("@matches(%s)@", schema.pattern); + } else if (!isEmpty(schema.enum_)) { + return String.format("@matches(%s)@", + String.join("|", schema.enum_)); + } else { + return "@notEmpty()@"; + } + case OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_INTEGER: + return "@isNumber()@"; + case "boolean" : + return "@matches(true|false)@"; + default: + return "@ignore@"; + } + } + + /** + * Create validation expression using regex according to schema type and format. + */ + public static String createValidationRegex(String name, @Nullable OasSchema oasSchema) { + + if (oasSchema != null && (OasModelHelper.isReferenceType(oasSchema) + || OasModelHelper.isObjectType(oasSchema))) { + throw new CitrusRuntimeException(String.format( + "Unable to create a validation regex for an reference of object schema '%s'!", + name)); + } + + return createValidationRegex(oasSchema); + } + + public static String createValidationRegex(@Nullable OasSchema schema) { + + if (schema == null) { + return ""; + } + + switch (schema.type) { + case "string" : + if (schema.format != null && schema.format.equals("date")) { + return "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"; + } else if (schema.format != null && schema.format.equals("date-time")) { + return "\\d{4}-\\d{2}-\\d{2}T[01]\\d:[0-5]\\d:[0-5]\\dZ"; + } else if (hasText(schema.pattern)) { + return schema.pattern; + } else if (!isEmpty(schema.enum_)) { + return "(" + (String.join("|", schema.enum_)) + ")"; + } else if (schema.format != null && schema.format.equals("uuid")) { + return "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; + } else { + return ".*"; + } + case OpenApiConstants.TYPE_NUMBER: + return "[0-9]+\\.?[0-9]*"; + case "integer" : + return "[0-9]+"; + case "boolean" : + return "(true|false)"; + default: + return ""; + } + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index 07ab6bd1c6..616e5b119b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -19,7 +19,12 @@ import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; +import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpClientRequestActionBuilder; @@ -34,17 +39,18 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.regex.Pattern; - /** * @since 4.1 */ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBuilder { - private final OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + private final OpenApiSpecification openApiSpec; + + private final String operationId; + + private boolean oasValidationEnabled = true; + + private OpenApiRequestValidationProcessor openApiRequestValidationProcessor; /** * Default constructor initializes http request message builder. @@ -57,14 +63,23 @@ public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, OpenApiSpecifi String operationId) { super(new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage); - openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); - process(openApiRequestValidationProcessor); - } + this.openApiSpec = openApiSpec; + this.operationId = operationId; + } + + @Override + public SendMessageAction doBuild() { - public OpenApiClientRequestActionBuilder disableOasValidation(boolean b) { - if (openApiRequestValidationProcessor != null) { - openApiRequestValidationProcessor.setEnabled(!b); + if (oasValidationEnabled && !messageProcessors.contains(openApiRequestValidationProcessor)) { + openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); + process(openApiRequestValidationProcessor); } + + return super.doBuild(); + } + + public OpenApiClientRequestActionBuilder disableOasValidation(boolean disabled) { + oasValidationEnabled = !disabled; return this; } @@ -117,7 +132,7 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter if (context.getVariables().containsKey(parameter.getName())) { parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; } else { - parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema); + parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema, false); } randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") .matcher(randomizedPath) @@ -171,4 +186,5 @@ private void setSpecifiedHeaders(TestContext context, OasOperation operation) { }); } } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index de3998e10e..3bc4b9d1c4 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -20,7 +20,12 @@ import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; +import java.util.Collection; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; +import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpClientResponseActionBuilder; @@ -29,7 +34,7 @@ import org.citrusframework.message.Message; import org.citrusframework.message.MessageType; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.OpenApiTestDataGenerator; +import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; @@ -37,17 +42,18 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; - /** * @since 4.1 */ public class OpenApiClientResponseActionBuilder extends HttpClientResponseActionBuilder { - private final OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + private OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + + private final OpenApiSpecification openApiSpec; + + private final String operationId; + + private boolean oasValidationEnabled = true; /** * Default constructor initializes http response message builder. @@ -62,15 +68,24 @@ public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, String operationId, String statusCode) { super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpec, operationId, statusCode), httpMessage); - - openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); - validate(openApiResponseValidationProcessor); + this.openApiSpec = openApiSpec; + this.operationId = operationId; } - public OpenApiClientResponseActionBuilder disableOasValidation(boolean b) { - if (openApiResponseValidationProcessor != null) { - openApiResponseValidationProcessor.setEnabled(!b); + @Override + public ReceiveMessageAction doBuild() { + + if (oasValidationEnabled && !messageProcessors.contains(openApiResponseValidationProcessor)) { + openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); + validate(openApiResponseValidationProcessor); } + + return super.doBuild(); + } + + public OpenApiClientResponseActionBuilder disableOasValidation(boolean disable) { + oasValidationEnabled = !disable; + ((OpenApiClientResponseMessageBuilder)getMessageBuilderSupport().getMessageBuilder()).setOasValidationEnabled(oasValidationEnabled); return this; } @@ -88,12 +103,10 @@ public static void fillMessageFromResponse(OpenApiSpecification openApiSpecifica Optional responseSchema = OasModelHelper.getSchema(response); responseSchema.ifPresent(oasSchema -> { httpMessage.setPayload( - OpenApiTestDataGenerator.createInboundPayload(oasSchema, + OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions( openApiSpecification.getOpenApiDoc(context)), openApiSpecification)); - // Best guess for the content type. Currently, we can only determine the content type - // for sure for json. Other content types will be neglected. OasSchema resolvedSchema = OasModelHelper.resolveSchema( openApiSpecification.getOpenApiDoc(null), oasSchema); if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType( @@ -108,7 +121,6 @@ public static void fillMessageFromResponse(OpenApiSpecification openApiSpecifica } } ); - } private static void fillRequiredHeaders( @@ -118,7 +130,7 @@ private static void fillRequiredHeaders( Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); for (Map.Entry header : requiredHeaders.entrySet()) { httpMessage.setHeader(header.getKey(), - OpenApiTestDataGenerator.createValidationExpression(header.getKey(), + OpenApiTestValidationDataGenerator.createValidationExpression(header.getKey(), header.getValue(), OasModelHelper.getSchemaDefinitions( openApiSpecification.getOpenApiDoc(context)), false, @@ -145,6 +157,8 @@ private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuil private final HttpMessage httpMessage; + private boolean oasValidationEnabled = true; + public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, String operationId, String statusCode) { @@ -169,7 +183,7 @@ public Message build(TestContext context, String messageType) { private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { OasOperation operation = operationPathAdapter.operation(); - if (operation.responses != null) { + if (oasValidationEnabled && operation.responses != null) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( openApiSpec.getOpenApiDoc(context), operation, statusCode, null); @@ -184,5 +198,9 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter httpMessage.status(HttpStatus.OK); } } + + public void setOasValidationEnabled(boolean oasValidationEnabled) { + this.oasValidationEnabled = oasValidationEnabled; + } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java index 9d93fd2326..bfb8c4ea5c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java @@ -16,10 +16,23 @@ package org.citrusframework.openapi.actions; +import static java.lang.String.format; +import static org.citrusframework.message.MessageType.JSON; +import static org.citrusframework.message.MessageType.PLAINTEXT; +import static org.citrusframework.message.MessageType.XML; +import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; +import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpServerRequestActionBuilder; @@ -27,32 +40,25 @@ import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.OpenApiTestDataGenerator; +import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.validation.OpenApiRequestValidationProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import java.util.List; -import java.util.Optional; -import java.util.regex.Pattern; - -import static java.lang.String.format; -import static org.citrusframework.message.MessageType.JSON; -import static org.citrusframework.message.MessageType.PLAINTEXT; -import static org.citrusframework.message.MessageType.XML; -import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; -import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; - /** * @since 4.1 */ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBuilder { - private final OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + private OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + + private final OpenApiSpecification openApiSpec; + + private final String operationId; + + private boolean oasValidationEnabled = true; /** * Default constructor initializes http request message builder. @@ -66,15 +72,23 @@ public OpenApiServerRequestActionBuilder(HttpMessage httpMessage, String operationId) { super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage); - - openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); - validate(openApiRequestValidationProcessor); + this.openApiSpec = openApiSpec; + this.operationId = operationId; } - public OpenApiServerRequestActionBuilder disableOasValidation(boolean b) { - if (openApiRequestValidationProcessor != null) { - openApiRequestValidationProcessor.setEnabled(!b); + @Override + public ReceiveMessageAction doBuild() { + + if (oasValidationEnabled && !messageProcessors.contains(openApiRequestValidationProcessor)) { + openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); + validate(openApiRequestValidationProcessor); } + + return super.doBuild(); + } + + public OpenApiServerRequestActionBuilder disableOasValidation(boolean disable) { + oasValidationEnabled = !disable; return this; } @@ -142,7 +156,7 @@ private void setSpecifiedBody(TestContext context, OperationPathAdapter operatio Optional body = OasModelHelper.getRequestBodySchema( openApiSpec.getOpenApiDoc(context), operationPathAdapter.operation()); body.ifPresent(oasSchema -> httpMessage.setPayload( - OpenApiTestDataGenerator.createInboundPayload(oasSchema, + OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions( openApiSpec.getOpenApiDoc(context)), openApiSpec))); } @@ -161,7 +175,7 @@ private String determinePath(TestContext context, OasOperation operation, .matcher(randomizedPath) .replaceAll(parameterValue); } else { - parameterValue = OpenApiTestDataGenerator.createValidationRegex( + parameterValue = OpenApiTestValidationDataGenerator.createValidationRegex( parameter.getName(), OasModelHelper.getParameterSchema(parameter).orElse(null)); @@ -188,7 +202,7 @@ private void setSpecifiedQueryParameters(TestContext context, param -> (param.required != null && param.required) || context.getVariables() .containsKey(param.getName())) .forEach(param -> httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createValidationExpression(param.getName(), + OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, openApiSpec, @@ -209,7 +223,7 @@ private void setSpecifiedHeaders(TestContext context, param -> (param.required != null && param.required) || context.getVariables() .containsKey(param.getName())) .forEach(param -> httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createValidationExpression(param.getName(), + OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, openApiSpec, diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index 2c673b711a..d5914d336e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -16,11 +16,29 @@ package org.citrusframework.openapi.actions; +import static java.lang.Integer.parseInt; +import static java.util.Collections.singletonMap; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; +import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpServerResponseActionBuilder; @@ -37,30 +55,18 @@ import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; import org.springframework.http.HttpStatus; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Pattern; - -import static java.lang.Integer.parseInt; -import static java.util.Collections.singletonMap; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; - /** * @since 4.1 */ public class OpenApiServerResponseActionBuilder extends HttpServerResponseActionBuilder { - private final OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + private OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + + private final OpenApiSpecification openApiSpec; + + private final String operationId; + + private boolean oasValidationEnabled = true; /** * Default constructor initializes http response message builder. @@ -75,16 +81,23 @@ public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, String operationId, String statusCode, String accept) { super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpec, operationId, statusCode, accept), httpMessage); - - openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, - operationId); - process(openApiResponseValidationProcessor); + this.openApiSpec = openApiSpec; + this.operationId = operationId; } - public OpenApiServerResponseActionBuilder disableOasValidation(boolean b) { - if (openApiResponseValidationProcessor != null) { - openApiResponseValidationProcessor.setEnabled(!b); + @Override + public SendMessageAction doBuild() { + + if (oasValidationEnabled && !messageProcessors.contains(openApiResponseValidationProcessor)) { + openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); + process(openApiResponseValidationProcessor); } + + return super.doBuild(); + } + + public OpenApiServerResponseActionBuilder disableOasValidation(boolean disable) { + oasValidationEnabled = !disable; return this; } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index 854f8f743d..cfbffdf139 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,6 +16,10 @@ package org.citrusframework.openapi.model; +import static java.util.Collections.singletonList; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; + import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; @@ -36,11 +40,6 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import jakarta.annotation.Nullable; -import org.citrusframework.openapi.model.v2.Oas20ModelHelper; -import org.citrusframework.openapi.model.v3.Oas30ModelHelper; -import org.citrusframework.util.StringUtils; -import org.springframework.http.MediaType; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -53,12 +52,14 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; - -import static java.util.Collections.singletonList; +import org.citrusframework.openapi.model.v2.Oas20ModelHelper; +import org.citrusframework.openapi.model.v3.Oas30ModelHelper; +import org.citrusframework.util.StringUtils; +import org.springframework.http.MediaType; public final class OasModelHelper { - public static final String DEFAULT_ = "default_"; + public static final String DEFAULT = "default_"; /** * List of preferred media types in the order of priority, @@ -76,7 +77,7 @@ private OasModelHelper() { * @return true if given schema is an object. */ public static boolean isObjectType(@Nullable OasSchema schema) { - return schema != null && "object".equals(schema.type); + return schema != null && TYPE_OBJECT.equals(schema.type); } /** @@ -85,7 +86,7 @@ public static boolean isObjectType(@Nullable OasSchema schema) { * @return true if given schema is an array. */ public static boolean isArrayType(@Nullable OasSchema schema) { - return schema != null && "array".equals(schema.type); + return schema != null && TYPE_ARRAY.equals(schema.type); } /** @@ -95,7 +96,7 @@ public static boolean isArrayType(@Nullable OasSchema schema) { */ public static boolean isObjectArrayType(@Nullable OasSchema schema) { - if (schema == null || !"array".equals(schema.type)) { + if (schema == null || !TYPE_ARRAY.equals(schema.type)) { return false; } @@ -290,7 +291,7 @@ public static Optional getResponseForRandomGeneration(OasDocument o Predicate acceptedSchemas = resp -> getSchema(operation, resp, accept != null ? singletonList(accept) : DEFAULT_ACCEPTED_MEDIA_TYPES).isPresent(); // Fallback 1: Pick the default if it exists - Optional response = Optional.ofNullable(responseMap.get(DEFAULT_)); + Optional response = Optional.ofNullable(responseMap.get(DEFAULT)); if (response.isEmpty()) { // Fallback 2: Pick the response object related to the first 2xx, providing an accepted schema @@ -463,7 +464,7 @@ private static boolean isOas20(OasDocument openApiDoc) { * This method iterates over the responses contained in the {@link OasResponses} object. If a response has a reference * (indicated by a non-null {@code $ref} field), it resolves the reference and adds the resolved response to the result list. * Non-referenced responses are added to the result list as-is. The resulting map includes the default response under - * the key {@link OasModelHelper#DEFAULT_}, if it exists. + * the key {@link OasModelHelper#DEFAULT}, if it exists. *

* * @param responses the {@link OasResponses} instance containing the responses to be resolved. @@ -491,10 +492,10 @@ private static Map resolveResponses(OasDocument openApiDoc, if (responses.default_.$ref != null) { OasResponse resolved = responseResolver.apply(responses.default_.$ref); if (resolved != null) { - responseMap.put(DEFAULT_, resolved); + responseMap.put(DEFAULT, resolved); } } else { - responseMap.put(DEFAULT_, responses.default_); + responseMap.put(DEFAULT, responses.default_); } } @@ -504,8 +505,8 @@ private static Map resolveResponses(OasDocument openApiDoc, private static Function getResponseResolver( OasDocument openApiDoc) { return delegate(openApiDoc, - (Function>) doc -> (responseRef -> doc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))), - (Function>) doc -> (responseRef -> doc.components.responses.get(OasModelHelper.getReferenceName(responseRef)))); + doc -> (responseRef -> doc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))), + doc -> (responseRef -> doc.components.responses.get(OasModelHelper.getReferenceName(responseRef)))); } /** diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java index 987ed05c90..c1a1999ac9 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -17,7 +17,7 @@ package org.citrusframework.openapi.model; import io.apicurio.datamodels.openapi.models.OasOperation; -import org.citrusframework.openapi.OpenApiUtils; +import org.citrusframework.openapi.util.OpenApiUtils; import static java.lang.String.format; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java similarity index 79% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java index 21fe3d32cc..dd6e48deb7 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiUtils.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java @@ -14,16 +14,18 @@ * limitations under the License. */ -package org.citrusframework.openapi; +package org.citrusframework.openapi.util; + +import static java.lang.String.format; import io.apicurio.datamodels.openapi.models.OasOperation; +import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nonnull; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.OpenApiConstants; import org.citrusframework.util.StringUtils; -import static java.lang.String.format; - public class OpenApiUtils { private OpenApiUtils() { @@ -35,7 +37,7 @@ public static String getMethodPath(@Nonnull HttpMessage httpMessage) { Object path = httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI); return getMethodPath(methodHeader != null ? methodHeader.toString().toLowerCase() : "null", - path != null? path.toString() : "null"); + path != null ? path.toString() : "null"); } public static String getMethodPath(@Nonnull String method, @Nonnull String path) { @@ -52,4 +54,12 @@ public static String createFullPathOperationIdentifier(String path, OasOperation return format("%s_%s", oasOperation.getMethod().toUpperCase(), path); } + public static boolean isAnyNumberScheme(OasSchema schema) { + return ( + schema != null && + (OpenApiConstants.TYPE_INTEGER.equalsIgnoreCase(schema.type) || + OpenApiConstants.TYPE_NUMBER.equalsIgnoreCase(schema.type)) + ); + } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java new file mode 100644 index 0000000000..4a31733459 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java @@ -0,0 +1,116 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.util; + +import java.util.ArrayList; +import java.util.LinkedHashMap; + +/** + * Interface representing a random element in a JSON structure. This interface provides default + * methods to push values into the element, which can be overridden by implementing classes. + */ +public interface RandomElement { + + default void push(Object value) { + throw new UnsupportedOperationException(); + } + + default void push(String key, Object value) { + throw new UnsupportedOperationException(); + } + + /** + * A random element representing an array. Array elements can be of type String (native + * attribute) or {@link RandomElement}. + */ + class RandomList extends ArrayList implements RandomElement { + + @Override + public void push(Object value) { + add(value); + } + + @Override + public void push(String key, Object value) { + if (!isEmpty()) { + Object lastElement = get(size() - 1); + if (lastElement instanceof RandomElement randomElement) { + randomElement.push(key, value); + } + } + } + } + + /** + * A random object representing a JSON object, with attributes stored as key-value pairs. Values + * are of type String (simple attributes) or {@link RandomElement}. + */ + class RandomObject extends LinkedHashMap implements RandomElement { + + @Override + public void push(String key, Object value) { + put(key, value); + } + + @Override + public void push(Object value) { + if (value instanceof RandomObject randomObject) { + this.putAll(randomObject); + return; + } + RandomElement.super.push(value); + } + } + + /** + * A random value that either holds a String (simple property) or a random element. + */ + class RandomValue implements RandomElement { + + private Object value; + + public RandomValue() { + } + + public RandomValue(Object value) { + this.value = value; + } + + public Object getValue() { + return value; + } + + @Override + public void push(Object pushedValue) { + if (value instanceof RandomElement randomElement) { + randomElement.push(pushedValue); + } else { + this.value = pushedValue; + } + } + + @Override + public void push(String key, Object pushedValue) { + if (value instanceof RandomElement randomElement) { + randomElement.push(key, pushedValue); + } else { + throw new IllegalStateException("Cannot push key/value to value: " + value); + } + } + + } +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java new file mode 100644 index 0000000000..43346b388a --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java @@ -0,0 +1,109 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.util; + +import java.util.ArrayDeque; +import java.util.Deque; +import org.citrusframework.openapi.util.RandomElement.RandomList; +import org.citrusframework.openapi.util.RandomElement.RandomObject; +import org.citrusframework.openapi.util.RandomElement.RandomValue; + +/** + * RandomModelBuilder is a class for building random JSON models. It supports adding + * simple values, objects, properties, and arrays to the JSON structure. The final + * model can be converted to a JSON string using the `writeToJson` method. I + *

+ * The builder is able to build nested structures and can also handle native string, + * number, and boolean elements, represented as functions for later dynamic string + * conversion by Citrus. + *

+ * Example usage: + *

+ * RandomModelBuilder builder = new RandomModelBuilder();
+ * builder.object(() -> {
+ *     builder.property("key1", () -> builder.appendSimple("value1"));
+ *     builder.property("key2", () -> builder.array(() -> {
+ *         builder.appendSimple("value2");
+ *         builder.appendSimple("value3");
+ *     }));
+ * });
+ * String json = builder.writeToJson();
+ * 
+ */ +public class RandomModelBuilder { + + final Deque deque = new ArrayDeque<>(); + + public RandomModelBuilder() { + deque.push(new RandomValue()); + } + + public String toString() { + return RandomModelWriter.toString(this); + } + + public void appendSimple(String nativeValue) { + if (deque.isEmpty()) { + deque.push(new RandomValue(nativeValue)); + } else { + deque.peek().push(nativeValue); + } + } + + public void object(Runnable objectBuilder) { + if (deque.isEmpty()) { + throwIllegalState(); + } + + RandomObject randomObject = new RandomObject(); + deque.peek().push(randomObject); + objectBuilder.run(); + } + + private static void throwIllegalState() { + throw new IllegalStateException("Encountered empty stack!"); + } + + public void property(String key, Runnable valueBuilder) { + if (deque.isEmpty()) { + throwIllegalState(); + } + + RandomValue randomValue = new RandomValue(); + deque.peek().push(key, randomValue); + + deque.push(randomValue); + valueBuilder.run(); + deque.pop(); + } + + public void array(Runnable arrayBuilder) { + if (deque.isEmpty()) { + throwIllegalState(); + } + RandomList randomList = new RandomList(); + deque.peek().push(randomList); + + // For a list, we need to push the list to the queue. This is because when the builder adds elements + // to the list, and we are dealing with nested lists, we can otherwise not distinguish whether to put + // an element into the list or into the nested list. + deque.push(randomList); + arrayBuilder.run(); + deque.pop(); + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java new file mode 100644 index 0000000000..11960d0973 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java @@ -0,0 +1,115 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.util; + +import static org.citrusframework.util.StringUtils.trimTrailingComma; + +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import org.citrusframework.openapi.util.RandomElement.RandomValue; + +/** + * Utility class for converting a {@link RandomModelBuilder} to its string representation. + * This class provides static methods to serialize the model built by {@link RandomModelBuilder}. + */ +class RandomModelWriter { + + private RandomModelWriter() { + // static access only + } + + static String toString(RandomModelBuilder randomModelBuilder) { + + StringBuilder builder = new StringBuilder(); + appendObject(builder, randomModelBuilder.deque); + return builder.toString(); + } + + private static void appendObject(StringBuilder builder, Object object) { + + if (object instanceof Deque deque) { + while (!deque.isEmpty()) { + appendObject(builder, deque.pop()); + } + return; + } + if (object instanceof Map map) { + //noinspection unchecked + appendMap(builder, (Map) map); + } else if (object instanceof List list) { + appendArray(builder, list); + } else if (object instanceof String string) { + builder.append(string); + } else if (object instanceof RandomValue randomValue) { + appendObject(builder, randomValue.getValue()); + } + } + + private static void appendArray(StringBuilder builder, List list) { + builder.append("["); + list.forEach(listValue -> { + appendObject(builder, listValue); + builder.append(","); + }); + trimTrailingComma(builder); + builder.append("]"); + } + + private static void appendMap(StringBuilder builder, Map map) { + if (map.size() == 1) { + Entry entry = map.entrySet().iterator().next(); + String key = entry.getKey(); + Object value = entry.getValue(); + + if ("ARRAY".equals(key)) { + appendObject(builder, value); + } else if ("NATIVE".equals(key)) { + builder.append(value); + } else { + appendJsonObject(builder, map); + } + } else { + appendJsonObject(builder, map); + } + } + + private static void appendJsonObject(StringBuilder builder, Map map) { + builder.append("{"); + for (Entry entry : map.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + builder.append("\""); + builder.append(key); + builder.append("\": "); + + if (value instanceof String) { + builder.append(value); + } else if (value instanceof Map) { + appendObject(builder, value); + } else if (value instanceof RandomValue randomValue) { + appendObject(builder, randomValue.getValue()); + } + + builder.append(","); + } + trimTrailingComma(builder); + + builder.append("}"); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java index b640adb365..cb14d44c89 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java @@ -33,28 +33,25 @@ public class OpenApiRequestValidationProcessor implements private final String operationId; - private boolean enabled = true; + private final OpenApiRequestValidator openApiRequestValidator; public OpenApiRequestValidationProcessor(OpenApiSpecification openApiSpecification, String operationId) { - this.operationId = operationId; this.openApiSpecification = openApiSpecification; + this.operationId = operationId; + this.openApiRequestValidator = new OpenApiRequestValidator(openApiSpecification); } - @Override public void validate(Message message, TestContext context) { - if (!enabled || !(message instanceof HttpMessage httpMessage)) { + if (!(message instanceof HttpMessage httpMessage)) { return; } + openApiSpecification.getOperation( operationId, context).ifPresent(operationPathAdapter -> - openApiSpecification.getRequestValidator().ifPresent(openApiRequestValidator -> - openApiRequestValidator.validateRequest(operationPathAdapter, httpMessage))); + openApiRequestValidator.validateRequest(operationPathAdapter, httpMessage)); } - public void setEnabled(boolean b) { - this.enabled = b; - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java index bef2c35230..94aa08ae9a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -16,28 +16,27 @@ package org.citrusframework.openapi.validation; -import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.SimpleRequest; import com.atlassian.oai.validator.report.ValidationReport; +import java.util.ArrayList; +import java.util.Collection; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.http.message.HttpMessageUtils; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import java.util.ArrayList; -import java.util.Collection; - -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledlobally; - /** * Specific validator that uses atlassian and is responsible for validating HTTP requests * against an OpenAPI specification using the provided {@code OpenApiInteractionValidator}. */ public class OpenApiRequestValidator extends OpenApiValidator { - public OpenApiRequestValidator(OpenApiInteractionValidator openApiInteractionValidator) { - super(openApiInteractionValidator, isRequestValidationEnabledlobally()); + public OpenApiRequestValidator(OpenApiSpecification openApiSpecification) { + super(openApiSpecification); + setEnabled(openApiSpecification.getSwaggerOpenApiValidationContext() != null && openApiSpecification.getSwaggerOpenApiValidationContext().isRequestValidationEnabled()); } @Override @@ -79,7 +78,7 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, SimpleRequest.Builder finalRequestBuilder = requestBuilder; finalRequestBuilder.withAccept(httpMessage.getAccept()); - httpMessage.getQueryParams() + HttpMessageUtils.getQueryParameterMap(httpMessage) .forEach((key, value) -> finalRequestBuilder.withQueryParam(key, new ArrayList<>( value))); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java index 18754062f1..c098fda6a0 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java @@ -23,7 +23,8 @@ import org.citrusframework.validation.ValidationProcessor; /** - * {@code ValidationProcessor} that delegates validation of OpenApi responses to instances of {@link OpenApiResponseValidator}. + * {@code ValidationProcessor} that delegates validation of OpenApi responses to instances of + * {@link OpenApiResponseValidator}. */ public class OpenApiResponseValidationProcessor implements ValidationProcessor { @@ -32,27 +33,25 @@ public class OpenApiResponseValidationProcessor implements private final String operationId; - private boolean enabled = true; + private final OpenApiResponseValidator openApiResponseValidator; - public OpenApiResponseValidationProcessor(OpenApiSpecification openApiSpecification, String operationId) { + public OpenApiResponseValidationProcessor(OpenApiSpecification openApiSpecification, + String operationId) { this.operationId = operationId; this.openApiSpecification = openApiSpecification; + this.openApiResponseValidator = new OpenApiResponseValidator(openApiSpecification); } @Override public void validate(Message message, TestContext context) { - if (!enabled || !(message instanceof HttpMessage httpMessage)) { + if (!(message instanceof HttpMessage httpMessage)) { return; } openApiSpecification.getOperation( operationId, context).ifPresent(operationPathAdapter -> - openApiSpecification.getResponseValidator().ifPresent(openApiResponseValidator -> - openApiResponseValidator.validateResponse(operationPathAdapter, httpMessage))); + openApiResponseValidator.validateResponse(operationPathAdapter, httpMessage)); } - public void setEnabled(boolean b) { - this.enabled = b; - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java index 9aba9b0764..faefe24a9b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -16,26 +16,25 @@ package org.citrusframework.openapi.validation; -import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.model.Response; import com.atlassian.oai.validator.model.SimpleResponse; import com.atlassian.oai.validator.report.ValidationReport; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; import org.springframework.http.HttpStatusCode; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; - /** * Specific validator, that facilitates the use of Atlassian's Swagger Request Validator, * and delegates validation of OpenApi requests to instances of {@link OpenApiRequestValidator}. */ public class OpenApiResponseValidator extends OpenApiValidator { - public OpenApiResponseValidator(OpenApiInteractionValidator openApiInteractionValidator) { - super(openApiInteractionValidator, isResponseValidationEnabledGlobally()); + public OpenApiResponseValidator(OpenApiSpecification openApiSpecification) { + super(openApiSpecification); + setEnabled(openApiSpecification.getSwaggerOpenApiValidationContext() != null && openApiSpecification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); } @Override diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java index a6bc2e98c8..c5393f8051 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java @@ -18,6 +18,7 @@ import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.report.ValidationReport; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; public abstract class OpenApiValidator { @@ -26,9 +27,14 @@ public abstract class OpenApiValidator { protected boolean enabled; - protected OpenApiValidator(OpenApiInteractionValidator openApiInteractionValidator, boolean enabled) { - this.openApiInteractionValidator = openApiInteractionValidator; - this.enabled = enabled; + protected OpenApiValidator(OpenApiSpecification openApiSpecification) { + SwaggerOpenApiValidationContext swaggerOpenApiValidationContext = openApiSpecification.getSwaggerOpenApiValidationContext(); + if (swaggerOpenApiValidationContext != null) { + openApiInteractionValidator = openApiSpecification.getSwaggerOpenApiValidationContext() + .getOpenApiInteractionValidator(); + } else { + openApiInteractionValidator = null; + } } public void setEnabled(boolean enabled) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java new file mode 100644 index 0000000000..ad9dbcf23e --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java @@ -0,0 +1,77 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; + +import com.atlassian.oai.validator.OpenApiInteractionValidator; +import com.atlassian.oai.validator.report.MessageResolver; +import com.atlassian.oai.validator.schema.SchemaValidator; +import com.atlassian.oai.validator.schema.SwaggerV20Library; +import io.swagger.v3.oas.models.OpenAPI; + +public class SwaggerOpenApiValidationContext { + + private final OpenAPI openApi; + + private OpenApiInteractionValidator openApiInteractionValidator; + + private SchemaValidator schemaValidator; + + private boolean responseValidationEnabled = isResponseValidationEnabledGlobally(); + + private boolean requestValidationEnabled = isRequestValidationEnabledGlobally(); + + public SwaggerOpenApiValidationContext(OpenAPI openApi) { + this.openApi = openApi; + } + + public OpenAPI getSwaggerOpenApi() { + return openApi; + } + + public synchronized OpenApiInteractionValidator getOpenApiInteractionValidator() { + if (openApiInteractionValidator == null) { + openApiInteractionValidator = new OpenApiInteractionValidator.Builder().withApi(openApi).build(); + } + return openApiInteractionValidator; + } + + public synchronized SchemaValidator getSchemaValidator() { + if (schemaValidator == null) { + schemaValidator = new SchemaValidator(openApi, new MessageResolver(), SwaggerV20Library::schemaFactory); + } + return schemaValidator; + } + + public boolean isResponseValidationEnabled() { + return responseValidationEnabled; + } + + public void setResponseValidationEnabled(boolean responseValidationEnabled) { + this.responseValidationEnabled = responseValidationEnabled; + } + + public boolean isRequestValidationEnabled() { + return requestValidationEnabled; + } + + public void setRequestValidationEnabled(boolean requestValidationEnabled) { + this.requestValidationEnabled = requestValidationEnabled; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java new file mode 100644 index 0000000000..51d0ba4412 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java @@ -0,0 +1,78 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import com.atlassian.oai.validator.OpenApiInteractionValidator.SpecSource; +import com.atlassian.oai.validator.util.OpenApiLoader; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.parser.core.models.ParseOptions; +import jakarta.annotation.Nonnull; +import java.net.URL; +import java.util.Collections; +import org.citrusframework.openapi.OpenApiResourceLoader; +import org.citrusframework.spi.Resource; + +/** + * Utility class for loading Swagger OpenAPI specifications from various resources. + */ +public abstract class SwaggerOpenApiValidationContextLoader { + + private SwaggerOpenApiValidationContextLoader() { + // Static access only + } + /** + * Loads an OpenAPI specification from a secured web resource. + * + * @param url the URL of the secured web resource + * @return the loaded OpenAPI specification + */ + public static SwaggerOpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), Collections.emptyList(), defaultParseOptions())); + } + + /** + * Loads an OpenAPI specification from a web resource. + * + * @param url the URL of the web resource + * @return the loaded OpenAPI specification + */ + public static SwaggerOpenApiValidationContext fromWebResource(@Nonnull URL url) { + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), Collections.emptyList(), defaultParseOptions())); + } + + /** + * Loads an OpenAPI specification from a file. + * + * @param resource the file resource containing the OpenAPI specification + * @return the loaded OpenAPI specification + */ + public static SwaggerOpenApiValidationContext fromFile(@Nonnull Resource resource) { + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), Collections.emptyList(), defaultParseOptions())); + } + + private static SwaggerOpenApiValidationContext createValidationContext(OpenAPI openApi) { + return new SwaggerOpenApiValidationContext(openApi); + } + + private static ParseOptions defaultParseOptions() { + final ParseOptions parseOptions = new ParseOptions(); + parseOptions.setResolve(true); + parseOptions.setResolveFully(true); + parseOptions.setResolveCombinators(false); + return parseOptions; + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java index d4e448ec26..41f612b495 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi; import org.testng.annotations.AfterMethod; @@ -17,7 +33,7 @@ public class OpenApiSettingsTest { private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); - private static final boolean REQUEST_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isRequestValidationEnabledlobally(); + private static final boolean REQUEST_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isRequestValidationEnabledGlobally(); private static final boolean RESPONSE_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isResponseValidationEnabledGlobally(); @@ -66,33 +82,33 @@ public void afterMethod() throws Exception { public void testRequestValidationEnabledByProperty() throws Exception { environmentVariables.setup(); System.setProperty(REQUEST_VALIDATION_ENABLED_PROPERTY, "true"); - assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + assertTrue(OpenApiSettings.isRequestValidationEnabledGlobally()); } @Test public void testRequestValidationDisabledByProperty() throws Exception { environmentVariables.setup(); System.setProperty(REQUEST_VALIDATION_ENABLED_PROPERTY, "false"); - assertFalse(OpenApiSettings.isRequestValidationEnabledlobally()); + assertFalse(OpenApiSettings.isRequestValidationEnabledGlobally()); } @Test public void testRequestValidationEnabledByEnvVar() throws Exception { environmentVariables.set(OpenApiSettings.REQUEST_VALIDATION_ENABLED_ENV, "true"); environmentVariables.setup(); - assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + assertTrue(OpenApiSettings.isRequestValidationEnabledGlobally()); } @Test public void testRequestValidationDisabledByEnvVar() throws Exception { environmentVariables.set(OpenApiSettings.REQUEST_VALIDATION_ENABLED_ENV, "false"); environmentVariables.setup(); - assertFalse(OpenApiSettings.isRequestValidationEnabledlobally()); + assertFalse(OpenApiSettings.isRequestValidationEnabledGlobally()); } @Test public void testRequestValidationEnabledByDefault() { - assertTrue(OpenApiSettings.isRequestValidationEnabledlobally()); + assertTrue(OpenApiSettings.isRequestValidationEnabledGlobally()); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index 05f22c522a..668ecb9b64 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi; import io.apicurio.datamodels.openapi.models.OasDocument; @@ -38,7 +54,6 @@ public class OpenApiSpecificationTest { - private static final String PING_API_HTTP_URL_STRING = "http://org.citrus.example.com/ping-api.yaml"; private static final String PING_API_HTTPS_URL_STRING = "https://org.citrus.example.com/ping-api.yaml"; @@ -85,27 +100,13 @@ public void tearDown() throws Exception { mockCloseable.close(); } - @Test - public void shouldInitializeFromSpecUrl() { - - // When - OpenApiSpecification specification = OpenApiSpecification.from(PING_API_HTTP_URL_STRING); - - // Then - assertNotNull(specification); - assertEquals(specification.getSpecUrl(), PING_API_HTTP_URL_STRING); - assertTrue(specification.getRequestValidator().isEmpty()); - assertTrue(specification.getResponseValidator().isEmpty()); - - } - @DataProvider(name = "protocollDataProvider") public static Object[][] protocolls() { return new Object[][] {{PING_API_HTTP_URL_STRING}, {PING_API_HTTPS_URL_STRING}}; } @Test(dataProvider = "protocollDataProvider") - public void shouldInitializeFromUrl(String urlString) throws Exception { + public void shouldInitializeFromUrl(String urlString) { // Given URL urlMock = mockUrlConnection(urlString); @@ -119,8 +120,7 @@ public void shouldInitializeFromUrl(String urlString) throws Exception { private void assertPingApi(OpenApiSpecification specification) { assertNotNull(specification); - assertTrue(specification.getRequestValidator().isPresent()); - assertTrue(specification.getResponseValidator().isPresent()); + assertNotNull(specification.getSwaggerOpenApiValidationContext()); Optional pingOperationPathAdapter = specification.getOperation( PING_OPERATION_ID, testContextMock); @@ -240,27 +240,25 @@ URL toSpecUrl(String resolvedSpecUrl) { when(endpointConfigurationMock.getRequestUrl()).thenReturn("http://org.citrus.sample"); // When - specification.setRequestValidationEnabled(false); + specification.setApiRequestValidationEnabled(false); // Then (not yet initialized) - assertFalse(specification.isRequestValidationEnabled()); - assertFalse(specification.getRequestValidator().isPresent()); + assertFalse(specification.isApiRequestValidationEnabled()); + assertNull(specification.getSwaggerOpenApiValidationContext()); // When (initialize) specification.getOpenApiDoc(testContextMock); // Then - assertFalse(specification.isRequestValidationEnabled()); - assertTrue(specification.getRequestValidator().isPresent()); - assertTrue(specification.getRequestValidator().isPresent()); + assertFalse(specification.isApiRequestValidationEnabled()); + assertNotNull(specification.getSwaggerOpenApiValidationContext()); // When - specification.setRequestValidationEnabled(true); + specification.setApiRequestValidationEnabled(true); // Then - assertTrue(specification.isRequestValidationEnabled()); - assertTrue(specification.getRequestValidator().isPresent()); - assertTrue(specification.getRequestValidator().get().isEnabled()); + assertTrue(specification.isApiRequestValidationEnabled()); + assertTrue(specification.getSwaggerOpenApiValidationContext().isRequestValidationEnabled()); } @@ -288,20 +286,19 @@ public void shouldDisableEnableResponseValidationWhenSet() { OpenApiSpecification specification = OpenApiSpecification.from(new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); // When - specification.setResponseValidationEnabled(false); + specification.setApiResponseValidationEnabled(false); // Then - assertFalse(specification.isResponseValidationEnabled()); - assertTrue(specification.getResponseValidator().isPresent()); - assertFalse(specification.getResponseValidator().get().isEnabled()); + assertFalse(specification.isApiResponseValidationEnabled()); + assertNotNull(specification.getSwaggerOpenApiValidationContext()); + assertFalse(specification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); // When - specification.setResponseValidationEnabled(true); + specification.setApiResponseValidationEnabled(true); // Then - assertTrue(specification.isResponseValidationEnabled()); - assertTrue(specification.getResponseValidator().isPresent()); - assertTrue(specification.getResponseValidator().get().isEnabled()); + assertTrue(specification.isApiResponseValidationEnabled()); + assertTrue(specification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index a16ea69d09..59227c5cd7 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -16,55 +16,492 @@ package org.citrusframework.openapi; -import static org.mockito.Mockito.mock; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DOUBLE; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_FLOAT; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT32; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT64; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_NUMBER; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; -import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; -import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; +import com.atlassian.oai.validator.report.ValidationReport; +import com.atlassian.oai.validator.report.ValidationReport.Message; +import com.atlassian.oai.validator.schema.SchemaValidator; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.HashMap; -import java.util.List; +import io.swagger.v3.oas.models.media.Schema; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.functions.DefaultFunctionRegistry; +import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.spi.Resources; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class OpenApiTestDataGeneratorTest { + private static final TestContext testContext = new TestContext(); + + private static OpenApiSpecification openApiSpecification; + + private static SchemaValidator schemaValidator; + + @BeforeClass + public static void beforeClass() { + testContext.setFunctionRegistry(new DefaultFunctionRegistry()); + + openApiSpecification = OpenApiSpecification.from( + Resources.fromClasspath("org/citrusframework/openapi/ping/ping-api.yaml")); + schemaValidator = openApiSpecification.getSwaggerOpenApiValidationContext() + .getSchemaValidator(); + } + + @DataProvider(name = "findLeastSignificantDecimalPlace") + public static Object[][] findLeastSignificantDecimalPlace() { + return new Object[][]{ + {new BigDecimal("1234.5678"), 4}, + {new BigDecimal("123.567"), 3}, + {new BigDecimal("123.56"), 2}, + {new BigDecimal("123.5"), 1}, + {new BigDecimal("123.0"), 0}, + {new BigDecimal("123"), 0} + }; + } + + @Test(dataProvider = "findLeastSignificantDecimalPlace") + void findLeastSignificantDecimalPlace(BigDecimal number, int expectedSignificance) { + assertEquals(OpenApiTestDataGenerator.findLeastSignificantDecimalPlace(number), + expectedSignificance); + } + + @DataProvider(name = "incrementToExclude") + public static Object[][] incrementToExclude() { + return new Object[][]{ + {new BigDecimal("1234.678"), new BigDecimal("1234.679")}, + {new BigDecimal("1234.78"), new BigDecimal("1234.79")}, + {new BigDecimal("1234.8"), new BigDecimal("1234.9")}, + {new BigDecimal("1234.0"), new BigDecimal("1235")}, + {new BigDecimal("1234"), new BigDecimal("1235")}, + }; + } + + @Test(dataProvider = "incrementToExclude") + void incrementToExclude(BigDecimal value, BigDecimal expectedValue) { + assertEquals(OpenApiTestDataGenerator.incrementToExclude(value), expectedValue); + } + + @DataProvider(name = "decrementToExclude") + public static Object[][] decrementToExclude() { + return new Object[][]{ + {new BigDecimal("1234.678"), new BigDecimal("1234.677")}, + {new BigDecimal("1234.78"), new BigDecimal("1234.77")}, + {new BigDecimal("1234.8"), new BigDecimal("1234.7")}, + {new BigDecimal("1234.0"), new BigDecimal("1233")}, + {new BigDecimal("1234"), new BigDecimal("1233")}, + }; + } + + @Test(dataProvider = "decrementToExclude") + void decrementToExclude(BigDecimal value, BigDecimal expectedValue) { + assertEquals(OpenApiTestDataGenerator.decrementToExclude(value), expectedValue); + } + @Test - public void anyOfIsIgnoredForOas3() { + void testUuidFormat() { + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = TYPE_STRING; + stringSchema.format = FORMAT_UUID; + + String uuidRandomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema, + false); + String finalUuidRandomValue = testContext.replaceDynamicContentInString(uuidRandomValue); + Pattern uuidPattern = Pattern.compile( + "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + + assertTrue(uuidPattern.matcher(finalUuidRandomValue).matches()); + } + + @DataProvider(name = "testRandomNumber") + public static Object[][] testRandomNumber() { + return new Object[][]{ + {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 11, 0, 12, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 12, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 13, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 14, 0, 14, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 15, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 16, -16, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 17, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 18, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 19, -20, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 20, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 21, 21, 21, false, false}, + + {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 11, 0, 12, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 12, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 13, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 14, 0, 14, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 15, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 16, -16, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 17, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 18, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 19, -20, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 20, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 21, 21, 21, false, false}, + + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, null, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 11.123f, 0, 13, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 12.123f, null, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 13.123f, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 14.123f, 0, 14, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 15.123f, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 16.123f, -16, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 17.123f, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 18.123f, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 19.123f, -21, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 20.123f, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 21.123f, 21.122f, 21.124f, false, false}, - Oas30Schema anyOfSchema = new Oas30Schema(); - anyOfSchema.anyOf = List.of(new Oas30Schema(), new Oas30Schema()); + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, null, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 11.123d, 0, 13, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 12.123d, null, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 13.123d, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 14.123d, 0, 14, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 15.123d, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 16.123d, -16, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 17.123d, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 18.123d, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 19.123d, -21, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 20.123d, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 21.123d, 21.122d, 21.124d, false, false}, + }; + } + + @Test(dataProvider = "testRandomNumber") + void testRandomNumber(String type, String format, Number multipleOf, Number minimum, + Number maximum, boolean exclusiveMinimum, boolean exclusiveMaximum) { + Oas30Schema testSchema = new Oas30Schema(); + testSchema.type = type; + testSchema.format = format; + testSchema.multipleOf = multipleOf; + testSchema.minimum = minimum; + testSchema.maximum = maximum; + testSchema.exclusiveMinimum = exclusiveMinimum; + testSchema.exclusiveMaximum = exclusiveMaximum; + + try { + for (int i = 0; i < 1000; i++) { + String randomValue = OpenApiTestDataGenerator.createOutboundPayload( + testSchema, openApiSpecification); + String finalRandomValue = testContext.resolveDynamicValue(randomValue); + BigDecimal value = new BigDecimal(finalRandomValue); + + if (multipleOf != null) { + BigDecimal remainder = value.remainder(new BigDecimal(multipleOf.toString())); - assertEquals(OpenApiTestDataGenerator.createValidationExpression( - anyOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + assertEquals( + remainder.compareTo(BigDecimal.ZERO), 0, + "Expected %s to be a multiple of %s! Remainder is %s".formatted( + finalRandomValue, multipleOf, + remainder)); + } + + if (maximum != null) { + if (exclusiveMaximum) { + assertTrue(value.doubleValue() < testSchema.maximum.doubleValue(), + "Expected %s to be lower than %s!".formatted( + finalRandomValue, maximum)); + } else { + assertTrue(value.doubleValue() <= testSchema.maximum.doubleValue(), + "Expected %s to be lower or equal than %s!".formatted( + finalRandomValue, maximum)); + } + } + + if (minimum != null) { + if (exclusiveMinimum) { + assertTrue(value.doubleValue() > testSchema.minimum.doubleValue(), + "Expected %s to be larger than %s!".formatted( + finalRandomValue, minimum)); + } else { + assertTrue(value.doubleValue() >= testSchema.minimum.doubleValue(), + "Expected %s to be larger or equal than %s!".formatted( + finalRandomValue, minimum)); + } + } + } + } catch (Exception e) { + Assert.fail("Creation of multiple float threw an exception: " + e.getMessage(), e); + } } @Test - public void allOfIsIgnoredForOas3() { + void testPattern() { + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = TYPE_STRING; - Oas30Schema allOfSchema = new Oas30Schema(); - allOfSchema.allOf = List.of(new Oas30Schema(), new Oas30Schema()); + String exp = "[0-3]([a-c]|[e-g]{1,2})"; + stringSchema.pattern = exp; - assertEquals(OpenApiTestDataGenerator.createValidationExpression( - allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + String randomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema, + false); + String finalRandomValue = testContext.replaceDynamicContentInString(randomValue); + assertTrue(finalRandomValue.matches(exp), + "Value '%s' does not match expression '%s'".formatted(finalRandomValue, exp)); + } + + @DataProvider(name = "testPingApiSchemas") + public static Object[][] testPingApiSchemas() { + return new Object[][]{ + + // Composites currently do not work properly - validation fails + //{"AnyOfType"}, + //{"AllOfType"}, + //{"PingRespType"}, + + {"OneOfType"}, + {"StringsType"}, + {"DatesType"}, + {"NumbersType"}, + {"MultipleOfType"}, + {"PingReqType"}, + {"Detail1"}, + {"Detail2"}, + {"BooleanType"}, + {"EnumType"}, + {"NestedType"}, + {"SimpleArrayType"}, + {"ComplexArrayType"}, + {"ArrayOfArraysType"}, + {"NullableType"}, + {"DefaultValueType"}, + }; + } + + + @Test(dataProvider = "testPingApiSchemas") + void testPingApiSchemas(String schemaType) throws IOException { + + OasSchema schema = OasModelHelper.getSchemaDefinitions( + openApiSpecification.getOpenApiDoc(null)).get(schemaType); + + Schema swaggerValidationSchema = openApiSpecification.getSwaggerOpenApiValidationContext() + .getSwaggerOpenApi().getComponents().getSchemas().get(schemaType); + + assertNotNull(schema); + + for (int i=0;i<100;i++) { + + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(schema, + openApiSpecification); + assertNotNull(randomValue); + + String finalJsonAsText = testContext.replaceDynamicContentInString(randomValue); + + try { + JsonNode valueNode = new ObjectMapper().readTree( + testContext.replaceDynamicContentInString(finalJsonAsText)); + ValidationReport validationReport = schemaValidator.validate(() -> valueNode, + swaggerValidationSchema, + "response.body"); + + String message = """ + Json is invalid according to schema. + Message: %s + Report: %s + """.formatted(finalJsonAsText, validationReport.getMessages().stream().map( + Message::getMessage).collect(Collectors.joining("\n"))); + assertFalse(validationReport.hasErrors(), message); + } catch (JsonParseException e) { + Assert.fail("Unable to read generated schema to json: "+finalJsonAsText); + } + } } @Test - public void oneOfIsIgnoredForOas3() { + void testArray() { + Oas30Schema arraySchema = new Oas30Schema(); + arraySchema.type = TYPE_ARRAY; + + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = TYPE_STRING; + stringSchema.minLength = 5; + stringSchema.maxLength = 15; - Oas30Schema oneOfSchema = new Oas30Schema(); - oneOfSchema.oneOf = List.of(new Oas30Schema(), new Oas30Schema()); + arraySchema.items = stringSchema; - assertEquals(OpenApiTestDataGenerator.createValidationExpression( - oneOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + for (int i = 0; i < 10; i++) { + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, + openApiSpecification); + int nElements = StringUtils.countMatches(randomValue, "citrus:randomString"); + assertTrue(nElements > 0); + } } @Test - public void allOfIsIgnoredForOas2() { + void testArrayMinItems() { + Oas30Schema arraySchema = new Oas30Schema(); + arraySchema.type = TYPE_ARRAY; + arraySchema.minItems = 5; + + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = TYPE_STRING; + stringSchema.minLength = 5; + stringSchema.maxLength = 15; + + arraySchema.items = stringSchema; - Oas20AllOfSchema allOfSchema = new Oas20AllOfSchema(); - allOfSchema.allOf = List.of(new Oas20Schema(), new Oas20Schema()); + for (int i = 0; i < 10; i++) { + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, + openApiSpecification); + int nElements = StringUtils.countMatches(randomValue, "citrus:randomString(15)"); + assertTrue(nElements <= 5); + } + } + + @Test + void testArrayMaxItems() { + Oas30Schema arraySchema = new Oas30Schema(); + arraySchema.type = TYPE_ARRAY; + arraySchema.minItems = 2; + arraySchema.maxItems = 5; + + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = TYPE_STRING; + stringSchema.minLength = 10; + stringSchema.maxLength = 15; + + arraySchema.items = stringSchema; + + Pattern pattern = Pattern.compile("citrus:randomString\\(1[0-5]\\)"); + for (int i = 0; i < 100; i++) { + String randomArrayValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, + openApiSpecification); + + Matcher matcher = pattern.matcher(randomArrayValue); + int matches = 0; + while (matcher.find()) { + matches++; + } + + assertTrue(2 <= matches && matches <= 5, + "Expected random array string with number of elements between 2 and 4 but found %s: %s".formatted( + matches, randomArrayValue)); + } + } + + @Test + public void testLowestMultipleOf() { + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(10)), BigDecimal.valueOf(-1000)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-10)), BigDecimal.valueOf(-1000)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(11)), BigDecimal.valueOf(-990)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-11)), BigDecimal.valueOf(-990)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(11.1234)), BigDecimal.valueOf(-989.9826)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-11.1234)), BigDecimal.valueOf(-989.9826)); + + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(10)), BigDecimal.valueOf(1000)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-10)), BigDecimal.valueOf(1000)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(11)), BigDecimal.valueOf(1001)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-11)), BigDecimal.valueOf(1001)); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(11.1234)), new BigDecimal("1001.1060")); + assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-11.1234)), new BigDecimal("1001.1060")); + } + + @Test + public void testLargestMultipleOf() { + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(10)), BigDecimal.valueOf(-1000)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-10)), BigDecimal.valueOf(-1000)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(11)), BigDecimal.valueOf(-1001)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-11)), BigDecimal.valueOf(-1001)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(11.1234)), new BigDecimal("-1001.1060")); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), + BigDecimal.valueOf(-11.1234)), new BigDecimal("-1001.1060")); - assertEquals(OpenApiTestDataGenerator.createValidationExpression( - allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(10)), BigDecimal.valueOf(1000)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-10)), BigDecimal.valueOf(1000)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(11)), BigDecimal.valueOf(990)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-11)), BigDecimal.valueOf(990)); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(11.1234)), new BigDecimal("989.9826")); + assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), + BigDecimal.valueOf(-11.1234)), new BigDecimal("989.9826")); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java new file mode 100644 index 0000000000..820a8cbbae --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java @@ -0,0 +1,71 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi; + +import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationExpression; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertEquals; + +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; +import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.HashMap; +import java.util.List; +import org.testng.annotations.Test; + +public class OpenApiTestValidationDataGeneratorTest { + + @Test + public void anyOfIsIgnoredForOas3() { + + Oas30Schema anyOfSchema = new Oas30Schema(); + anyOfSchema.anyOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + anyOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void allOfIsIgnoredForOas3() { + + Oas30Schema allOfSchema = new Oas30Schema(); + allOfSchema.allOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void oneOfIsIgnoredForOas3() { + + Oas30Schema oneOfSchema = new Oas30Schema(); + oneOfSchema.oneOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + oneOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void allOfIsIgnoredForOas2() { + + Oas20AllOfSchema allOfSchema = new Oas20AllOfSchema(); + allOfSchema.allOf = List.of(new Oas20Schema(), new Oas20Schema()); + + assertEquals(createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java index 2c411b1179..9dbc709fa6 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java @@ -1,7 +1,24 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.util.OpenApiUtils; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterMethod; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index 42aadd18d8..94786d08c2 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -31,6 +31,8 @@ import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.citrusframework.util.SocketUtils; import org.springframework.http.HttpStatus; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; import static org.citrusframework.http.actions.HttpActionBuilder.http; @@ -59,25 +61,39 @@ public class OpenApiClientIT extends TestNGCitrusSpringSupport { .requestUrl("http://localhost:%d".formatted(port)) .build(); - /** - * Directly loaded open api. - */ private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + private final OpenApiSpecification pingSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + @CitrusTest @Test public void shouldExecuteGetPetByIdFromDirectSpec() { - shouldExecuteGetPetById(openapi(petstoreSpec), VALID_PET_PATH, true); + shouldExecuteGetPetById(openapi(petstoreSpec), VALID_PET_PATH, true, false); + } + + @CitrusTest + @Test + public void shouldFailOnMissingNameInResponse() { + shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, false, false); + } + + @CitrusTest + @Test + public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { + shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, true, true); } - private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String responseFile, boolean valid) { + private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String responseFile, + boolean valid, boolean disableValidation) { variable("petId", "1001"); when(openapi .client(httpClient) .send("getPetById") + .message() .fork(true)); then(http().server(httpServer) @@ -94,7 +110,9 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String respon .contentType("application/json")); OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi - .client(httpClient).receive("getPetById", HttpStatus.OK); + .client(httpClient).receive("getPetById", HttpStatus.OK) + .disableOasValidation(disableValidation); + if (valid) { then(clientResponseActionBuilder); } else { @@ -114,12 +132,6 @@ public void shouldProperlyExecuteGetAndAddPetFromRepository() { shouldExecuteGetAndAddPet(openapi(petstoreSpec)); } - @CitrusTest - @Test - public void shouldFailOnMissingNameInResponse() { - shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, false); - } - @CitrusTest @Test public void shouldFailOnMissingNameInRequest() { @@ -203,4 +215,37 @@ private void shouldExecuteGetAndAddPet(OpenApiActionBuilder openapi) { .client(httpClient) .receive("addPet", HttpStatus.CREATED)); } + + @DataProvider(name="pingApiOperationDataprovider") + public static Object[][] pingApiOperationDataprovider() { + return new Object[][]{{"doPing"}, {"doPong"}, {"doPung"}}; + } + + @Test(dataProvider = "pingApiOperationDataprovider") + @CitrusTest + @Ignore // Solve issue with composite schemes + public void shouldPerformRoundtripPingOperation(String pingApiOperation) { + + variable("id", 2001); + when(openapi(pingSpec) + .client(httpClient) + .send(pingApiOperation) + .message() + .fork(true)); + + then(openapi(pingSpec).server(httpServer) + .receive(pingApiOperation) + .message() + .accept("@contains('application/json')@")); + + then(openapi(pingSpec).server(httpServer) + .send(pingApiOperation) + .message() + .contentType("application/json")); + + OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi(pingSpec) + .client(httpClient).receive(pingApiOperation, HttpStatus.OK); + + then(clientResponseActionBuilder); + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index d29a11f75a..82d48fa427 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -18,6 +18,7 @@ import org.citrusframework.annotations.CitrusTest; import org.citrusframework.exceptions.TestCaseFailedException; +import org.citrusframework.http.actions.HttpServerResponseActionBuilder.HttpMessageBuilderSupport; import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; @@ -67,11 +68,6 @@ public class OpenApiServerIT extends TestNGCitrusSpringSupport { @CitrusTest public void shouldExecuteGetPetById() { - shouldExecuteGetPetById(openapi(petstoreSpec)); - } - - - private void shouldExecuteGetPetById(OpenApiActionBuilder openapi) { variable("petId", "1001"); when(http() @@ -82,11 +78,11 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi) { .accept("application/json") .fork(true)); - then(openapi + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById")); - then(openapi + then(openapi(petstoreSpec) .server(httpServer) .send("getPetById", HttpStatus.OK)); @@ -110,6 +106,96 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi) { """)); } + @CitrusTest + public void executeGetPetByIdShouldFailOnInvalidResponse() { + variable("petId", "1001"); + + when(http() + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept("application/json") + .fork(true)); + + then(openapi(petstoreSpec) + .server(httpServer) + .receive("getPetById")); + + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) + .server(httpServer) + .send("getPetById", HttpStatus.OK) + .message().body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """); + assertThrows(TestCaseFailedException.class, () ->then(getPetByIdResponseBuilder)); + } + + @CitrusTest + public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisabled() { + variable("petId", "1001"); + + when(http() + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept("application/json") + .fork(true)); + + then(openapi(petstoreSpec) + .server(httpServer) + .receive("getPetById")); + + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) + .server(httpServer) + .send("getPetById", HttpStatus.OK) + .disableOasValidation(true) + .message().body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """); + then(getPetByIdResponseBuilder); + + then(http() + .client(httpClient) + .receive() + .response(HttpStatus.OK) + .message() + .body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """)); + } + @CitrusTest public void shouldExecuteAddPet() { shouldExecuteAddPet(openapi(petstoreSpec), VALID_PET_PATH, true); @@ -167,7 +253,7 @@ public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { @CitrusTest public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { - variable("petId", "xxx"); + variable("petId", -1); when(http() .client(httpClient) @@ -181,7 +267,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) .server(httpServer) .receive("addPet") - .disableOasValidation(true); + .disableOasValidation(false); try { when(addPetBuilder); @@ -220,4 +306,5 @@ private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFil .receive() .response(HttpStatus.CREATED)); } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java index 7846daf42b..d24101fb35 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java @@ -1,7 +1,23 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.model; import io.apicurio.datamodels.openapi.v3.models.Oas30Operation; -import org.citrusframework.openapi.OpenApiUtils; +import org.citrusframework.openapi.util.OpenApiUtils; import org.testng.annotations.Test; import static java.lang.String.format; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java new file mode 100644 index 0000000000..2add7086c8 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java @@ -0,0 +1,89 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.util; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomElementTest { + + private RandomElement.RandomList randomList; + private RandomElement.RandomObject randomObject; + private RandomElement.RandomValue randomValue; + + @BeforeMethod + public void setUp() { + randomList = new RandomElement.RandomList(); + randomObject = new RandomElement.RandomObject(); + randomValue = new RandomElement.RandomValue(); + } + + @Test + public void testRandomListPushValue() { + randomList.push("testValue"); + assertEquals(randomList.size(), 1); + assertEquals(randomList.get(0), "testValue"); + } + + @Test + public void testRandomListPushKeyValue() { + randomList.push(new RandomElement.RandomObject()); + randomList.push("key", "value"); + assertEquals(((RandomElement.RandomObject) randomList.get(0)).get("key"), "value"); + } + + @Test + public void testRandomObjectPushKeyValue() { + randomObject.push("key", "value"); + assertEquals(randomObject.get("key"), "value"); + } + + @Test + public void testRandomObjectPushRandomObject() { + RandomElement.RandomObject nestedObject = new RandomElement.RandomObject(); + nestedObject.push("nestedKey", "nestedValue"); + randomObject.push(nestedObject); + assertEquals(randomObject.size(), 1); + assertEquals(randomObject.get("nestedKey"), "nestedValue"); + } + + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testRandomObjectPushValueThrowsException() { + randomObject.push("value"); + } + + @Test + public void testRandomValuePushValue() { + randomValue.push("testValue"); + assertEquals(randomValue.getValue(), "testValue"); + } + + @Test + public void testRandomValuePushRandomElement() { + RandomElement.RandomObject nestedObject = new RandomElement.RandomObject(); + randomValue = new RandomElement.RandomValue(nestedObject); + randomValue.push("key", "value"); + assertEquals(((RandomElement.RandomObject) randomValue.getValue()).get("key"), "value"); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testRandomValuePushKeyValueThrowsException() { + randomValue.push("key", "value"); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java new file mode 100644 index 0000000000..f7570c2083 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java @@ -0,0 +1,127 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.util; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +public class RandomModelBuilderTest { + + private RandomModelBuilder builder; + + @BeforeMethod + public void setUp() { + builder = new RandomModelBuilder(); + } + + @Test + public void testInitialState() { + String text = builder.toString(); + assertEquals(text, ""); + } + + @Test + public void testAppendSimple() { + builder.appendSimple("testValue"); + String json = builder.toString(); + assertEquals(json, "testValue"); + } + + @Test + public void testObjectWithProperties() { + builder.object(() -> { + builder.property("key1", () -> builder.appendSimple("\"value1\"")); + builder.property("key2", () -> builder.appendSimple("\"value2\"")); + }); + String json = builder.toString(); + assertEquals(json, "{\"key1\": \"value1\",\"key2\": \"value2\"}"); + } + + @Test + public void testNestedObject() { + builder.object(() -> + builder.property("outerKey", () -> builder.object(() -> + builder.property("innerKey", () -> builder.appendSimple("\"innerValue\"")) + )) + ); + String json = builder.toString(); + assertEquals(json, "{\"outerKey\": {\"innerKey\": \"innerValue\"}}"); + } + + @Test + public void testArray() { + builder.array(() -> { + builder.appendSimple("\"value1\""); + builder.appendSimple("\"value2\""); + builder.appendSimple("\"value3\""); + }); + String json = builder.toString(); + assertEquals(json, "[\"value1\",\"value2\",\"value3\"]"); + } + + @Test + public void testNestedArray() { + builder.array(() -> { + builder.appendSimple("\"value1\""); + builder.array(() -> { + builder.appendSimple("\"nestedValue1\""); + builder.appendSimple("\"nestedValue2\""); + }); + builder.appendSimple("\"value2\""); + }); + String json = builder.toString(); + assertEquals(json, "[\"value1\",[\"nestedValue1\",\"nestedValue2\"],\"value2\"]"); + } + + @Test + public void testMixedStructure() { + builder.object(() -> { + builder.property("key1", () -> builder.array(() -> { + builder.appendSimple("\"value1\""); + builder.object(() -> + builder.property("nestedKey", () -> builder.appendSimple("\"nestedValue\"")) + ); + })); + builder.property("key2", () -> builder.appendSimple("\"value2\"")); + }); + String json = builder.toString(); + assertEquals(json, "{\"key1\": [\"value1\",{\"nestedKey\": \"nestedValue\"}],\"key2\": \"value2\"}"); + } + + @Test + public void testIllegalStateOnEmptyDeque() { + + builder.deque.clear(); + + Exception exception = expectThrows(IllegalStateException.class, () -> + builder.property("key", () -> builder.appendSimple("value")) + ); + assertEquals(exception.getMessage(), "Encountered empty stack!"); + + exception = expectThrows(IllegalStateException.class, () -> + builder.object(() -> {}) + ); + assertEquals(exception.getMessage(), "Encountered empty stack!"); + + exception = expectThrows(IllegalStateException.class, () -> + builder.array(() -> {}) + ); + assertEquals(exception.getMessage(), "Encountered empty stack!"); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java index 7c7a578106..80d901395d 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java @@ -1,39 +1,53 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.validation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNotNull; + +import java.util.Optional; import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.util.Optional; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class OpenApiRequestValidationProcessorTest { @Mock private OpenApiSpecification openApiSpecificationMock; - @Mock - private OpenApiRequestValidator requestValidatorMock; - @Mock private OperationPathAdapter operationPathAdapterMock; - @InjectMocks private OpenApiRequestValidationProcessor processor; private AutoCloseable mockCloseable; @@ -49,71 +63,61 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test - public void shouldNotValidateWhenDisabled() { - processor.setEnabled(false); - HttpMessage messageMock = mock(); - - processor.validate(messageMock, mock()); - - verify(openApiSpecificationMock, never()).getOperation(any(), any()); - } - @Test public void shouldNotValidateNonHttpMessage() { Message messageMock = mock(); processor.validate(messageMock, mock()); - verify(openApiSpecificationMock, never()).getOperation(any(), any()); + verify(openApiSpecificationMock,times(2)).getSwaggerOpenApiValidationContext(); + verifyNoMoreInteractions(openApiSpecificationMock); } @Test public void shouldValidateHttpMessage() { - processor.setEnabled(true); HttpMessage httpMessageMock = mock(); TestContext contextMock = mock(); + OpenApiRequestValidator openApiRequestValidatorSpy = replaceValidatorWithSpy(httpMessageMock); + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) .thenReturn(Optional.of(operationPathAdapterMock)); - when(openApiSpecificationMock.getRequestValidator()) - .thenReturn(Optional.of(requestValidatorMock)); processor.validate(httpMessageMock, contextMock); - verify(requestValidatorMock, times(1)).validateRequest(operationPathAdapterMock, httpMessageMock); + verify(openApiRequestValidatorSpy, times(1)).validateRequest(operationPathAdapterMock, httpMessageMock); } @Test - public void shouldNotValidateWhenNoOperation() { - processor.setEnabled(true); - HttpMessage httpMessage = mock(HttpMessage.class); - TestContext context = mock(TestContext.class); + public void shouldCallValidateRequest() { + HttpMessage httpMessageMock = mock(); + TestContext contextMock = mock(); + + OpenApiRequestValidator openApiRequestValidatorSpy = replaceValidatorWithSpy(httpMessageMock); when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) .thenReturn(Optional.empty()); - processor.validate(httpMessage, context); + processor.validate(httpMessageMock, contextMock); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); - verify(openApiSpecificationMock, never()).getRequestValidator(); + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), + any(TestContext.class)); + verify(openApiRequestValidatorSpy, times(0)).validateRequest(operationPathAdapterMock, httpMessageMock); } - @Test - public void shouldNotValidateWhenNoValidator() { - processor.setEnabled(true); - HttpMessage httpMessage = mock(HttpMessage.class); - TestContext context = mock(TestContext.class); + private OpenApiRequestValidator replaceValidatorWithSpy(HttpMessage httpMessage) { + OpenApiRequestValidator openApiRequestValidator = (OpenApiRequestValidator) ReflectionTestUtils.getField( + processor, + "openApiRequestValidator"); - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.of(operationPathAdapterMock)); - when(openApiSpecificationMock.getRequestValidator()) - .thenReturn(Optional.empty()); + assertNotNull(openApiRequestValidator); + OpenApiRequestValidator openApiRequestValidatorSpy = spy(openApiRequestValidator); + ReflectionTestUtils.setField(processor, "openApiRequestValidator", openApiRequestValidatorSpy); - processor.validate(httpMessage, context); + doAnswer((invocation) -> null + // do nothing + ).when(openApiRequestValidatorSpy).validateRequest(operationPathAdapterMock, httpMessage); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); - verify(openApiSpecificationMock, times(1)).getRequestValidator(); - verify(requestValidatorMock, never()).validateRequest(any(), any()); + return openApiRequestValidatorSpy; } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java index 9b97d42b78..f79a8a9887 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -1,14 +1,46 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.validation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.report.ValidationReport; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.web.bind.annotation.RequestMethod; @@ -17,23 +49,13 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +public class OpenApiRequestValidatorTest { -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; + @Mock + private OpenApiSpecification openApiSpecificationMock; -public class OpenApiRequestValidatorTest { + @Mock + private SwaggerOpenApiValidationContext swaggerOpenApiValidationContextMock; @Mock private OpenApiInteractionValidator openApiInteractionValidatorMock; @@ -47,7 +69,6 @@ public class OpenApiRequestValidatorTest { @Mock private ValidationReport validationReportMock; - @InjectMocks private OpenApiRequestValidator openApiRequestValidator; private AutoCloseable mockCloseable; @@ -55,7 +76,11 @@ public class OpenApiRequestValidatorTest { @BeforeMethod public void beforeMethod() { mockCloseable = MockitoAnnotations.openMocks(this); - openApiRequestValidator = new OpenApiRequestValidator(openApiInteractionValidatorMock); + + doReturn(swaggerOpenApiValidationContextMock).when(openApiSpecificationMock).getSwaggerOpenApiValidationContext(); + doReturn(openApiInteractionValidatorMock).when(swaggerOpenApiValidationContextMock).getOpenApiInteractionValidator(); + + openApiRequestValidator = new OpenApiRequestValidator(openApiSpecificationMock); } @AfterMethod @@ -143,13 +168,4 @@ public void shouldCreateRequestFromMessage() throws IOException { assertEquals(request.getRequestBody().get().toString(StandardCharsets.UTF_8), "payload"); } - private Request callCreateRequestFromMessage(OpenApiRequestValidator validator, OperationPathAdapter adapter, HttpMessage message) { - try { - var method = OpenApiRequestValidator.class.getDeclaredMethod("createRequestFromMessage", OperationPathAdapter.class, HttpMessage.class); - method.setAccessible(true); - return (Request) method.invoke(validator, adapter, message); - } catch (Exception e) { - throw new RuntimeException(e); - } - } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java index bd60fd55b6..671560ba9f 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java @@ -1,39 +1,53 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.validation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertNotNull; + +import java.util.Optional; import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.test.util.ReflectionTestUtils; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.util.Optional; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class OpenApiResponseValidationProcessorTest { @Mock private OpenApiSpecification openApiSpecificationMock; - @Mock - private OpenApiResponseValidator responseValidatorMock; - @Mock private OperationPathAdapter operationPathAdapterMock; - @InjectMocks private OpenApiResponseValidationProcessor processor; private AutoCloseable mockCloseable; @@ -49,71 +63,61 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test - public void shouldNotValidateWhenDisabled() { - processor.setEnabled(false); - HttpMessage messageMock = mock(); - - processor.validate(messageMock, mock()); - - verify(openApiSpecificationMock, never()).getOperation(any(), any()); - } - @Test public void shouldNotValidateNonHttpMessage() { Message messageMock = mock(); processor.validate(messageMock, mock()); - verify(openApiSpecificationMock, never()).getOperation(any(), any()); + verify(openApiSpecificationMock,times(2)).getSwaggerOpenApiValidationContext(); + verifyNoMoreInteractions(openApiSpecificationMock); } @Test - public void shouldValidateHttpMessage() { - processor.setEnabled(true); + public void shouldCallValidateResponse() { HttpMessage httpMessageMock = mock(); TestContext contextMock = mock(); + OpenApiResponseValidator openApiResponseValidatorSpy = replaceValidatorWithSpy(httpMessageMock); + when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) .thenReturn(Optional.of(operationPathAdapterMock)); - when(openApiSpecificationMock.getResponseValidator()) - .thenReturn(Optional.of(responseValidatorMock)); processor.validate(httpMessageMock, contextMock); - verify(responseValidatorMock, times(1)).validateResponse(operationPathAdapterMock, httpMessageMock); + verify(openApiResponseValidatorSpy, times(1)).validateResponse(operationPathAdapterMock, httpMessageMock); } @Test public void shouldNotValidateWhenNoOperation() { - processor.setEnabled(true); - HttpMessage httpMessage = mock(HttpMessage.class); - TestContext context = mock(TestContext.class); + HttpMessage httpMessageMock = mock(); + TestContext contextMock = mock(); + + OpenApiResponseValidator openApiResponseValidatorSpy = replaceValidatorWithSpy(httpMessageMock); when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) .thenReturn(Optional.empty()); - processor.validate(httpMessage, context); + processor.validate(httpMessageMock, contextMock); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); - verify(openApiSpecificationMock, never()).getResponseValidator(); + verify(openApiSpecificationMock, times(1)).getOperation(anyString(), + any(TestContext.class)); + verify(openApiResponseValidatorSpy, times(0)).validateResponse(operationPathAdapterMock, httpMessageMock); } - @Test - public void shouldNotValidateWhenNoValidator() { - processor.setEnabled(true); - HttpMessage httpMessage = mock(HttpMessage.class); - TestContext context = mock(TestContext.class); + private OpenApiResponseValidator replaceValidatorWithSpy(HttpMessage httpMessage) { + OpenApiResponseValidator openApiResponseValidator = (OpenApiResponseValidator) ReflectionTestUtils.getField( + processor, + "openApiResponseValidator"); - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.of(operationPathAdapterMock)); - when(openApiSpecificationMock.getResponseValidator()) - .thenReturn(Optional.empty()); + assertNotNull(openApiResponseValidator); + OpenApiResponseValidator openApiResponseValidatorSpy = spy(openApiResponseValidator); + ReflectionTestUtils.setField(processor, "openApiResponseValidator", openApiResponseValidatorSpy); - processor.validate(httpMessage, context); + doAnswer((invocation) -> null + // do nothing + ).when(openApiResponseValidatorSpy).validateResponse(operationPathAdapterMock, httpMessage); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), any(TestContext.class)); - verify(openApiSpecificationMock, times(1)).getResponseValidator(); - verify(responseValidatorMock, never()).validateResponse(any(), any()); + return openApiResponseValidatorSpy; } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java index 5bfef2eacb..e59f1f2821 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.validation; import com.atlassian.oai.validator.OpenApiInteractionValidator; @@ -7,6 +23,7 @@ import io.apicurio.datamodels.openapi.models.OasOperation; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -23,15 +40,23 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; public class OpenApiResponseValidatorTest { + @Mock + private OpenApiSpecification openApiSpecificationMock; + + @Mock + private SwaggerOpenApiValidationContext swaggerOpenApiValidationContextMock; + @Mock private OpenApiInteractionValidator openApiInteractionValidatorMock; @@ -55,7 +80,11 @@ public class OpenApiResponseValidatorTest { @BeforeMethod public void beforeMethod() { mockCloseable = MockitoAnnotations.openMocks(this); - openApiResponseValidator = new OpenApiResponseValidator(openApiInteractionValidatorMock); + + doReturn(swaggerOpenApiValidationContextMock).when(openApiSpecificationMock).getSwaggerOpenApiValidationContext(); + doReturn(openApiInteractionValidatorMock).when(swaggerOpenApiValidationContextMock).getOpenApiInteractionValidator(); + + openApiResponseValidator = new OpenApiResponseValidator(openApiSpecificationMock); } @AfterMethod @@ -128,7 +157,9 @@ public void shouldCreateResponseMessage() throws IOException { // Then assertNotNull(response); + assertTrue(response.getResponseBody().isPresent()); assertEquals(response.getResponseBody().get().toString(StandardCharsets.UTF_8), "payload"); + assertTrue(response.getHeaderValue("Content-Type").isPresent()); assertEquals(response.getHeaderValue("Content-Type").get(), "application/json"); assertEquals(response.getStatus(), Integer.valueOf(200)); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index 30ad30e4eb..ca2d7e8732 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -249,4 +249,5 @@ public void shouldLookupTestActionBuilder() { Assert.assertTrue(XmlTestActionBuilder.lookup("openapi").isPresent()); Assert.assertEquals(XmlTestActionBuilder.lookup("openapi").get().getClass(), OpenApi.class); } + } diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-v3.json b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-v3.json index 618854948f..a7e135c535 100644 --- a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-v3.json +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-v3.json @@ -98,7 +98,8 @@ "description": "ID of pet to return", "schema": { "format": "int64", - "type": "integer" + "type": "integer", + "minimum": 1 }, "in": "path", "required": true @@ -158,7 +159,8 @@ "description": "Pet id to delete", "schema": { "format": "int64", - "type": "integer" + "type": "integer", + "minimum": 1 }, "in": "path", "required": true diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml index f5e8f95b1a..29bda14fb2 100644 --- a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml @@ -84,24 +84,33 @@ paths: responses: 200: description: successful operation without a response + /pung/{id}: + get: + tags: + - pong + summary: Do the pung + operationId: doPung + parameters: + - name: id + in: path + description: Id to pung + required: true + explode: true + schema: + type: integer + format: int64 + responses: + 200: + description: successful pung operation with all types + content: + application/json: + schema: + $ref: '#/components/schemas/StringsType' + plain/text: + schema: + type: string components: schemas: - Ipv6Type: - required: - - ipv6 - type: object - properties: - ipv6: - type: string - format: ipv6 - Ipv4Type: - required: - - ipv4 - type: object - properties: - ipv4: - type: string - format: ipv4 DateType: required: - date @@ -118,98 +127,207 @@ components: dateTime: type: string format: date-time - EmailType: - required: - - email + AllOfType: + allOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + AnyOfType: + anyOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + OneOfType: + oneOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + MultipleOfType: type: object - properties: - email: - type: string - format: email - ByteType: required: - - byte - type: object + - type + - manyPi + - even properties: - byte: + type: type: string - format: byte - BinaryType: - required: - - binary + enum: [ MultiplesType ] + manyPi: + type: number + format: double + multipleOf: 3.14159 + minimum: 0 + maximum: 31459 + even: + type: integer + format: int32 + multipleOf: 2 + minimum: -2000 + maximum: 2000 + StringsType: type: object - properties: - binary: - type: string - format: binary - UriType: required: - - uri - type: object + - type properties: - uri: + type: type: string - format: uri - UriReferenceType: - required: - - uriReference - type: object - properties: - uriReference: + enum: [ StringsType ] + smallString: type: string - format: uri-refence - HostnameType: - required: - - hostname + minLength: 0 + maxLength: 10 + mediumString: + type: string + minLength: 0 + maxLength: 256 + largeString: + type: string + minLength: 0 + maxLength: 1024 + nonEmptyString: + type: string + minLength: 256 + maxLength: 512 + NumbersType: type: object + required: + - type + - integerInt32 + - integerInt64 + - numberFloat + - numberDouble + - positiveIntegerInt32 + - negativeIntegerInt64 + - positiveNumberFloat + - negativeNumberDouble + - betweenIntegerInt32 + - betweenIntegerInt64 + - betweenNumberFloat + - betweenNumberDouble + - betweenIntegerInt32Exclude + - betweenIntegerInt64Exclude + - betweenNumberFloatExclude + - betweenNumberDoubleExclude properties: - hostname: + type: type: string - format: hostname - AllTypes: + enum: [ NumbersType ] + integerInt32: + type: integer + format: int32 + integerInt64: + type: integer + format: int64 + numberFloat: + type: number + format: float + numberDouble: + type: number + format: double + positiveIntegerInt32: + type: integer + format: int32 + minimum: 0 + negativeIntegerInt64: + type: integer + format: int64 + maximum: 0 + positiveNumberFloat: + type: number + format: float + minimum: 0 + negativeNumberDouble: + type: number + format: double + maximum: 0 + betweenIntegerInt32: + type: integer + format: int32 + minimum: 2 + maximum: 8 + betweenIntegerInt64: + type: integer + format: int64 + minimum: 2 + maximum: 3 + betweenNumberFloat: + type: number + format: float + minimum: 2 + maximum: 3 + betweenNumberDouble: + type: number + format: double + minimum: 2 + maximum: 3 + betweenIntegerInt32Exclude: + type: integer + format: int32 + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenIntegerInt64Exclude: + type: integer + format: int64 + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenNumberFloatExclude: + type: number + format: float + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenNumberDoubleExclude: + type: number + format: double + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + DatesType: required: - - email - - ipv6 - - ipv4 + - type - date - dateTime - - binary - - byte - - uri - - uriReference - - hostname type: object properties: - ipv6: + type: type: string - format: ipv6 - ipv4: - type: string - format: ipv4 + enum: [ DatesType ] date: type: string format: date dateTime: type: string format: date-time - email: - type: string - format: email - binary: - type: string - format: binary - byte: - type: string - format: byte - uri: - type: string - format: uri - uriReference: - type: string - format: uri-reference - hostname: - type: string - format: hostname PingReqType: type: object properties: @@ -218,21 +336,34 @@ components: format: int64 Detail1: type: object + required: + - type properties: - host: - $ref: '#/components/schemas/HostnameType' - uri: - $ref: '#/components/schemas/UriType' + type: + type: string + enum: [ Detail1Type ] + allTypes: + $ref: '#/components/schemas/NumbersType' Detail2: type: object + required: + - type properties: - ipv4: - $ref: '#/components/schemas/Ipv4Type' - uriReference: - $ref: '#/components/schemas/UriReferenceType' + type: + type: string + enum: [ Detail2Type ] + allString: + $ref: '#/components/schemas/StringsType' + allDates: + $ref: '#/components/schemas/DatesType' PingRespType: type: object + required: + - type properties: + type: + type: string + enum: [ PingRespType ] id: type: integer format: int64 @@ -242,3 +373,95 @@ components: anyOf: - $ref: '#/components/schemas/Detail1' - $ref: '#/components/schemas/Detail2' + discriminator: + propertyName: type + mapping: + Detail1Type: '#/components/schemas/Detail1' + Detail2Type: '#/components/schemas/Detail2' + BooleanType: + type: object + required: + - isActive + - isVerified + properties: + isActive: + type: boolean + isVerified: + type: boolean + EnumType: + type: object + required: + - status + properties: + status: + type: string + enum: + - ACTIVE + - INACTIVE + - PENDING + NestedType: + type: object + properties: + id: + type: integer + format: int64 + details: + $ref: '#/components/schemas/Detail1' + SimpleArrayType: + type: object + properties: + stringItems: + type: array + items: + type: string + minLength: 2 + maxLength: 5 + minItems: 10 + maxItems: 20 + numberItems: + type: array + items: + type: integer + minItems: 10 + maxItems: 20 + booleanItems: + type: array + items: + type: boolean + dateItems: + type: array + items: + type: string + format: date + ComplexArrayType: + type: object + properties: + stringItems: + type: array + items: + $ref: '#/components/schemas/StringsType' + numberItems: + type: array + items: + $ref: '#/components/schemas/NumbersType' + ArrayOfArraysType: + type: object + properties: + matrix: + type: array + items: + type: array + items: + type: integer + NullableType: + type: object + properties: + nullableString: + type: string + nullable: true + DefaultValueType: + type: object + properties: + defaultValue: + type: string + default: "defaultValue" \ No newline at end of file diff --git a/core/citrus-base/pom.xml b/core/citrus-base/pom.xml index c7e349aa0a..959f7acf01 100644 --- a/core/citrus-base/pom.xml +++ b/core/citrus-base/pom.xml @@ -28,12 +28,16 @@ commons-codec commons-codec - jakarta.xml.bind jakarta.xml.bind-api provided + + com.github.mifmif + generex + 1.0.2 + diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java index be7fc8e0f5..f3542428bd 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java @@ -32,8 +32,10 @@ import org.citrusframework.functions.core.LowerCaseFunction; import org.citrusframework.functions.core.MaxFunction; import org.citrusframework.functions.core.MinFunction; +import org.citrusframework.functions.core.AdvancedRandomNumberFunction; import org.citrusframework.functions.core.RandomEnumValueFunction; import org.citrusframework.functions.core.RandomNumberFunction; +import org.citrusframework.functions.core.RandomPatternFunction; import org.citrusframework.functions.core.RandomStringFunction; import org.citrusframework.functions.core.RandomUUIDFunction; import org.citrusframework.functions.core.ReadFileResourceFunction; @@ -64,7 +66,9 @@ public DefaultFunctionLibrary() { setName("citrusFunctionLibrary"); getMembers().put("randomNumber", new RandomNumberFunction()); + getMembers().put("randomNumberGenerator", new AdvancedRandomNumberFunction()); getMembers().put("randomString", new RandomStringFunction()); + getMembers().put("randomValue", new RandomPatternFunction()); getMembers().put("concat", new ConcatFunction()); getMembers().put("currentDate", new CurrentDateFunction()); getMembers().put("substring", new SubstringFunction()); diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java new file mode 100644 index 0000000000..bc7252e057 --- /dev/null +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java @@ -0,0 +1,144 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.functions.core; + +import static java.lang.String.format; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; +import java.util.Random; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.citrusframework.functions.Function; + +/** + * A function for generating random double values with specified decimal places and range. This + * function includes options to specify the number of decimal places, minimum and maximum values, + * and whether to include or exclude the minimum and maximum values. + *

+ * Parameters: + *

    + *
  1. Decimal places: The number of decimal places in the generated random number (optional, default: 0). Note that definition of 0 results in an integer.
  2. + *
  3. Min value: The minimum value for the generated random number (optional, default: Double.MIN_VALUE).
  4. + *
  5. Max value: The maximum value for the generated random number (optional, default: Double.MAX_VALUE).
  6. + *
  7. Exclude min: Whether to exclude the minimum value (optional, default: false).
  8. + *
  9. Exclude man: Whether to exclude the maximum value (optional, default: false).
  10. + *
+ *

+ * This function differs from the {@link RandomNumberFunction} in several key ways: + *

    + *
  • It allows to specify several aspects of a number (see above).
  • + *
  • The length of the number is restricted to the range and precision of a double, whereas RandomNumberFunction can create arbitrarily long integer values.
  • + *
+ */ +public class AdvancedRandomNumberFunction implements Function { + + /** + * Basic seed generating random number + */ + private static final Random generator = new Random(System.currentTimeMillis()); + + public String execute(List parameterList, TestContext context) { + int decimalPlaces = 0; + double minValue = -1000000; + double maxValue = 1000000; + boolean excludeMin = false; + boolean excludeMax = false; + + if (parameterList == null) { + throw new InvalidFunctionUsageException("Function parameters must not be null."); + } + + if (!parameterList.isEmpty()) { + decimalPlaces = parseParameter(1, parameterList.get(0), Integer.class, + Integer::parseInt); + if (decimalPlaces < 0) { + throw new InvalidFunctionUsageException( + "Invalid parameter definition. Decimal places must be a non-negative integer value."); + } + } + + if (parameterList.size() > 1) { + minValue = parseParameter(2, parameterList.get(1), Double.class, Double::parseDouble); + } + + if (parameterList.size() > 2) { + maxValue = parseParameter(3, parameterList.get(2), Double.class, Double::parseDouble); + if (minValue > maxValue) { + throw new InvalidFunctionUsageException( + "Invalid parameter definition. Min value must be less than max value."); + } + } + + if (parameterList.size() > 3) { + excludeMin = parseParameter(4, parameterList.get(3), Boolean.class, + Boolean::parseBoolean); + } + + if (parameterList.size() > 4) { + excludeMax = parseParameter(5, parameterList.get(4), Boolean.class, + Boolean::parseBoolean); + } + + return getRandomNumber(decimalPlaces, minValue, maxValue, excludeMin, excludeMax); + } + + private T parseParameter(int index, String text, Class type, + java.util.function.Function parseFunction) { + try { + return parseFunction.apply(text); + } catch (Exception e) { + throw new InvalidFunctionUsageException( + format("Invalid parameter at index %d. %s must be parsable to %s.", index, text, + type.getSimpleName())); + } + } + + /** + * Static number generator method. + */ + private String getRandomNumber(int decimalPlaces, double minValue, double maxValue, + boolean excludeMin, boolean excludeMax) { + double adjustment = Math.pow(10, -decimalPlaces); + + if (excludeMin) { + minValue += adjustment; + } + + if (excludeMax) { + maxValue -= adjustment; + } + + BigDecimal range = BigDecimal.valueOf(maxValue).subtract(BigDecimal.valueOf(minValue)); + + double randomValue = getRandomValue(minValue, range, generator.nextDouble()); + BigDecimal bd = new BigDecimal(Double.toString(randomValue)); + bd = bd.setScale(2, RoundingMode.HALF_UP); + + return decimalPlaces == 0 ? + format("%s", bd.longValue()) : + format(format("%%.%sf", decimalPlaces), bd.doubleValue()); + } + + double getRandomValue(double minValue, BigDecimal range, double random) { + BigDecimal offset = range.multiply(BigDecimal.valueOf(random)); + BigDecimal value = BigDecimal.valueOf(minValue).add(offset); + return value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ? Double.MAX_VALUE : value.doubleValue(); + } + +} \ No newline at end of file diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java new file mode 100644 index 0000000000..4720921c7e --- /dev/null +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java @@ -0,0 +1,60 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.functions.core; + +import static org.citrusframework.util.StringUtils.hasText; + +import com.mifmif.common.regex.Generex; +import java.util.List; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.citrusframework.functions.Function; + +/** + * The RandomPatternFunction class implements the Function interface. This function generates a + * random string based on a provided regular expression pattern. It uses the Generex library to + * generate the random string. + *

+ * Note: The Generex library has limitations in its ability to generate all possible expressions + * from a given regular expression. It may not support certain complex regex features or produce all + * possible variations. + */ +public class RandomPatternFunction implements Function { + + + public String execute(List parameterList, TestContext context) { + + if (parameterList == null) { + throw new InvalidFunctionUsageException("Function parameters must not be null."); + } + + String pattern = parameterList.get(0); + + if (!hasText(pattern)) { + throw new InvalidFunctionUsageException("Pattern must not be empty."); + } + + if (!Generex.isValidPattern(pattern)) { + throw new IllegalArgumentException( + "Function called with a pattern, the algorithm is not able to create a string for."); + } + + Generex generex = new Generex(pattern); + return generex.random(); + } + +} \ No newline at end of file diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 3fbc64c812..3d6be1f9b3 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -61,4 +61,31 @@ public static String appendSegmentToUrlPath(String path, String segment) { return path + segment; } + + public static String quote(String text, boolean quote) { + return quote ? String.format("\"%s\"", text) : text; + } + + /** + * Trims trailing whitespace characters and the first trailing comma from the end of the given StringBuilder. + * + * This method removes all trailing whitespace characters (such as spaces, tabs, and newline characters) + * and the first trailing comma found from the end of the content in the provided StringBuilder. + * Any additional commas or whitespace characters after the first trailing comma are not removed. + * + * @param builder the StringBuilder whose trailing whitespace characters and first comma are to be removed + */ + public static void trimTrailingComma(StringBuilder builder) { + int length = builder.length(); + while (length > 0 && (builder.charAt(length - 1) == ',' || Character.isWhitespace(builder.charAt(length - 1)))) { + char c = builder.charAt(length - 1); + builder.deleteCharAt(length - 1); + + if (c == ',') { + return; + } + + length = builder.length(); + } + } } diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java new file mode 100644 index 0000000000..1452fb881b --- /dev/null +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java @@ -0,0 +1,246 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.functions.core; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.math.BigDecimal; +import java.util.List; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomDoubleFunctionTest { + + private AdvancedRandomNumberFunction function; + private TestContext context; + + @BeforeMethod + public void setUp() { + function = new AdvancedRandomNumberFunction(); + context = new TestContext(); + } + + @Test + public void testRandomNumberWithNullParameter() { + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(null, context)); + assertEquals(exception.getMessage(), + "Function parameters must not be null."); + } + + @Test + public void testRandomNumberWithDefaultValues() { + List params = List.of(); + String result = function.execute(params, context); + assertNotNull(result); + assertTrue(result.matches("-?\\d*")); + } + + @Test + public void testRandomNumberWithDecimalPlaces() { + List params = List.of("2"); + String result = function.execute(params, context); + assertNotNull(result); + assertTrue(result.matches("-?\\d*\\.\\d{2}"), "result does not match pattern: "+result); + } + + @Test + public void testRandomNumberWithinRange() { + List params = List.of("2", "10.5", "20.5"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= 10.5 && randomValue <= 20.5); + } + + @Test + public void testRandomNumberIncludesMin() { + List params = List.of("1", "10.5", "20.5"); + function = new AdvancedRandomNumberFunction() { + @Override + double getRandomValue(double minValue, BigDecimal range, double random) { + random = 0.0; + return super.getRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertEquals(result, "10.5"); + } + + @Test + public void testRandomNumberIncludesMax() { + List params = List.of("1", "10.5", "20.5"); + function = new AdvancedRandomNumberFunction() { + @Override + double getRandomValue(double minValue, BigDecimal range, double random) { + random = 1.0; + return super.getRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertEquals(result, "20.5"); + } + + @Test + public void testRandomNumberExcludeMin() { + List params = List.of("1", "10.5", "20.5", "true", "false"); + function = new AdvancedRandomNumberFunction() { + @Override + double getRandomValue(double minValue, BigDecimal range, double random) { + random = 0.0; + return super.getRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue > 10.5 && randomValue <= 20.5); + } + + @Test + public void testRandomNumberExcludeMax() { + List params = List.of("2", "10.5", "20.5", "false", "true"); + function = new AdvancedRandomNumberFunction() { + @Override + double getRandomValue(double minValue, BigDecimal range, double random) { + random = 1.0; + return super.getRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= 10.5 && randomValue < 20.5); + } + + @Test + public void testRandomInteger32EdgeCase() { + List params = List.of("0", "-2147483648", "2147483647", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Integer.MAX_VALUE && randomValue < Integer.MAX_VALUE); + } + + @Test + public void testRandomInteger32MinEqualsMaxEdgeCase() { + List params = List.of("0", "3", "3", "false", "false"); + for (int i =0;i<100;i++) { + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertEquals(randomValue, 3); + } + } + + + + // randomDouble('0','3','3','true','true') + // randomDouble('0','3','3','true','true') + + @Test + public void testRandomDouble32MinEqualsMaxEdgeCase() { + List params = List.of("2", "3.0", "3.0", "false", "false"); + for (int i =0;i<100;i++) { + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertEquals(randomValue, 3); + } + } + + @Test + public void testRandomInteger64EdgeCase() { + List params = List.of("0", "-9223372036854775808", "9223372036854775807", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >=-Long.MAX_VALUE && randomValue < Long.MAX_VALUE); + } + + @Test + public void testRandomNumberFloatEdgeCase() { + List params = List.of("0", "-3.4028235E38", "3.4028235E38", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Float.MAX_VALUE && randomValue < Float.MAX_VALUE); + } + + @Test + public void testRandomNumberDoubleEdgeCase() { + List params = List.of("0", "-1.7976931348623157E308", "1.7976931348623157E308", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Double.MAX_VALUE && randomValue < Double.MAX_VALUE); + } + + @Test + public void testInvalidDecimalPlaces() { + List params = List.of("-1"); // invalid decimalPlaces + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); + assertEquals(exception.getMessage(), "Invalid parameter definition. Decimal places must be a non-negative integer value."); + } + + @Test + public void testInvalidRange() { + List params = List.of("2", "20.5", "10.5"); // invalid range + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); + assertEquals(exception.getMessage(), "Invalid parameter definition. Min value must be less than max value."); + } + + @Test + public void testInvalidDecimalPlacesFormat() { + List params = List.of("xxx"); // invalid decimalPlaces + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); + assertEquals(exception.getMessage(), "Invalid parameter at index 1. xxx must be parsable to Integer."); + } + + @Test + public void testInvalidMinValueFormat() { + List params = List.of("1","xxx"); // invalid min value + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); + assertEquals(exception.getMessage(), "Invalid parameter at index 2. xxx must be parsable to Double."); + } + + @Test + public void testInvalidMaxValueFormat() { + List params = List.of("1", "1.1", "xxx"); // invalid max value + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Invalid parameter at index 3. xxx must be parsable to Double."); + } + + private T expectThrows(Class exceptionClass, Runnable runnable) { + try { + runnable.run(); + } catch (Throwable throwable) { + if (exceptionClass.isInstance(throwable)) { + return exceptionClass.cast(throwable); + } else { + throw new AssertionError("Unexpected exception type", throwable); + } + } + throw new AssertionError("Expected exception not thrown"); + } +} \ No newline at end of file diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java new file mode 100644 index 0000000000..dccbb4b0fc --- /dev/null +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java @@ -0,0 +1,75 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.functions.core; + +import static org.testng.Assert.assertTrue; + +import java.util.List; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class RandomPatternFunctionTest { + + private final RandomPatternFunction function = new RandomPatternFunction(); + private final TestContext context = new TestContext(); + + @Test(expectedExceptions = InvalidFunctionUsageException.class) + public void testExecuteWithNullParameterList() { + function.execute(null, context); + } + + @Test(expectedExceptions = InvalidFunctionUsageException.class) + public void testExecuteWithEmptyPattern() { + function.execute(List.of(""), context); + } + + @Test + public void testExecuteWithValidPattern() { + String pattern = "[a-zA-Z0-9]{10}"; + String result = function.execute(List.of(pattern), context); + assertTrue(result.matches(pattern), "Generated string does not match the pattern"); + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testExecuteWithInvalidPattern() { + String pattern = "[0-3]([a-c]|[e-g]{1"; // Invalid regex pattern with "Character range is out of order" + function.execute(List.of(pattern), context); + } + + @DataProvider(name = "patternProvider") + public Object[][] patternProvider() { + return new Object[][]{ + {"testExecuteWithComplexPattern", "(foo|bar)[0-9]{2,4}"}, + {"testIpv6", "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"}, + {"testIpv4", "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}"}, + {"testEmail", "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}"}, + {"testUri", "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})"} + }; + } + + @Test(dataProvider = "patternProvider") + public void testPatterns(String description, String pattern) { + for (int i = 0; i < 100; i++) { + String result = function.execute(List.of(pattern), context); + assertTrue(result.matches(pattern), "Generated string does not match the pattern: " + description); + } + } + + +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java index 47b42c3195..dc6269b8f4 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java @@ -16,6 +16,15 @@ package org.citrusframework.http.message; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_QUERY_PARAMS; +import static org.citrusframework.util.StringUtils.hasText; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; import org.citrusframework.message.Message; import org.citrusframework.message.MessageHeaders; @@ -38,8 +47,8 @@ private HttpMessageUtils() { */ public static void copy(Message from, HttpMessage to) { HttpMessage source; - if (from instanceof HttpMessage) { - source = (HttpMessage) from; + if (from instanceof HttpMessage httpMessage) { + source = httpMessage; } else { source = new HttpMessage(from); } @@ -65,4 +74,30 @@ public static void copy(HttpMessage from, HttpMessage to) { from.getHeaderData().forEach(to::addHeaderData); from.getCookies().forEach(to::cookie); } + + /** + * Extracts query parameters from the citrus HTTP message header and returns them as a map. + * + * @param httpMessage the HTTP message containing the query parameters in the header + * @return a map of query parameter names and their corresponding values + * @throws IllegalArgumentException if the query parameters are not formatted correctly + */ + public static Map> getQueryParameterMap(HttpMessage httpMessage) { + String queryParams = (String) httpMessage.getHeader(HTTP_QUERY_PARAMS); + if (hasText(queryParams)) { + return Arrays.stream(queryParams.split(",")) + .map(queryParameterKeyValue -> { + String[] keyAndValue = queryParameterKeyValue.split("=", 2); + if (keyAndValue.length == 0) { + throw new IllegalArgumentException("Query parameter must have a key."); + } + String key = keyAndValue[0]; + String value = keyAndValue.length > 1 ? keyAndValue[1] : ""; + return Pair.of(key, value); + }) + .collect(Collectors.groupingBy( + Pair::getLeft, Collectors.mapping(Pair::getRight, Collectors.toList()))); + } + return Collections.emptyMap(); + } } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java index 92edb71fe9..9bce6d1042 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java @@ -16,15 +16,24 @@ package org.citrusframework.http.message; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_COOKIE_PREFIX; +import static org.citrusframework.http.message.HttpMessageUtils.getQueryParameterMap; +import static org.citrusframework.message.MessageHeaders.ID; +import static org.citrusframework.message.MessageHeaders.MESSAGE_TYPE; +import static org.citrusframework.message.MessageHeaders.TIMESTAMP; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import jakarta.servlet.http.Cookie; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; - import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; -import org.citrusframework.message.MessageHeaders; import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; @@ -46,16 +55,16 @@ public void testCopy() { HttpMessageUtils.copy(from, to); - Assert.assertNotEquals(from.getId(), to.getId()); - Assert.assertEquals(to.getName(), "FooMessage"); - Assert.assertEquals(to.getPayload(String.class), "fooMessage"); - Assert.assertEquals(to.getHeaders().size(), 4L); - Assert.assertNotNull(to.getHeader(MessageHeaders.ID)); - Assert.assertNotNull(to.getHeader(MessageHeaders.MESSAGE_TYPE)); - Assert.assertNotNull(to.getHeader(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(to.getHeader("X-Foo"), "foo"); - Assert.assertEquals(to.getHeaderData().size(), 1L); - Assert.assertEquals(to.getHeaderData().get(0), "HeaderData"); + assertNotEquals(from.getId(), to.getId()); + assertEquals(to.getName(), "FooMessage"); + assertEquals(to.getPayload(String.class), "fooMessage"); + assertEquals(to.getHeaders().size(), 4L); + assertNotNull(to.getHeader(ID)); + assertNotNull(to.getHeader(MESSAGE_TYPE)); + assertNotNull(to.getHeader(TIMESTAMP)); + assertEquals(to.getHeader("X-Foo"), "foo"); + assertEquals(to.getHeaderData().size(), 1L); + assertEquals(to.getHeaderData().get(0), "HeaderData"); } @Test @@ -76,20 +85,20 @@ public void testCopyPreventExistingOverwritePayload() { HttpMessageUtils.copy(from, to); - Assert.assertNotEquals(from.getId(), to.getId()); - Assert.assertEquals(to.getName(), "FooMessage"); - Assert.assertEquals(to.getPayload(String.class), "fooMessage"); - Assert.assertEquals(to.getHeaders().size(), 7L); - Assert.assertNotNull(to.getHeader(MessageHeaders.ID)); - Assert.assertNotNull(to.getHeader(MessageHeaders.MESSAGE_TYPE)); - Assert.assertNotNull(to.getHeader(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(to.getHeader("X-Foo"), "foo"); - Assert.assertEquals(to.getHeader("X-Existing"), "existing"); - Assert.assertEquals(to.getHeader(HttpMessageHeaders.HTTP_COOKIE_PREFIX + "Foo"), "Foo=fooCookie"); - Assert.assertEquals(to.getHeader(HttpMessageHeaders.HTTP_COOKIE_PREFIX + "Existing"), "Existing=existingCookie"); - Assert.assertEquals(to.getHeaderData().size(), 2L); - Assert.assertEquals(to.getHeaderData().get(0), "ExistingHeaderData"); - Assert.assertEquals(to.getHeaderData().get(1), "HeaderData"); + assertNotEquals(from.getId(), to.getId()); + assertEquals(to.getName(), "FooMessage"); + assertEquals(to.getPayload(String.class), "fooMessage"); + assertEquals(to.getHeaders().size(), 7L); + assertNotNull(to.getHeader(ID)); + assertNotNull(to.getHeader(MESSAGE_TYPE)); + assertNotNull(to.getHeader(TIMESTAMP)); + assertEquals(to.getHeader("X-Foo"), "foo"); + assertEquals(to.getHeader("X-Existing"), "existing"); + assertEquals(to.getHeader(HTTP_COOKIE_PREFIX + "Foo"), "Foo=fooCookie"); + assertEquals(to.getHeader(HTTP_COOKIE_PREFIX + "Existing"), "Existing=existingCookie"); + assertEquals(to.getHeaderData().size(), 2L); + assertEquals(to.getHeaderData().get(0), "ExistingHeaderData"); + assertEquals(to.getHeaderData().get(1), "HeaderData"); } @Test @@ -104,19 +113,19 @@ public void testConvertAndCopy() { HttpMessageUtils.copy(from, to); - Assert.assertNotEquals(from.getId(), to.getId()); - Assert.assertEquals(to.getName(), "FooMessage"); - Assert.assertEquals(to.getPayload(String.class), "fooMessage"); - Assert.assertEquals(to.getHeader("X-Foo"), "foo"); - Assert.assertEquals(to.getHeaderData().size(), 1L); - Assert.assertEquals(to.getHeaderData().get(0), "HeaderData"); + assertNotEquals(from.getId(), to.getId()); + assertEquals(to.getName(), "FooMessage"); + assertEquals(to.getPayload(String.class), "fooMessage"); + assertEquals(to.getHeader("X-Foo"), "foo"); + assertEquals(to.getHeaderData().size(), 1L); + assertEquals(to.getHeaderData().get(0), "HeaderData"); } @Test(dataProvider = "queryParamStrings") public void testQueryParamsExtraction(String queryParamString, Map params) { HttpMessage message = new HttpMessage(); message.queryParams(queryParamString); - Assert.assertEquals(message.getQueryParams().size(), params.size()); + assertEquals(message.getQueryParams().size(), params.size()); params.forEach((key, value) -> Assert.assertTrue(message.getQueryParams().get(key).contains(value))); } @@ -136,4 +145,55 @@ public Object[][] queryParamStrings() { .collect(Collectors.toMap(keyValue -> keyValue[0], keyValue -> keyValue[1])) } }; } + + + @Test + public void testGetQueryParameterMapWithValues() { + HttpMessage httpMessage = new HttpMessage(); + httpMessage.queryParam("q1", "v1"); + httpMessage.queryParam("q1", "v2"); + httpMessage.queryParam("q2", "v3"); + httpMessage.queryParam("q2", "v4"); + httpMessage.queryParam("q3", "v5"); + + Map> queryParams = getQueryParameterMap(httpMessage); + + assertEquals(queryParams.size(), 3); + List q1Values = queryParams.get("q1"); + assertTrue(q1Values.contains("v1")); + assertTrue(q1Values.contains("v2")); + List q2Values = queryParams.get("q2"); + assertTrue(q2Values.contains("v3")); + assertTrue(q2Values.contains("v4")); + List q3Values = queryParams.get("q3"); + assertTrue(q3Values.contains("v5")); + } + + @Test + public void testGetQueryParameterMapWithNoValues() { + HttpMessage httpMessage = new HttpMessage(); + + Map> queryParams = getQueryParameterMap(httpMessage); + + assertTrue(queryParams.isEmpty()); + } + + @Test + public void testGetQueryParameterMapWithMissingValues() { + HttpMessage httpMessage = new HttpMessage(); + httpMessage.queryParam("q1", ""); + httpMessage.queryParam("q2", ""); + httpMessage.queryParam("q3", ""); + + Map> queryParams = getQueryParameterMap(httpMessage); + + assertEquals(queryParams.size(), 3); + List q1Values = queryParams.get("q1"); + assertTrue(q1Values.contains("")); + List q2Values = queryParams.get("q2"); + assertTrue(q2Values.contains("")); + List q3Values = queryParams.get("q3"); + assertTrue(q3Values.contains("")); + } + } From 519471b70db4eaf418955f927507cf4e9e57a125 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Mon, 8 Jul 2024 00:12:03 +0200 Subject: [PATCH 07/47] feat(#1175): added random generator framework Framework was added in favour of OpenApiTestDataGenerator implementation --- .../openapi/OpenApiTestDataGenerator.java | 601 +----------------- .../OpenApiTestValidationDataGenerator.java | 12 +- .../OpenApiClientRequestActionBuilder.java | 9 +- .../OpenApiServerResponseActionBuilder.java | 27 +- .../openapi/random/RandomArrayGenerator.java | 51 ++ .../random/RandomCompositeGenerator.java | 74 +++ .../openapi/random/RandomConfiguration.java | 63 ++ .../openapi/random/RandomContext.java | 120 ++++ .../{util => random}/RandomElement.java | 2 +- .../openapi/random/RandomEnumGenerator.java | 25 + .../openapi/random/RandomGenerator.java | 61 ++ .../random/RandomGeneratorBuilder.java | 62 ++ .../{util => random}/RandomModelBuilder.java | 56 +- .../{util => random}/RandomModelWriter.java | 4 +- .../openapi/random/RandomNumberGenerator.java | 155 +++++ .../openapi/random/RandomObjectGenerator.java | 58 ++ .../openapi/random/RandomStringGenerator.java | 39 ++ .../openapi/util/OpenApiUtils.java | 11 + .../openapi/OpenApiTestDataGeneratorTest.java | 122 +--- .../random/OasRandomConfigurationTest.java | 179 ++++++ .../random/RandomArrayGeneratorTest.java | 106 +++ .../random/RandomCompositeGeneratorTest.java | 90 +++ .../openapi/random/RandomContextTest.java | 76 +++ .../{util => random}/RandomElementTest.java | 2 +- .../random/RandomEnumGeneratorTest.java | 77 +++ .../random/RandomGeneratorBuilderTest.java | 92 +++ .../openapi/random/RandomGeneratorTest.java | 152 +++++ .../RandomModelBuilderTest.java | 48 +- .../random/RandomNumberGeneratorTest.java | 217 +++++++ .../random/RandomObjectGeneratorTest.java | 134 ++++ .../random/RandomStringGeneratorTest.java | 70 ++ ...OpenApiRequestValidationProcessorTest.java | 4 +- .../OpenApiRequestValidatorTest.java | 9 +- ...penApiResponseValidationProcessorTest.java | 4 +- .../OpenApiResponseValidatorTest.java | 36 +- .../functions/DefaultFunctionLibrary.java | 2 +- .../core/AdvancedRandomNumberFunction.java | 201 ++++-- .../functions/core/RandomPatternFunction.java | 5 +- .../functions/core/RandomStringFunction.java | 23 +- .../org/citrusframework/util/StringUtils.java | 2 +- .../AdvancedRandomNumberFunctionTest.java | 416 ++++++++++++ .../core/RandomDoubleFunctionTest.java | 246 ------- .../core/RandomStringFunctionTest.java | 32 +- 43 files changed, 2669 insertions(+), 1106 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/{util => random}/RandomElement.java (98%) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/{util => random}/RandomModelBuilder.java (62%) rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/{util => random}/RandomModelWriter.java (97%) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java rename connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/{util => random}/RandomElementTest.java (98%) create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java rename connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/{util => random}/RandomModelBuilderTest.java (74%) create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java create mode 100644 core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java delete mode 100644 core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index 74deef213f..106d06fd36 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -17,230 +17,43 @@ package org.citrusframework.openapi; import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; -import org.citrusframework.openapi.model.OasModelHelper; -import org.citrusframework.openapi.util.OpenApiUtils; -import org.citrusframework.openapi.util.RandomModelBuilder; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; - -import static java.lang.Boolean.TRUE; -import static java.lang.String.format; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; -import static org.citrusframework.util.StringUtils.hasText; -import static org.citrusframework.util.StringUtils.quote; -import static org.springframework.util.CollectionUtils.isEmpty; +import org.citrusframework.openapi.random.RandomContext; /** * Generates proper payloads and validation expressions based on Open API specification rules. */ public abstract class OpenApiTestDataGenerator { - public static final BigDecimal THOUSAND = new BigDecimal(1000); - public static final BigDecimal HUNDRED = BigDecimal.valueOf(100); - public static final BigDecimal MINUS_THOUSAND = new BigDecimal(-1000); - private OpenApiTestDataGenerator() { // Static access only } - private static final Map SPECIAL_FORMATS = Map.of( - "email", "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}", - "uri", - "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})", - "hostname", - "(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])", - "ipv4", - "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)", - "ipv6", - "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"); - /** * Creates payload from schema for outbound message. */ public static String createOutboundPayload(OasSchema schema, OpenApiSpecification specification) { - return createOutboundPayload(schema, - OasModelHelper.getSchemaDefinitions(specification.getOpenApiDoc(null)), specification); - } - - /** - * Creates payload from schema for outbound message. - */ - public static String createOutboundPayload(OasSchema schema, Map definitions, - OpenApiSpecification specification) { - return createOutboundPayload(schema, definitions, specification, new HashSet<>()); - } - - /** - * Creates payload from schema for outbound message. - */ - private static String createOutboundPayload(OasSchema schema, - Map definitions, - OpenApiSpecification specification, Set visitedRefSchemas) { - RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); - createOutboundPayloadAsMap(randomModelBuilder, schema, definitions, specification, - visitedRefSchemas); - return randomModelBuilder.toString(); - } - - private static void createOutboundPayloadAsMap(RandomModelBuilder randomModelBuilder, - OasSchema schema, - Map definitions, - OpenApiSpecification specification, Set visitedRefSchemas) { - - if (hasText(schema.$ref) && visitedRefSchemas.contains(schema)) { - // Avoid recursion - return; - } - - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - createOutboundPayloadAsMap(randomModelBuilder, resolved, definitions, specification, - visitedRefSchemas); - return; - } - - if (OasModelHelper.isCompositeSchema(schema)) { - createComposedSchema(randomModelBuilder, schema, true, specification, - visitedRefSchemas); - return; - } - - switch (schema.type) { - case OpenApiConstants.TYPE_OBJECT -> - createRandomObjectSchemeMap(randomModelBuilder, schema, specification, - visitedRefSchemas); - case OpenApiConstants.TYPE_ARRAY -> - createRandomArrayValueMap(randomModelBuilder, schema, specification, - visitedRefSchemas); - case OpenApiConstants.TYPE_STRING, TYPE_INTEGER, OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_BOOLEAN -> - createRandomValueExpressionMap(randomModelBuilder, schema, true); - default -> randomModelBuilder.appendSimple("\"\""); - } + RandomContext randomContext = new RandomContext(specification, true); + randomContext.generate(schema); + return randomContext.getRandomModelBuilder().write(); } /** * Use test variable with given name if present or create value from schema with random values */ - public static String createRandomValueExpression(String name, OasSchema schema, - Map definitions, - boolean quotes, OpenApiSpecification specification, TestContext context) { + public static String createRandomValueExpression(String name, OasSchema schema, OpenApiSpecification specification, + TestContext context) { + if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } - return createRandomValueExpression(schema, definitions, quotes, specification); - } - - /** - * Create payload from schema with random values. - */ - public static String createRandomValueExpression(OasSchema schema, - Map definitions, boolean quotes, - OpenApiSpecification specification) { - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createRandomValueExpression(resolved, definitions, quotes, specification); - } - - StringBuilder payload = new StringBuilder(); - if (OasModelHelper.isObjectType(schema) || OasModelHelper.isArrayType(schema)) { - payload.append(createOutboundPayload(schema, definitions, specification)); - } else if (OpenApiConstants.TYPE_STRING.equals(schema.type)) { - if (quotes) { - payload.append("\""); - } - if (OpenApiConstants.FORMAT_DATE.equals(schema.format)) { - payload.append("citrus:currentDate('yyyy-MM-dd')"); - } else if (OpenApiConstants.FORMAT_DATE_TIME.equals(schema.format)) { - payload.append("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')"); - } else if (hasText(schema.pattern)) { - payload.append("citrus:randomValue(").append(schema.pattern).append(")"); - } else if (!isEmpty(schema.enum_)) { - payload.append("citrus:randomEnumValue(").append( - schema.enum_.stream().map(value -> "'" + value + "'") - .collect(Collectors.joining(","))).append(")"); - } else if (OpenApiConstants.FORMAT_UUID.equals(schema.format)) { - payload.append("citrus:randomUUID()"); - } else { - if (schema.format != null && SPECIAL_FORMATS.containsValue(schema.format)) { - payload.append("citrus:randomValue('") - .append(SPECIAL_FORMATS.get(schema.format)).append("')"); - } else { - int length = 10; - if (schema.maxLength != null && schema.maxLength.intValue() > 0) { - length = schema.maxLength.intValue(); - } else if (schema.minLength != null && schema.minLength.intValue() > 0) { - length = schema.minLength.intValue(); - } - - payload.append("citrus:randomString(").append(length).append(")"); - } - } - - if (quotes) { - payload.append("\""); - } - } else if (OpenApiUtils.isAnyNumberScheme(schema)) { - payload.append("citrus:randomNumber(8)"); - } else if (OpenApiConstants.TYPE_BOOLEAN.equals(schema.type)) { - payload.append("citrus:randomEnumValue('true', 'false')"); - } else if (quotes) { - payload.append("\"\""); - } - - return payload.toString(); - } - - public static T createRawRandomValueExpression(OasSchema schema, - Map definitions, boolean quotes, - OpenApiSpecification specification, TestContext context) { - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); - return createRawRandomValueExpression(resolved, definitions, quotes, specification, - context); - } - - StringBuilder payload = new StringBuilder(); - if (OpenApiConstants.TYPE_STRING.equals(schema.type) || OasModelHelper.isObjectType(schema) - || OasModelHelper.isArrayType(schema)) { - return (T) createRandomValueExpression(schema, definitions, quotes, specification); - } else if (OpenApiConstants.TYPE_NUMBER.equals(schema.type)) { - return (T) Double.valueOf( - context.replaceDynamicContentInString("citrus:randomNumber(8,2)")); - } else if ("integer".equals(schema.type)) { - return (T) Double.valueOf( - context.replaceDynamicContentInString("citrus:randomNumber(8)")); - } else if ("boolean".equals(schema.type)) { - return (T) Boolean.valueOf( - context.replaceDynamicContentInString("citrus:randomEnumValue('true', 'false')")); - } else if (quotes) { - payload.append("\"\""); - } - - return (T) payload.toString(); - } - - /** - * Checks if given field name is in list of required fields for this schema. - */ - private static boolean isRequired(OasSchema schema, String field) { - if (schema.required == null) { - return true; - } + RandomContext randomContext = new RandomContext(specification, false); + randomContext.generate(schema); + return randomContext.getRandomModelBuilder().write(); - return schema.required.contains(field); } /** @@ -249,398 +62,20 @@ private static boolean isRequired(OasSchema schema, String field) { */ public static String createRandomValueExpression(String name, OasSchema schema, TestContext context) { + if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } - RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); - createRandomValueExpressionMap(randomModelBuilder, schema, false); - return randomModelBuilder.toString(); - } - - public static String createRandomValueExpression(OasSchema schema, boolean quotes) { - RandomModelBuilder randomModelBuilder = new RandomModelBuilder(); - createRandomValueExpressionMap(randomModelBuilder, schema, quotes); - return randomModelBuilder.toString(); - } - - /** - * Create random value expression using functions according to schema type and format. - */ - private static void createRandomValueExpressionMap(RandomModelBuilder randomModelBuilder, - OasSchema schema, boolean quotes) { - - switch (schema.type) { - case OpenApiConstants.TYPE_STRING -> { - if (OpenApiConstants.FORMAT_DATE.equals(schema.format)) { - randomModelBuilder.appendSimple( - quote("citrus:currentDate('yyyy-MM-dd')", quotes)); - } else if (OpenApiConstants.FORMAT_DATE_TIME.equals(schema.format)) { - randomModelBuilder.appendSimple( - quote("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')", quotes)); - } else if (hasText(schema.pattern)) { - randomModelBuilder.appendSimple( - quote("citrus:randomValue('" + schema.pattern + "')", quotes)); - } else if (!isEmpty(schema.enum_)) { - randomModelBuilder.appendSimple( - quote("citrus:randomEnumValue(" + (java.lang.String.join(",", schema.enum_)) - + ")", quotes)); - } else if (OpenApiConstants.FORMAT_UUID.equals(schema.format)) { - randomModelBuilder.appendSimple(quote("citrus:randomUUID()", quotes)); - } else { - - if (schema.format != null && SPECIAL_FORMATS.containsKey(schema.format)) { - randomModelBuilder.appendSimple(quote( - "citrus:randomValue('" + SPECIAL_FORMATS.get(schema.format) + "')", - quotes)); - } else { - long minLength = - schema.minLength != null && schema.minLength.longValue() > 0 - ? schema.minLength.longValue() : 10L; - long maxLength = - schema.maxLength != null && schema.maxLength.longValue() > 0 - ? schema.maxLength.longValue() : 10L; - long length = ThreadLocalRandom.current() - .nextLong(minLength, maxLength + 1); - randomModelBuilder.appendSimple( - quote("citrus:randomString(%s)".formatted(length), quotes)); - } - } - } - case OpenApiConstants.TYPE_NUMBER, TYPE_INTEGER -> - // No quotes for numbers - randomModelBuilder.appendSimple(createRandomNumber(schema)); - case OpenApiConstants.TYPE_BOOLEAN -> - // No quotes for boolean - randomModelBuilder.appendSimple("citrus:randomEnumValue('true', 'false')"); - default -> randomModelBuilder.appendSimple(""); - } - } - - private static String createRandomNumber(OasSchema schema) { - Number multipleOf = schema.multipleOf; - - boolean exclusiveMaximum = TRUE.equals(schema.exclusiveMaximum); - boolean exclusiveMinimum = TRUE.equals(schema.exclusiveMinimum); - - BigDecimal[] bounds = determineBounds(schema); - - BigDecimal minimum = bounds[0]; - BigDecimal maximum = bounds[1]; - - if (multipleOf != null) { - minimum = exclusiveMinimum ? incrementToExclude(minimum) : minimum; - maximum = exclusiveMaximum ? decrementToExclude(maximum) : maximum; - return createMultipleOf(minimum, maximum, new BigDecimal(multipleOf.toString())); - } - - return format( - "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s')", - determineDecimalPlaces(schema, minimum, maximum), - minimum, - maximum, - exclusiveMinimum, - exclusiveMaximum - ); + RandomContext randomContext = new RandomContext(); + randomContext.generate(schema); + return randomContext.getRandomModelBuilder().write(); } - /** - * Determines the number of decimal places to use based on the given schema and minimum/maximum values. - * For integer types, it returns 0. For other types, it returns the maximum number of decimal places - * found between the minimum and maximum values, with a minimum of 2 decimal places. - */ - private static int determineDecimalPlaces(OasSchema schema, BigDecimal minimum, - BigDecimal maximum) { - if (TYPE_INTEGER.equals(schema.type)) { - return 0; - } else { - return - Math.max(2, Math.max(findLeastSignificantDecimalPlace(minimum), - findLeastSignificantDecimalPlace(maximum))); - } + public static String createRandomValueExpression(OasSchema schema) { + RandomContext randomContext = new RandomContext(); + randomContext.generate(schema); + return randomContext.getRandomModelBuilder().write(); } - /** - * Determine some reasonable bounds for a random number - */ - private static BigDecimal[] determineBounds(OasSchema schema) { - Number maximum = schema.maximum; - Number minimum = schema.minimum; - Number multipleOf = schema.multipleOf; - - BigDecimal bdMinimum; - BigDecimal bdMaximum; - if (minimum == null && maximum == null) { - bdMinimum = MINUS_THOUSAND; - bdMaximum = THOUSAND; - } else if (minimum == null) { - // Determine min relative to max - bdMaximum = new BigDecimal(maximum.toString()); - - if (multipleOf != null) { - bdMinimum = bdMaximum.subtract(new BigDecimal(multipleOf.toString()).abs().multiply( - HUNDRED)); - } else { - bdMinimum = bdMaximum.subtract(bdMaximum.multiply(BigDecimal.valueOf(2)).max( - THOUSAND)); - } - } else if (maximum == null) { - // Determine max relative to min - bdMinimum = new BigDecimal(minimum.toString()); - if (multipleOf != null) { - bdMaximum = bdMinimum.add(new BigDecimal(multipleOf.toString()).abs().multiply( - HUNDRED)); - } else { - bdMaximum = bdMinimum.add(bdMinimum.multiply(BigDecimal.valueOf(2)).max(THOUSAND)); - } - } else { - bdMaximum = new BigDecimal(maximum.toString()); - bdMinimum = new BigDecimal(minimum.toString()); - } - - return new BigDecimal[]{bdMinimum, bdMaximum}; - } - - /** - * Create a random schema value - * - * @param schema the type to create - * @param visitedRefSchemas the schemas already created during descent, used to avoid recursion - */ - private static void createRandomValue(RandomModelBuilder randomModelBuilder, OasSchema schema, - boolean quotes, - OpenApiSpecification specification, Set visitedRefSchemas) { - if (hasText(schema.$ref) && visitedRefSchemas.contains(schema)) { - // Avoid recursion - return; - } - - if (OasModelHelper.isReferenceType(schema)) { - OasSchema resolved = OasModelHelper.getSchemaDefinitions( - specification.getOpenApiDoc(null)) - .get(OasModelHelper.getReferenceName(schema.$ref)); - createRandomValue(randomModelBuilder, resolved, quotes, specification, - visitedRefSchemas); - return; - } - - if (OasModelHelper.isCompositeSchema(schema)) { - createComposedSchema(randomModelBuilder, schema, quotes, specification, - visitedRefSchemas); - return; - } - - switch (schema.type) { - case OpenApiConstants.TYPE_OBJECT -> - createRandomObjectSchemeMap(randomModelBuilder, schema, specification, - visitedRefSchemas); - case OpenApiConstants.TYPE_ARRAY -> - createRandomArrayValueMap(randomModelBuilder, schema, specification, - visitedRefSchemas); - case OpenApiConstants.TYPE_STRING, TYPE_INTEGER, OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_BOOLEAN -> - createRandomValueExpressionMap(randomModelBuilder, schema, quotes); - default -> { - if (quotes) { - randomModelBuilder.appendSimple("\"\""); - } else { - randomModelBuilder.appendSimple(""); - } - } - } - } - - private static void createRandomObjectSchemeMap(RandomModelBuilder randomModelBuilder, - OasSchema objectSchema, - OpenApiSpecification specification, Set visitedRefSchemas) { - - randomModelBuilder.object(() -> { - if (objectSchema.properties != null) { - for (Map.Entry entry : objectSchema.properties.entrySet()) { - if (specification.isGenerateOptionalFields() || isRequired(objectSchema, - entry.getKey())) { - randomModelBuilder.property(entry.getKey(), () -> - createRandomValue(randomModelBuilder, entry.getValue(), true, - specification, - visitedRefSchemas)); - } - } - } - }); - } - - private static void createComposedSchema(RandomModelBuilder randomModelBuilder, - OasSchema schema, boolean quotes, - OpenApiSpecification specification, Set visitedRefSchemas) { - - if (!isEmpty(schema.allOf)) { - createAllOff(randomModelBuilder, schema, quotes, specification, visitedRefSchemas); - } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.anyOf)) { - createAnyOf(randomModelBuilder, oas30Schema, quotes, specification, visitedRefSchemas); - } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.oneOf)) { - createOneOf(randomModelBuilder, oas30Schema.oneOf, quotes, specification, - visitedRefSchemas); - } - } - - private static void createOneOf(RandomModelBuilder randomModelBuilder, List schemas, - boolean quotes, - OpenApiSpecification specification, Set visitedRefSchemas) { - int schemaIndex = ThreadLocalRandom.current().nextInt(schemas.size()); - randomModelBuilder.object(() -> - createRandomValue(randomModelBuilder, schemas.get(schemaIndex), quotes, specification, - visitedRefSchemas)); - } - - private static void createAnyOf(RandomModelBuilder randomModelBuilder, Oas30Schema schema, - boolean quotes, - OpenApiSpecification specification, Set visitedRefSchemas) { - - randomModelBuilder.object(() -> { - boolean anyAdded = false; - for (OasSchema oneSchema : schema.anyOf) { - if (ThreadLocalRandom.current().nextBoolean()) { - createRandomValue(randomModelBuilder, oneSchema, quotes, specification, - visitedRefSchemas); - anyAdded = true; - } - } - - // Add at least one - if (!anyAdded) { - createOneOf(randomModelBuilder, schema.anyOf, quotes, specification, - visitedRefSchemas); - } - }); - } - - private static Map createAllOff(RandomModelBuilder randomModelBuilder, - OasSchema schema, boolean quotes, - OpenApiSpecification specification, Set visitedRefSchemas) { - Map allOf = new HashMap<>(); - - randomModelBuilder.object(() -> { - for (OasSchema oneSchema : schema.allOf) { - createRandomValue(randomModelBuilder, oneSchema, quotes, specification, - visitedRefSchemas); - } - }); - - return allOf; - } - - private static String createMultipleOf( - BigDecimal minimum, - BigDecimal maximum, - BigDecimal multipleOf - ) { - - BigDecimal lowestMultiple = lowestMultipleOf(minimum, multipleOf); - BigDecimal largestMultiple = largestMultipleOf(maximum, multipleOf); - - // Check if there are no valid multiples in the range - if (lowestMultiple.compareTo(largestMultiple) > 0) { - return null; - } - - BigDecimal range = largestMultiple.subtract(lowestMultiple) - .divide(multipleOf, RoundingMode.DOWN); - - // Don't go for incredible large numbers - if (range.compareTo(BigDecimal.valueOf(11)) > 0) { - range = BigDecimal.valueOf(10); - } - - long factor = 0; - if (range.compareTo(BigDecimal.ZERO) != 0) { - factor = ThreadLocalRandom.current().nextLong(1, range.longValue() + 1); - } - BigDecimal randomMultiple = lowestMultiple.add( - multipleOf.multiply(BigDecimal.valueOf(factor))); - randomMultiple = randomMultiple.setScale(findLeastSignificantDecimalPlace(multipleOf), - RoundingMode.HALF_UP); - - return randomMultiple.toString(); - } - - /** - * Create a random array value. - * - * @param schema the type to create - * @param visitedRefSchemas the schemas already created during descent, used to avoid recursion - */ - @SuppressWarnings("rawtypes") - private static void createRandomArrayValueMap(RandomModelBuilder randomModelBuilder, - OasSchema schema, - OpenApiSpecification specification, Set visitedRefSchemas) { - Object items = schema.items; - - if (items instanceof OasSchema itemsSchema) { - createRandomArrayValueWithSchemaItem(randomModelBuilder, schema, itemsSchema, - specification, - visitedRefSchemas); - } else { - throw new UnsupportedOperationException( - "Random array creation for an array with items having different schema is currently not supported!"); - } - } - - private static void createRandomArrayValueWithSchemaItem(RandomModelBuilder randomModelBuilder, - OasSchema schema, - OasSchema itemsSchema, OpenApiSpecification specification, - Set visitedRefSchemas) { - Number minItems = schema.minItems; - minItems = minItems != null ? minItems : 1; - Number maxItems = schema.maxItems; - maxItems = maxItems != null ? maxItems : 9; - - int nItems = ThreadLocalRandom.current() - .nextInt(minItems.intValue(), maxItems.intValue() + 1); - - randomModelBuilder.array(() -> { - for (int i = 0; i < nItems; i++) { - createRandomValue(randomModelBuilder, itemsSchema, true, specification, - visitedRefSchemas); - } - }); - } - - static BigDecimal largestMultipleOf(BigDecimal highest, BigDecimal multipleOf) { - RoundingMode roundingMode = - highest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.UP : RoundingMode.DOWN; - BigDecimal factor = highest.divide(multipleOf, 0, roundingMode); - return multipleOf.multiply(factor); - } - - static BigDecimal lowestMultipleOf(BigDecimal lowest, BigDecimal multipleOf) { - RoundingMode roundingMode = - lowest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.DOWN : RoundingMode.UP; - BigDecimal factor = lowest.divide(multipleOf, 0, roundingMode); - return multipleOf.multiply(factor); - } - - static BigDecimal incrementToExclude(BigDecimal val) { - return val.add(determineIncrement(val)) - .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); - } - - static BigDecimal decrementToExclude(BigDecimal val) { - return val.subtract(determineIncrement(val)) - .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); - } - - static BigDecimal determineIncrement(BigDecimal number) { - return BigDecimal.valueOf(1.0d / (Math.pow(10d, findLeastSignificantDecimalPlace(number)))); - } - - static int findLeastSignificantDecimalPlace(BigDecimal number) { - number = number.stripTrailingZeros(); - - String[] parts = number.toPlainString().split("\\."); - - if (parts.length == 1) { - return 0; - } - - return parts[1].length(); - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java index 3f9e123679..95033bb26c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java @@ -175,7 +175,7 @@ private static String createValidationExpression(OasSchema schema) { } switch (schema.type) { - case "string" : + case OpenApiConstants.TYPE_STRING : if (schema.format != null && schema.format.equals("date")) { return "@matchesDatePattern('yyyy-MM-dd')@"; } else if (schema.format != null && schema.format.equals("date-time")) { @@ -190,7 +190,7 @@ private static String createValidationExpression(OasSchema schema) { } case OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_INTEGER: return "@isNumber()@"; - case "boolean" : + case OpenApiConstants.TYPE_BOOLEAN : return "@matches(true|false)@"; default: return "@ignore@"; @@ -219,7 +219,7 @@ public static String createValidationRegex(@Nullable OasSchema schema) { } switch (schema.type) { - case "string" : + case OpenApiConstants.TYPE_STRING: if (schema.format != null && schema.format.equals("date")) { return "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])"; } else if (schema.format != null && schema.format.equals("date-time")) { @@ -227,7 +227,7 @@ public static String createValidationRegex(@Nullable OasSchema schema) { } else if (hasText(schema.pattern)) { return schema.pattern; } else if (!isEmpty(schema.enum_)) { - return "(" + (String.join("|", schema.enum_)) + ")"; + return "(" + String.join("|", schema.enum_) + ")"; } else if (schema.format != null && schema.format.equals("uuid")) { return "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; } else { @@ -235,9 +235,9 @@ public static String createValidationRegex(@Nullable OasSchema schema) { } case OpenApiConstants.TYPE_NUMBER: return "[0-9]+\\.?[0-9]*"; - case "integer" : + case OpenApiConstants.TYPE_INTEGER: return "[0-9]+"; - case "boolean" : + case OpenApiConstants.TYPE_BOOLEAN: return "(true|false)"; default: return ""; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index 616e5b119b..a7722559f1 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -132,7 +132,7 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter if (context.getVariables().containsKey(parameter.getName())) { parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; } else { - parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema, false); + parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema); } randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") .matcher(randomizedPath) @@ -151,8 +151,7 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter private void setSpecifiedBody(TestContext context, OasOperation operation) { Optional body = OasModelHelper.getRequestBodySchema( openApiSpec.getOpenApiDoc(context), operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), openApiSpec))); + body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, openApiSpec))); } private void setSpecifiedQueryParameters(TestContext context, OasOperation operation) { @@ -179,9 +178,7 @@ private void setSpecifiedHeaders(TestContext context, OasOperation operation) { .forEach(param -> { if(httpMessage.getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, - OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc( - context)), false, openApiSpec, context)); + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, openApiSpec, context)); } }); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index d5914d336e..3b4a522f92 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -24,7 +24,6 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; -import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; @@ -160,26 +159,24 @@ public Message build(TestContext context, String messageType) { } private void fillRandomData(OperationPathAdapter operationPathAdapter, TestContext context) { - OasDocument oasDocument = openApiSpec.getOpenApiDoc(context); if (operationPathAdapter.operation().responses != null) { - buildResponse(context, operationPathAdapter.operation(), oasDocument); + buildResponse(context, operationPathAdapter.operation()); } } - private void buildResponse(TestContext context, OasOperation operation, - OasDocument oasDocument) { + private void buildResponse(TestContext context, OasOperation operation) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( openApiSpec.getOpenApiDoc(context), operation, statusCode, null); if (responseForRandomGeneration.isPresent()) { - buildRandomHeaders(context, oasDocument, responseForRandomGeneration.get()); - buildRandomPayload(operation, oasDocument, responseForRandomGeneration.get()); + buildRandomHeaders(context, responseForRandomGeneration.get()); + buildRandomPayload(operation, responseForRandomGeneration.get()); } } - private void buildRandomHeaders(TestContext context, OasDocument oasDocument, OasResponse response) { + private void buildRandomHeaders(TestContext context, OasResponse response) { Set filteredHeaders = new HashSet<>(getMessage().getHeaders().keySet()); Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains( entry.getKey()); @@ -191,7 +188,6 @@ private void buildRandomHeaders(TestContext context, OasDocument oasDocument, Oa .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), entry.getValue(), - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context)))) ); @@ -209,8 +205,7 @@ private void buildRandomHeaders(TestContext context, OasDocument oasDocument, Oa + CitrusSettings.VARIABLE_SUFFIX))))); } - private void buildRandomPayload(OasOperation operation, OasDocument oasDocument, - OasResponse response) { + private void buildRandomPayload(OasOperation operation, OasResponse response) { Optional> schemaForMediaTypeOptional; if (statusCode.startsWith("2")) { @@ -227,7 +222,7 @@ private void buildRandomPayload(OasOperation operation, OasDocument oasDocument, OasAdapter schemaForMediaType = schemaForMediaTypeOptional.get(); if (getMessage().getPayload() == null || ( getMessage().getPayload() instanceof String string && string.isEmpty())) { - createRandomPayload(getMessage(), oasDocument, schemaForMediaType); + createRandomPayload(getMessage(), schemaForMediaType); } // If we have a schema and a media type and the content type has not yet been set, do it. @@ -238,7 +233,7 @@ private void buildRandomPayload(OasOperation operation, OasDocument oasDocument, } } - private void createRandomPayload(HttpMessage message, OasDocument oasDocument, OasAdapter schemaForMediaType) { + private void createRandomPayload(HttpMessage message, OasAdapter schemaForMediaType) { if (schemaForMediaType.node() == null) { // No schema means no payload, no type @@ -246,13 +241,11 @@ private void createRandomPayload(HttpMessage message, OasDocument oasDocument, O } else { if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { // Schema but plain text - message.setPayload(createOutboundPayload(schemaForMediaType.node(), - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); + message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpec)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.adapted())) { // Json Schema - message.setPayload(createOutboundPayload(schemaForMediaType.node(), - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec)); + message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpec)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java new file mode 100644 index 0000000000..afee6f3f68 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java @@ -0,0 +1,51 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.concurrent.ThreadLocalRandom; +import org.citrusframework.openapi.model.OasModelHelper; + +/** + * A generator for producing random arrays based on an OpenAPI schema. This class extends the + * {@link RandomGenerator} and provides a specific implementation for generating random arrays + * with constraints defined in the schema. + * + *

The generator supports arrays with items of a single schema type. If the array's items have + * different schemas, an {@link UnsupportedOperationException} will be thrown.

s + * + */ +public class RandomArrayGenerator extends RandomGenerator { + + @Override + public boolean handles(OasSchema other) { + return OasModelHelper.isArrayType(other); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + Object items = schema.items; + + if (items instanceof OasSchema itemsSchema) { + createRandomArrayValueWithSchemaItem(randomContext, schema, itemsSchema); + } else { + throw new UnsupportedOperationException( + "Random array creation for an array with items having different schema is currently not supported!"); + } + } + + private static void createRandomArrayValueWithSchemaItem(RandomContext randomContext, + OasSchema schema, + OasSchema itemsSchema) { + + Number minItems = schema.minItems != null ? schema.minItems : 1; + Number maxItems = schema.maxItems != null ? schema.maxItems : 10; + + int nItems = ThreadLocalRandom.current() + .nextInt(minItems.intValue(), maxItems.intValue() + 1); + + randomContext.getRandomModelBuilder().array(() -> { + for (int i = 0; i < nItems; i++) { + randomContext.generate(itemsSchema); + } + }); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java new file mode 100644 index 0000000000..6a7877ca39 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java @@ -0,0 +1,74 @@ +package org.citrusframework.openapi.random; + +import static org.springframework.util.CollectionUtils.isEmpty; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; +import org.citrusframework.openapi.model.OasModelHelper; + +/** + * A generator for producing random composite schemas based on an OpenAPI schema. This class extends + * the {@link RandomGenerator} and provides a specific implementation for generating composite schemas + * with constraints defined in the schema. + * + *

The generator supports composite schemas, which include `allOf`, `anyOf`, and `oneOf` constructs.

+ */ +public class RandomCompositeGenerator extends RandomGenerator { + + @Override + public boolean handles(OasSchema other) { + return OasModelHelper.isCompositeSchema(other); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + + if (!isEmpty(schema.allOf)) { + createAllOff(randomContext, schema); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.anyOf)) { + createAnyOf(randomContext, oas30Schema); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.oneOf)) { + createOneOf(randomContext, oas30Schema.oneOf); + } + } + + private static void createOneOf(RandomContext randomContext, List schemas) { + int schemaIndex = ThreadLocalRandom.current().nextInt(schemas.size()); + randomContext.getRandomModelBuilder().object(() -> + randomContext.generate(schemas.get(schemaIndex))); + } + + private static void createAnyOf(RandomContext randomContext, Oas30Schema schema) { + + randomContext.getRandomModelBuilder().object(() -> { + boolean anyAdded = false; + for (OasSchema oneSchema : schema.anyOf) { + if (ThreadLocalRandom.current().nextBoolean()) { + randomContext.generate(oneSchema); + anyAdded = true; + } + } + + // Add at least one + if (!anyAdded) { + createOneOf(randomContext, schema.anyOf); + } + }); + } + + private static Map createAllOff(RandomContext randomContext, OasSchema schema) { + Map allOf = new HashMap<>(); + + randomContext.getRandomModelBuilder().object(() -> { + for (OasSchema oneSchema : schema.allOf) { + randomContext.generate(oneSchema); + } + }); + + return allOf; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java new file mode 100644 index 0000000000..c986a16eb3 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java @@ -0,0 +1,63 @@ +package org.citrusframework.openapi.random; + +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE_TIME; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_BOOLEAN; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; +import static org.citrusframework.openapi.random.RandomGenerator.ANY; +import static org.citrusframework.openapi.random.RandomGenerator.NULL_GENERATOR; +import static org.citrusframework.openapi.random.RandomGeneratorBuilder.builder; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Configuration class that initializes and manages a list of random generators + * for producing random data based on an OpenAPI schema. This class is a singleton + * and provides a static instance {@code RANDOM_CONFIGURATION} for global access. + */ +public class RandomConfiguration { + + private static final String EMAIL_PATTERN = "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}"; + private static final String URI_PATTERN = "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})"; + private static final String HOSTNAME_PATTERN = "(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])"; + private static final String IPV4_PATTERN = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"; + private static final String IPV6_PATTERN = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"; + + private final List randomGenerators; + + public static final RandomConfiguration RANDOM_CONFIGURATION = new RandomConfiguration(); + + private RandomConfiguration() { + List generators = new ArrayList<>(); + + // Note that the order of generators in the list is relevant, as the list is traversed from start to end, to find the first matching generator for a schema, and some generators match for less significant schemas. + generators.add(new RandomEnumGenerator()); + generators.add(builder(TYPE_STRING, FORMAT_DATE).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd')"))); + generators.add(builder(TYPE_STRING, FORMAT_DATE_TIME).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')"))); + generators.add(builder(TYPE_STRING, FORMAT_UUID).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomUUID()"))); + generators.add(builder(TYPE_STRING, "email").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+EMAIL_PATTERN+"')"))); + generators.add(builder(TYPE_STRING, "uri").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+URI_PATTERN+"')"))); + generators.add(builder(TYPE_STRING, "hostname").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+HOSTNAME_PATTERN+"')"))); + generators.add(builder(TYPE_STRING, "ipv4").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+IPV4_PATTERN+"')"))); + generators.add(builder(TYPE_STRING,"ipv6").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+IPV6_PATTERN+"')"))); + generators.add(builder().withType(TYPE_STRING).withPattern(ANY).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+schema.pattern+"')"))); + generators.add(builder().withType(TYPE_BOOLEAN).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimple("citrus:randomEnumValue('true', 'false')"))); + generators.add(new RandomStringGenerator()); + generators.add(new RandomCompositeGenerator()); + generators.add(new RandomNumberGenerator()); + generators.add(new RandomObjectGenerator()); + generators.add(new RandomArrayGenerator()); + + randomGenerators = Collections.unmodifiableList(generators); + } + + public RandomGenerator getGenerator(OasSchema oasSchema) { + return randomGenerators.stream().filter(generator -> generator.handles(oasSchema)) + .findFirst() + .orElse(NULL_GENERATOR); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java new file mode 100644 index 0000000000..978d3b666b --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java @@ -0,0 +1,120 @@ +package org.citrusframework.openapi.random; + +import static org.citrusframework.openapi.random.RandomConfiguration.RANDOM_CONFIGURATION; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OasModelHelper; + +/** + * Context class for generating random values based on an OpenAPI specification. + * This class manages the state and configuration needed to generate random values + * for various schemas defined in the OpenAPI specification. + */ +public class RandomContext { + + private final OpenApiSpecification specification; + + private Map schemaDefinitions; + + private final RandomModelBuilder randomModelBuilder; + + /** + * Cache for storing variable during random value generation. + */ + private final Map contextVariables = new HashMap<>(); + + /** + * Constructs a default RandomContext backed by no specification. Note, that this context can not + * resolve referenced schemas, as no specification is available. + * + */ + public RandomContext() { + this.randomModelBuilder = new RandomModelBuilder(false); + this.specification = null; + } + + /** + * Constructs a new RandomContext with the specified OpenAPI specification and quote option. + * + * @param specification the OpenAPI specification + * @param quote whether to quote the generated random values + */ + public RandomContext(OpenApiSpecification specification, boolean quote) { + this.specification = specification; + this.randomModelBuilder = new RandomModelBuilder(quote); + } + + /** + * Generates random values based on the specified schema. + * + * @param schema the schema to generate random values for + */ + public void generate(OasSchema schema) { + doGenerate(resolveSchema(schema)); + } + + void doGenerate(OasSchema resolvedSchema) { + RANDOM_CONFIGURATION.getGenerator(resolvedSchema).generate(this, resolvedSchema); + } + + /** + * Resolves a schema, handling reference schemas by fetching the referenced schema definition. + * + * @param schema the schema to resolve + * @return the resolved schema + */ + OasSchema resolveSchema(OasSchema schema) { + if (OasModelHelper.isReferenceType(schema)) { + if (schemaDefinitions == null) { + schemaDefinitions = getSchemaDefinitions(); + } + schema = schemaDefinitions.get(OasModelHelper.getReferenceName(schema.$ref)); + } + return schema; + } + + /** + * Returns the RandomModelBuilder associated with this context. + * + * @return the RandomModelBuilder + */ + public RandomModelBuilder getRandomModelBuilder() { + return randomModelBuilder; + } + + /** + * Returns the OpenAPI specification associated with this context. + * + * @return the OpenAPI specification + */ + public OpenApiSpecification getSpecification() { + return specification; + } + + /** + * Returns the schema definitions from the specified OpenAPI document. + * + * @return a map of schema definitions + */ + Map getSchemaDefinitions() { + return specification != null ?OasModelHelper.getSchemaDefinitions(specification.getOpenApiDoc(null)) : Collections.emptyMap(); + } + + /** + * Retrieves a context variable by key, computing its value if necessary using the provided mapping function. + * + * @param the type of the context variable + * @param key the key of the context variable + * @param mappingFunction the function to compute the value if it is not present + * @return the context variable value + */ + public T get(String key, Function mappingFunction) { + //noinspection unchecked + return (T) contextVariables.computeIfAbsent(key, mappingFunction); + } +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomElement.java similarity index 98% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomElement.java index 4a31733459..4c515a4256 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomElement.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomElement.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.citrusframework.openapi.util; +package org.citrusframework.openapi.random; import java.util.ArrayList; import java.util.LinkedHashMap; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java new file mode 100644 index 0000000000..67b46e8be7 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java @@ -0,0 +1,25 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import java.util.stream.Collectors; + +public class RandomEnumGenerator extends RandomGenerator { + + + @Override + public boolean handles(OasSchema other) { + return other.enum_ != null; + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + List anEnum = schema.enum_; + if (anEnum != null) { + String enumValues = schema.enum_.stream().map(value -> "'" + value + "'") + .collect(Collectors.joining(",")); + randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomEnumValue(%s)".formatted(enumValues)); + } + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java new file mode 100644 index 0000000000..9f74422e48 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java @@ -0,0 +1,61 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.Objects; + +/** + * Abstract base class for generators that produce random data based on an OpenAPI schema. + * Subclasses must implement the {@link #generate} method to provide specific random data generation logic. + * + *

The class provides methods for determining if a generator can handle a given schema, + * based on the schema type, format, pattern, and enum constraints. + */ +public abstract class RandomGenerator { + + public static final String ANY = "$ANY$"; + + private final OasSchema schema; + + protected RandomGenerator() { + this.schema = null; + } + + protected RandomGenerator(OasSchema schema) { + this.schema = schema; + } + + public boolean handles(OasSchema other) { + if (other == null || schema == null) { + return false; + } + + if (ANY.equals(schema.type) || Objects.equals(schema.type, other.type)) { + if (schema.format != null) { + return (ANY.equals(schema.format) && other.format != null)|| Objects.equals(schema.format, other.format); + } + + if (schema.pattern != null) { + return (ANY.equals(schema.pattern) && other.pattern != null) || Objects.equals(schema.pattern, other.pattern); + } + + if (schema.enum_ != null && other.enum_ != null) { + return true; + } + + return true; + } + + return false; + } + + abstract void generate(RandomContext randomContext, OasSchema schema); + + public static final RandomGenerator NULL_GENERATOR = new RandomGenerator() { + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + // Do nothing + } + }; + +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java new file mode 100644 index 0000000000..8fbeac3ef4 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java @@ -0,0 +1,62 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.Collections; +import java.util.function.BiConsumer; + +/** + * A simple builder for building {@link java.util.random.RandomGenerator}s. + */ +public class RandomGeneratorBuilder { + + private final OasSchema schema = new Oas30Schema(); + + private RandomGeneratorBuilder() { + } + + static RandomGeneratorBuilder builder() { + return new RandomGeneratorBuilder(); + } + + static RandomGeneratorBuilder builder(String type, String format) { + return new RandomGeneratorBuilder().with(type, format); + } + + RandomGeneratorBuilder with(String type, String format) { + schema.type = type; + schema.format = format; + return this; + } + + + RandomGeneratorBuilder withType(String type) { + schema.type = type; + return this; + } + + RandomGeneratorBuilder withFormat(String format) { + schema.format = format; + return this; + } + + RandomGeneratorBuilder withPattern(String pattern) { + schema.pattern = pattern; + return this; + } + + RandomGeneratorBuilder withEnum() { + schema.enum_ = Collections.emptyList(); + return this; + } + + RandomGenerator build(BiConsumer consumer) { + return new RandomGenerator(schema) { + @Override + void generate(RandomContext randomContext, OasSchema schema) { + consumer.accept(randomContext, schema); + } + }; + } + +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java similarity index 62% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java index 43346b388a..c2ff6bbfea 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java @@ -14,22 +14,21 @@ * limitations under the License. */ -package org.citrusframework.openapi.util; +package org.citrusframework.openapi.random; import java.util.ArrayDeque; import java.util.Deque; -import org.citrusframework.openapi.util.RandomElement.RandomList; -import org.citrusframework.openapi.util.RandomElement.RandomObject; -import org.citrusframework.openapi.util.RandomElement.RandomValue; +import org.citrusframework.openapi.random.RandomElement.RandomList; +import org.citrusframework.openapi.random.RandomElement.RandomObject; +import org.citrusframework.openapi.random.RandomElement.RandomValue; /** - * RandomModelBuilder is a class for building random JSON models. It supports adding - * simple values, objects, properties, and arrays to the JSON structure. The final - * model can be converted to a JSON string using the `writeToJson` method. I + * RandomModelBuilder is a class for building random JSON models. It supports adding simple values, + * objects, properties, and arrays to the JSON structure. The final model can be converted to a JSON + * string using the `writeToJson` method. I *

- * The builder is able to build nested structures and can also handle native string, - * number, and boolean elements, represented as functions for later dynamic string - * conversion by Citrus. + * The builder is able to build nested structures and can also handle native string, number, and + * boolean elements, represented as functions for later dynamic string conversion by Citrus. *

* Example usage: *

@@ -48,22 +47,45 @@ public class RandomModelBuilder {
 
     final Deque deque = new ArrayDeque<>();
 
-    public RandomModelBuilder() {
+    private final boolean quote;
+
+    /**
+     * Creates a {@link RandomModelBuilder} in respective quoting mode.
+     * Quoting should be activated in case an object is created by the builder. In this case,
+     * all properties added by respective "quoted" methods, will be quoted.
+     *
+     * @param quote whether to run the builder in quoting mode or not.
+     */
+    public RandomModelBuilder(boolean quote) {
         deque.push(new RandomValue());
+        this.quote = quote;
     }
 
-    public String toString() {
+    public String write() {
         return RandomModelWriter.toString(this);
     }
 
-    public void appendSimple(String nativeValue) {
+    /**
+     * Append the simpleValue as is, no quoting
+     */
+    public void appendSimple(String simpleValue) {
         if (deque.isEmpty()) {
-            deque.push(new RandomValue(nativeValue));
+            deque.push(new RandomValue(simpleValue));
         } else {
-            deque.peek().push(nativeValue);
+            deque.peek().push(simpleValue);
         }
     }
 
+    /**
+     * If the builder is in quoting mode, the native value will be quoted, otherwise it will be
+     * added as ist.
+     *s
+     * @param simpleValue
+     */
+    public void appendSimpleQuoted(String simpleValue) {
+        appendSimple(quote(simpleValue));
+    }
+
     public void object(Runnable objectBuilder) {
         if (deque.isEmpty()) {
             throwIllegalState();
@@ -106,4 +128,8 @@ public void array(Runnable arrayBuilder) {
         deque.pop();
     }
 
+    public String quote(String text) {
+        return quote ? String.format("\"%s\"", text) : text;
+    }
+
 }
diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java
similarity index 97%
rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java
rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java
index 11960d0973..2c37e621e5 100644
--- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/RandomModelWriter.java
+++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package org.citrusframework.openapi.util;
+package org.citrusframework.openapi.random;
 
 import static org.citrusframework.util.StringUtils.trimTrailingComma;
 
@@ -22,7 +22,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import org.citrusframework.openapi.util.RandomElement.RandomValue;
+import org.citrusframework.openapi.random.RandomElement.RandomValue;
 
 /**
  * Utility class for converting a {@link RandomModelBuilder} to its string representation.
diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java
new file mode 100644
index 0000000000..a9c0742259
--- /dev/null
+++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java
@@ -0,0 +1,155 @@
+package org.citrusframework.openapi.random;
+
+import static java.lang.Boolean.TRUE;
+import static java.lang.String.format;
+import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER;
+
+import io.apicurio.datamodels.openapi.models.OasSchema;
+import java.math.BigDecimal;
+import org.citrusframework.openapi.util.OpenApiUtils;
+
+/**
+ * A generator for producing random numbers based on an OpenAPI schema. This class extends the
+ * {@link RandomGenerator} and provides a specific implementation for generating random numbers with
+ * constraints defined in the schema.
+ *
+ * 

Supported constraints: + *

    + *
  • minimum: The minimum value for the generated number.
  • + *
  • maximum: The maximum value for the generated number.
  • + *
  • exclusiveMinimum: If true, the generated number will be strictly greater than the minimum.
  • + *
  • exclusiveMaximum: If true, the generated number will be strictly less than the maximum.
  • + *
  • multipleOf: The generated number will be a multiple of this value.
  • + *
+ * + *

The generator supports generating numbers for both integer and floating-point types, including + * int32, int64, double, and float. This support + * extends to the multipleOf constraint, ensuring that the generated numbers can be precise + * multiples of the specified value. + * + *

The generator determines the appropriate bounds and constraints based on the provided schema + * and generates a random number accordingly. + */ +public class RandomNumberGenerator extends RandomGenerator { + + public static final BigDecimal THOUSAND = new BigDecimal(1000); + public static final BigDecimal HUNDRED = java.math.BigDecimal.valueOf(100); + public static final BigDecimal MINUS_THOUSAND = new BigDecimal(-1000); + + @Override + public boolean handles(OasSchema other) { + return OpenApiUtils.isAnyNumberScheme(other); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + + boolean exclusiveMaximum = TRUE.equals(schema.exclusiveMaximum); + boolean exclusiveMinimum = TRUE.equals(schema.exclusiveMinimum); + + BigDecimal[] bounds = determineBounds(schema); + + BigDecimal minimum = bounds[0]; + BigDecimal maximum = bounds[1]; + + if (schema.multipleOf != null) { + randomContext.getRandomModelBuilder().appendSimple(format( + "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s', '%s')", + determineDecimalPlaces(schema, minimum, maximum), + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum, + schema.multipleOf + )); + } else { + randomContext.getRandomModelBuilder().appendSimple(format( + "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s')", + determineDecimalPlaces(schema, minimum, maximum), + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum + )); + } + } + + /** + * Determines the number of decimal places to use based on the given schema and + * minimum/maximum/multipleOf values. For integer types, it returns 0. For other types, it + * returns the maximum number of decimal places found between the minimum and maximum values, + * with a minimum of 2 decimal places. + */ + private int determineDecimalPlaces(OasSchema schema, BigDecimal minimum, + BigDecimal maximum) { + if (TYPE_INTEGER.equals(schema.type)) { + return 0; + } else { + Number multipleOf = schema.multipleOf; + if (multipleOf != null) { + return findLeastSignificantDecimalPlace(new BigDecimal(multipleOf.toString())); + } + + return Math.max(2, Math.max(findLeastSignificantDecimalPlace(minimum), + findLeastSignificantDecimalPlace(maximum))); + + } + } + + /** + * Determine some reasonable bounds for a random number + */ + private static BigDecimal[] determineBounds(OasSchema schema) { + Number maximum = schema.maximum; + Number minimum = schema.minimum; + Number multipleOf = schema.multipleOf; + + BigDecimal bdMinimum; + BigDecimal bdMaximum; + + if (minimum == null && maximum == null) { + bdMinimum = MINUS_THOUSAND; + bdMaximum = THOUSAND; + } else if (minimum == null) { + bdMaximum = new BigDecimal(maximum.toString()); + bdMinimum = calculateMinRelativeToMax(bdMaximum, multipleOf); + } else if (maximum == null) { + bdMinimum = new BigDecimal(minimum.toString()); + bdMaximum = calculateMaxRelativeToMin(bdMinimum, multipleOf); + } else { + bdMinimum = new BigDecimal(minimum.toString()); + bdMaximum = new BigDecimal(maximum.toString()); + } + + return new BigDecimal[]{bdMinimum, bdMaximum}; + } + + static BigDecimal calculateMinRelativeToMax(BigDecimal max, Number multipleOf) { + if (multipleOf != null) { + return max.subtract(new BigDecimal(multipleOf.toString()).abs().multiply(HUNDRED)); + } else { + return max.subtract(max.multiply(BigDecimal.valueOf(2)).max(THOUSAND)); + } + } + + static BigDecimal calculateMaxRelativeToMin(BigDecimal min, Number multipleOf) { + if (multipleOf != null) { + return min.add(new BigDecimal(multipleOf.toString()).abs().multiply(HUNDRED)); + } else { + return min.add(min.multiply(BigDecimal.valueOf(2)).max(THOUSAND)); + } + } + + int findLeastSignificantDecimalPlace(BigDecimal number) { + number = number.stripTrailingZeros(); + + String[] parts = number.toPlainString().split("\\."); + + if (parts.length == 1) { + return 0; + } + + return parts[1].length(); + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java new file mode 100644 index 0000000000..8b7ef2b9d4 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java @@ -0,0 +1,58 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Map; +import org.citrusframework.openapi.OpenApiConstants; +import org.citrusframework.openapi.util.OpenApiUtils; + +/** + * A generator for producing random objects based on an OpenAPI schema. This class extends + * the {@link RandomGenerator} and provides a specific implementation for generating objects + * with properties defined in the schema. + * + *

The generator supports object schemas and prevents recursion by keeping track of the + * schemas being processed.

+ */ +public class RandomObjectGenerator extends RandomGenerator { + + private static final String OBJECT_STACK = "OBJECT_STACK"; + + private static final OasSchema OBJECT_SCHEMA = new Oas30Schema(); + + static { + OBJECT_SCHEMA.type = OpenApiConstants.TYPE_OBJECT; + } + + public RandomObjectGenerator() { + super(OBJECT_SCHEMA); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + + Deque objectStack = randomContext.get(OBJECT_STACK, k -> new ArrayDeque<>()); + + if (objectStack.contains(schema)) { + // If we have already created this schema, we are very likely in a recursion and need to stop. + return; + } + + objectStack.push(schema); + randomContext.getRandomModelBuilder().object(() -> { + if (schema.properties != null) { + for (Map.Entry entry : schema.properties.entrySet()) { + if (randomContext.getSpecification().isGenerateOptionalFields() || OpenApiUtils.isRequired(schema, + entry.getKey())) { + randomContext.getRandomModelBuilder().property(entry.getKey(), () -> + randomContext.generate(entry.getValue())); + } + } + } + }); + objectStack.pop(); + } + +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java new file mode 100644 index 0000000000..cc30c220eb --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java @@ -0,0 +1,39 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.OpenApiConstants; + +/** + * A generator for producing random strings based on an OpenAPI schema. + * This class extends the {@link RandomGenerator} and provides a specific implementation + * for generating random strings with constraints defined in the schema. + */ +public class RandomStringGenerator extends RandomGenerator { + + private static final OasSchema STRING_SCHEMA = new Oas30Schema(); + + static { + STRING_SCHEMA.type = OpenApiConstants.TYPE_STRING; + } + + public RandomStringGenerator() { + super(STRING_SCHEMA); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + int min = 1; + int max = 10; + + if (schema.minLength != null && schema.minLength.intValue() > 0) { + min = schema.minLength.intValue(); + } + + if (schema.maxLength != null && schema.maxLength.intValue() > 0) { + max = schema.maxLength.intValue(); + } + + randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomString(%s,MIXED,true,%s)".formatted(max, min)); + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java index dd6e48deb7..ae4008111a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java @@ -62,4 +62,15 @@ public static boolean isAnyNumberScheme(OasSchema schema) { ); } + /** + * Checks if given field name is in list of required fields for this schema. + */ + public static boolean isRequired(OasSchema schema, String field) { + if (schema.required == null) { + return true; + } + + return schema.required.contains(field); + } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index 59227c5cd7..6ac0dd9d60 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -72,64 +72,13 @@ public static void beforeClass() { .getSchemaValidator(); } - @DataProvider(name = "findLeastSignificantDecimalPlace") - public static Object[][] findLeastSignificantDecimalPlace() { - return new Object[][]{ - {new BigDecimal("1234.5678"), 4}, - {new BigDecimal("123.567"), 3}, - {new BigDecimal("123.56"), 2}, - {new BigDecimal("123.5"), 1}, - {new BigDecimal("123.0"), 0}, - {new BigDecimal("123"), 0} - }; - } - - @Test(dataProvider = "findLeastSignificantDecimalPlace") - void findLeastSignificantDecimalPlace(BigDecimal number, int expectedSignificance) { - assertEquals(OpenApiTestDataGenerator.findLeastSignificantDecimalPlace(number), - expectedSignificance); - } - - @DataProvider(name = "incrementToExclude") - public static Object[][] incrementToExclude() { - return new Object[][]{ - {new BigDecimal("1234.678"), new BigDecimal("1234.679")}, - {new BigDecimal("1234.78"), new BigDecimal("1234.79")}, - {new BigDecimal("1234.8"), new BigDecimal("1234.9")}, - {new BigDecimal("1234.0"), new BigDecimal("1235")}, - {new BigDecimal("1234"), new BigDecimal("1235")}, - }; - } - - @Test(dataProvider = "incrementToExclude") - void incrementToExclude(BigDecimal value, BigDecimal expectedValue) { - assertEquals(OpenApiTestDataGenerator.incrementToExclude(value), expectedValue); - } - - @DataProvider(name = "decrementToExclude") - public static Object[][] decrementToExclude() { - return new Object[][]{ - {new BigDecimal("1234.678"), new BigDecimal("1234.677")}, - {new BigDecimal("1234.78"), new BigDecimal("1234.77")}, - {new BigDecimal("1234.8"), new BigDecimal("1234.7")}, - {new BigDecimal("1234.0"), new BigDecimal("1233")}, - {new BigDecimal("1234"), new BigDecimal("1233")}, - }; - } - - @Test(dataProvider = "decrementToExclude") - void decrementToExclude(BigDecimal value, BigDecimal expectedValue) { - assertEquals(OpenApiTestDataGenerator.decrementToExclude(value), expectedValue); - } - @Test void testUuidFormat() { Oas30Schema stringSchema = new Oas30Schema(); stringSchema.type = TYPE_STRING; stringSchema.format = FORMAT_UUID; - String uuidRandomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema, - false); + String uuidRandomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema); String finalUuidRandomValue = testContext.replaceDynamicContentInString(uuidRandomValue); Pattern uuidPattern = Pattern.compile( "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); @@ -300,8 +249,7 @@ void testPattern() { String exp = "[0-3]([a-c]|[e-g]{1,2})"; stringSchema.pattern = exp; - String randomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema, - false); + String randomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema); String finalRandomValue = testContext.replaceDynamicContentInString(randomValue); assertTrue(finalRandomValue.matches(exp), "Value '%s' does not match expression '%s'".formatted(finalRandomValue, exp)); @@ -315,18 +263,17 @@ public static Object[][] testPingApiSchemas() { //{"AnyOfType"}, //{"AllOfType"}, //{"PingRespType"}, - {"OneOfType"}, {"StringsType"}, {"DatesType"}, {"NumbersType"}, - {"MultipleOfType"}, {"PingReqType"}, {"Detail1"}, {"Detail2"}, {"BooleanType"}, {"EnumType"}, {"NestedType"}, + {"MultipleOfType"}, {"SimpleArrayType"}, {"ComplexArrayType"}, {"ArrayOfArraysType"}, @@ -354,13 +301,11 @@ void testPingApiSchemas(String schemaType) throws IOException { assertNotNull(randomValue); String finalJsonAsText = testContext.replaceDynamicContentInString(randomValue); - try { JsonNode valueNode = new ObjectMapper().readTree( testContext.replaceDynamicContentInString(finalJsonAsText)); ValidationReport validationReport = schemaValidator.validate(() -> valueNode, - swaggerValidationSchema, - "response.body"); + swaggerValidationSchema, null); String message = """ Json is invalid according to schema. @@ -430,7 +375,7 @@ void testArrayMaxItems() { arraySchema.items = stringSchema; - Pattern pattern = Pattern.compile("citrus:randomString\\(1[0-5]\\)"); + Pattern pattern = Pattern.compile("citrus:randomString\\(1[0-5],MIXED,true,10\\)"); for (int i = 0; i < 100; i++) { String randomArrayValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification); @@ -447,61 +392,4 @@ void testArrayMaxItems() { } } - @Test - public void testLowestMultipleOf() { - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(10)), BigDecimal.valueOf(-1000)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-10)), BigDecimal.valueOf(-1000)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(11)), BigDecimal.valueOf(-990)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-11)), BigDecimal.valueOf(-990)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(11.1234)), BigDecimal.valueOf(-989.9826)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-11.1234)), BigDecimal.valueOf(-989.9826)); - - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(10)), BigDecimal.valueOf(1000)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-10)), BigDecimal.valueOf(1000)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(11)), BigDecimal.valueOf(1001)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-11)), BigDecimal.valueOf(1001)); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(11.1234)), new BigDecimal("1001.1060")); - assertEquals(OpenApiTestDataGenerator.lowestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-11.1234)), new BigDecimal("1001.1060")); - } - - @Test - public void testLargestMultipleOf() { - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(10)), BigDecimal.valueOf(-1000)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-10)), BigDecimal.valueOf(-1000)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(11)), BigDecimal.valueOf(-1001)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-11)), BigDecimal.valueOf(-1001)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(11.1234)), new BigDecimal("-1001.1060")); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(-1000), - BigDecimal.valueOf(-11.1234)), new BigDecimal("-1001.1060")); - - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(10)), BigDecimal.valueOf(1000)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-10)), BigDecimal.valueOf(1000)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(11)), BigDecimal.valueOf(990)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-11)), BigDecimal.valueOf(990)); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(11.1234)), new BigDecimal("989.9826")); - assertEquals(OpenApiTestDataGenerator.largestMultipleOf(BigDecimal.valueOf(1000), - BigDecimal.valueOf(-11.1234)), new BigDecimal("989.9826")); - } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java new file mode 100644 index 0000000000..43fd6d628b --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java @@ -0,0 +1,179 @@ +package org.citrusframework.openapi.random; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.citrusframework.openapi.OpenApiConstants.*; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; +import static org.testng.Assert.assertTrue; + +public class OasRandomConfigurationTest { + + private RandomConfiguration randomConfiguration; + + @BeforeClass + public void setUp() { + randomConfiguration = RandomConfiguration.RANDOM_CONFIGURATION; + } + + @Test + public void testGetGeneratorForDateFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = FORMAT_DATE; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForDateTimeFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = FORMAT_DATE_TIME; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForUUIDFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = FORMAT_UUID; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForEmailFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = "email"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForURIFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = "uri"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForHostnameFormat() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = "hostname"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForIPv4Format() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = "ipv4"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForIPv6Format() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + schema.format = "ipv6"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForBooleanType() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_BOOLEAN; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForStringType() { + OasSchema schema = new Oas30Schema(); + schema.type = TYPE_STRING; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForNumberType() { + OasSchema schema = new Oas30Schema(); + schema.type = "number"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForObjectType() { + OasSchema schema = new Oas30Schema(); + schema.type = "object"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForArrayType() { + OasSchema schema = new Oas30Schema(); + schema.type = "array"; + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForEnum() { + OasSchema schema = new Oas30Schema(); + schema.enum_ = List.of("value1", "value2"); + + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertTrue(generator.handles(schema)); + } + + @Test + public void testGetGeneratorForNullSchema() { + OasSchema schema = new Oas30Schema(); + RandomGenerator generator = randomConfiguration.getGenerator(schema); + assertNotNull(generator); + assertSame(generator, RandomGenerator.NULL_GENERATOR); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java new file mode 100644 index 0000000000..c361e0f1f6 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java @@ -0,0 +1,106 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.OpenApiConstants; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomArrayGeneratorTest { + + private RandomArrayGenerator generator; + private RandomContext mockContext; + private RandomModelBuilder builderSpy; + + @BeforeMethod + public void setUp() { + generator = new RandomArrayGenerator(); + mockContext = mock(); + + builderSpy = spy(new RandomModelBuilder(true)); + + when(mockContext.getRandomModelBuilder()).thenReturn(builderSpy); + } + + @Test + public void testGenerateArrayWithDefaultItems() { + Oas30Schema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_ARRAY; + + Oas30Schema itemsSchema = new Oas30Schema(); + itemsSchema.type = OpenApiConstants.TYPE_STRING; + schema.items = itemsSchema; + + generator.generate(mockContext, schema); + + verify(builderSpy, atLeastOnce()).array(any()); + verify(mockContext, atLeastOnce()).generate(any(OasSchema.class)); + } + + @Test + public void testGenerateArrayWithMinItems() { + Oas30Schema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_ARRAY; + schema.minItems = 5; + + Oas30Schema itemsSchema = new Oas30Schema(); + itemsSchema.type = OpenApiConstants.TYPE_STRING; + schema.items = itemsSchema; + + generator.generate(mockContext, schema); + + verify(builderSpy, atLeastOnce()).array(any()); + verify(mockContext, atLeast(5)).generate(any(OasSchema.class)); + } + + @Test + public void testGenerateArrayWithMaxItems() { + Oas30Schema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_ARRAY; + schema.maxItems = 3; + + Oas30Schema itemsSchema = new Oas30Schema(); + itemsSchema.type = OpenApiConstants.TYPE_STRING; + schema.items = itemsSchema; + + generator.generate(mockContext, schema); + + verify(builderSpy, atLeastOnce()).array(any()); + verify(mockContext, atMost(3)).generate(any(OasSchema.class)); + } + + @Test + public void testGenerateArrayWithMinMaxItems() { + Oas30Schema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_ARRAY; + schema.minItems = 2; + schema.maxItems = 5; + + Oas30Schema itemsSchema = new Oas30Schema(); + itemsSchema.type = OpenApiConstants.TYPE_STRING; + schema.items = itemsSchema; + + generator.generate(mockContext, schema); + + verify(builderSpy, atLeastOnce()).array(any()); + verify(mockContext, atLeast(2)).generate(any(OasSchema.class)); + verify(mockContext, atMost(5)).generate(any(OasSchema.class)); + } + + @Test(expectedExceptions = UnsupportedOperationException.class) + public void testGenerateArrayWithUnsupportedItems() { + Oas30Schema schema = new Oas30Schema(); + schema.items = new Object(); // Unsupported items type + + generator.generate(mockContext, schema); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java new file mode 100644 index 0000000000..ab2da578e7 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java @@ -0,0 +1,90 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.assertArg; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.Collections; +import java.util.List; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomCompositeGeneratorTest { + + private RandomCompositeGenerator generator; + private RandomContext mockContext; + private RandomModelBuilder builderSpy; + + @BeforeMethod + public void setUp() { + generator = new RandomCompositeGenerator(); + mockContext = mock(RandomContext.class); + builderSpy = spy(new RandomModelBuilder(true)); + + when(mockContext.getRandomModelBuilder()).thenReturn(builderSpy); + } + + @Test + public void testHandlesCompositeSchema() { + Oas30Schema schema = new Oas30Schema(); + schema.allOf = Collections.singletonList(new Oas30Schema()); + + assertTrue(generator.handles(schema)); + } + + @Test + public void testGenerateAllOf() { + Oas30Schema schema = new Oas30Schema(); + schema.allOf = List.of(new Oas30Schema(), new Oas30Schema(), new Oas30Schema()); + + generator.generate(mockContext, schema); + + verify(builderSpy).object(any()); + verify(mockContext).generate(schema.allOf.get(0)); + verify(mockContext).generate(schema.allOf.get(1)); + verify(mockContext).generate(schema.allOf.get(2)); + } + + @Test + public void testGenerateAnyOf() { + Oas30Schema schema = new Oas30Schema(); + schema.anyOf = List.of(new Oas30Schema(), new Oas30Schema(), new Oas30Schema()); + + generator.generate(mockContext, schema); + + verify(builderSpy).object(any()); + verify(mockContext, atLeast(1)).generate(assertArg(arg -> schema.anyOf.contains(arg))); + verify(mockContext, atMost(3)).generate(assertArg(arg -> schema.anyOf.contains(arg))); + } + + @Test + public void testGenerateOneOf() { + Oas30Schema schema = new Oas30Schema(); + schema.oneOf = List.of(new Oas30Schema(), new Oas30Schema(), new Oas30Schema()); + + generator.generate(mockContext, schema); + + verify(builderSpy, atLeastOnce()).object(any()); + verify(mockContext).generate(any(OasSchema.class)); + } + + @Test + public void testGenerateWithNoCompositeSchema() { + Oas30Schema schema = new Oas30Schema(); + + generator.generate(mockContext, schema); + + verify(builderSpy, never()).object(any()); + verify(mockContext, never()).generate(any(OasSchema.class)); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java new file mode 100644 index 0000000000..78d47bb52e --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java @@ -0,0 +1,76 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertSame; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.HashMap; +import java.util.Map; +import org.citrusframework.openapi.OpenApiSpecification; +import org.springframework.test.util.ReflectionTestUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomContextTest { + + private OpenApiSpecification specificationMock; + + private RandomContext randomContext; + + private Map schemaDefinitions; + + @BeforeMethod + public void setUp() { + RandomModelBuilder randomModelBuilderMock = mock(); + specificationMock = mock(); + + schemaDefinitions =new HashMap<>(); + + randomContext = spy(new RandomContext(specificationMock, true)); + ReflectionTestUtils.setField(randomContext, "randomModelBuilder", randomModelBuilderMock); + + doReturn(schemaDefinitions).when(randomContext).getSchemaDefinitions(); + } + + @Test + public void testGenerateWithResolvedSchema() { + OasSchema oasSchema = new Oas30Schema(); + randomContext.generate(oasSchema); + verify(randomContext).doGenerate(oasSchema); + } + + @Test + public void testGenerateWithReferencedSchema() { + OasSchema referencedSchema = new Oas30Schema(); + schemaDefinitions.put("reference", referencedSchema); + OasSchema oasSchema = new Oas30Schema(); + oasSchema.$ref = "reference"; + + randomContext.generate(oasSchema); + verify(randomContext).doGenerate(referencedSchema); + } + + @Test + public void testGetRandomModelBuilder() { + assertNotNull(randomContext.getRandomModelBuilder()); + } + + @Test + public void testGetSpecification() { + assertEquals(randomContext.getSpecification(), specificationMock); + } + + @Test + public void testCacheVariable() { + HashMap cachedValue1 = randomContext.get("testKey", k -> new HashMap<>()); + HashMap cachedValue2 = randomContext.get("testKey", k -> new HashMap<>()); + + assertSame(cachedValue1, cachedValue2); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java similarity index 98% rename from connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java rename to connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java index 2add7086c8..0f17bd143e 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomElementTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.citrusframework.openapi.util; +package org.citrusframework.openapi.random; import static org.testng.Assert.assertEquals; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java new file mode 100644 index 0000000000..8d4d7a14e9 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java @@ -0,0 +1,77 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomEnumGeneratorTest { + + private RandomEnumGenerator generator; + private RandomContext mockContext; + private RandomModelBuilder mockBuilder; + private OasSchema mockSchema; + + @BeforeMethod + public void setUp() { + generator = new RandomEnumGenerator(); + mockContext = mock(RandomContext.class); + mockBuilder = mock(RandomModelBuilder.class); + mockSchema = mock(OasSchema.class); + + when(mockContext.getRandomModelBuilder()).thenReturn(mockBuilder); + } + + @Test + public void testHandlesWithEnum() { + mockSchema.enum_ = List.of("value1", "value2", "value3"); + + boolean result = generator.handles(mockSchema); + + assertTrue(result); + } + + @Test + public void testHandlesWithoutEnum() { + mockSchema.enum_ = null; + + boolean result = generator.handles(mockSchema); + + assertFalse(result); + } + + @Test + public void testGenerateWithEnum() { + mockSchema.enum_ = List.of("value1", "value2", "value3"); + + generator.generate(mockContext, mockSchema); + + verify(mockBuilder).appendSimpleQuoted("citrus:randomEnumValue('value1','value2','value3')"); + } + + @Test + public void testGenerateWithEmptyEnum() { + mockSchema.enum_ = List.of(); + + generator.generate(mockContext, mockSchema); + + verify(mockBuilder).appendSimpleQuoted("citrus:randomEnumValue()"); + } + + @Test + public void testGenerateWithNullEnum() { + mockSchema.enum_ = null; + + generator.generate(mockContext, mockSchema); + + verify(mockBuilder, never()).appendSimpleQuoted(anyString()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java new file mode 100644 index 0000000000..01d1c253e6 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java @@ -0,0 +1,92 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.function.BiConsumer; +import org.springframework.test.util.ReflectionTestUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + + +public class RandomGeneratorBuilderTest { + + private BiConsumer consumerMock; + private RandomContext contextMock; + private OasSchema schemaMock; + + @BeforeMethod + public void setUp() { + consumerMock = mock(); + contextMock = mock(); + schemaMock = mock(); + } + + @Test + public void testBuilderWithTypeAndFormat() { + String type = "type1"; + String format = "format1"; + + RandomGenerator generator = RandomGeneratorBuilder.builder(type, format).build(consumerMock); + OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); + assertNotNull(schema); + assertEquals(schema.type, type); + assertEquals(schema.format, format); + } + + @Test + public void testBuilderWithType() { + String type = "type1"; + + RandomGenerator generator = RandomGeneratorBuilder.builder().withType(type).build( + consumerMock); + OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); + assertNotNull(schema); + assertEquals(schema.type, type); + } + + @Test + public void testBuilderWithFormat() { + String format = "format1"; + + RandomGenerator generator = RandomGeneratorBuilder.builder().withFormat(format).build( + consumerMock); + OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); + assertNotNull(schema); + assertEquals(schema.format, format); + } + + @Test + public void testBuilderWithPattern() { + String pattern = "pattern1"; + + RandomGenerator generator = RandomGeneratorBuilder.builder().withPattern(pattern).build( + consumerMock); + OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); + assertNotNull(schema); + assertEquals(schema.pattern, pattern); + } + + @Test + public void testBuilderWithEnum() { + RandomGenerator generator = RandomGeneratorBuilder.builder().withEnum().build(consumerMock); + OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); + assertNotNull(schema); + assertNotNull(schema.enum_); + assertTrue(schema.enum_.isEmpty()); + } + + @Test + public void testBuildGenerator() { + RandomGenerator generator = RandomGeneratorBuilder.builder().build(consumerMock); + + generator.generate(contextMock, schemaMock); + + verify(consumerMock).accept(contextMock, schemaMock); + } + +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java new file mode 100644 index 0000000000..c788fff730 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java @@ -0,0 +1,152 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.List; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomGeneratorTest { + + private RandomGenerator generator; + private OasSchema mockSchema; + + @BeforeMethod + public void setUp() { + mockSchema = mock(OasSchema.class); + generator = new RandomGenerator(mockSchema) { + @Override + void generate(RandomContext randomContext, OasSchema schema) { + // Implementation not needed for this test + } + }; + } + + @Test + public void testHandlesWithMatchingTypeAndFormat() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.format = "format1"; + + mockSchema.type = "type1"; + mockSchema.format = "format1"; + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithTypeAny() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.format = "format1"; + + mockSchema.type = RandomGenerator.ANY; + mockSchema.format = "format1"; + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithFormatAny() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.format = "format1"; + + mockSchema.type = "type1"; + mockSchema.format = RandomGenerator.ANY; + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithPatternAny() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.pattern = "pattern1"; + + mockSchema.type = "type1"; + mockSchema.pattern = RandomGenerator.ANY; + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithMatchingPattern() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.pattern = "pattern1"; + + mockSchema.type = "type1"; + mockSchema.pattern = "pattern1"; + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithMatchingEnum() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.enum_ = List.of("value1", "value2"); + + mockSchema.type = "type1"; + mockSchema.enum_ = List.of("value1", "value2"); + + assertTrue(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithNonMatchingType() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type2"; + otherSchema.format = "format1"; + + mockSchema.type = "type1"; + mockSchema.format = "format1"; + + assertFalse(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithNonMatchingFormat() { + OasSchema otherSchema = new Oas30Schema(); + otherSchema.type = "type1"; + otherSchema.format = "format2"; + + mockSchema.type = "type1"; + mockSchema.format = "format1"; + + assertFalse(generator.handles(otherSchema)); + } + + @Test + public void testHandlesWithNullSchema() { + assertFalse(generator.handles(null)); + } + + @Test + public void testHandlesWithNullGeneratorSchema() { + RandomGenerator generatorWithNullSchema = new RandomGenerator() { + @Override + void generate(RandomContext randomContext, OasSchema schema) { + // Do nothing + } + }; + + assertFalse(generatorWithNullSchema.handles(mockSchema)); + } + + @Test + public void testNullGenerator() { + RandomContext mockContext = mock(RandomContext.class); + + RandomGenerator.NULL_GENERATOR.generate(mockContext, mockSchema); + + verify(mockContext, never()).getRandomModelBuilder(); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java similarity index 74% rename from connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java rename to connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java index f7570c2083..ef4deb3abc 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/util/RandomModelBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java @@ -14,32 +14,58 @@ * limitations under the License. */ -package org.citrusframework.openapi.util; +package org.citrusframework.openapi.random; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.expectThrows; + +import java.util.ArrayDeque; +import org.springframework.test.util.ReflectionTestUtils; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.testng.Assert.*; - public class RandomModelBuilderTest { private RandomModelBuilder builder; @BeforeMethod public void setUp() { - builder = new RandomModelBuilder(); + builder = new RandomModelBuilder(true); } @Test public void testInitialState() { - String text = builder.toString(); + String text = builder.write(); assertEquals(text, ""); } @Test public void testAppendSimple() { builder.appendSimple("testValue"); - String json = builder.toString(); + String json = builder.write(); + assertEquals(json, "testValue"); + } + + @Test + public void testAppendSimpleToEmptyQueue() { + ReflectionTestUtils.setField(builder, "deque", new ArrayDeque<>()); + builder.appendSimple("testValue"); + String json = builder.write(); + assertEquals(json, "testValue"); + } + + @Test + public void testAppendSimpleQuoted() { + builder.appendSimpleQuoted("testValue"); + String json = builder.write(); + assertEquals(json, "\"testValue\""); + } + + @Test + public void testAppendSimpleQuotedIfNotQuoting() { + ReflectionTestUtils.setField(builder,"quote", false); + builder.appendSimpleQuoted("testValue"); + String json = builder.write(); assertEquals(json, "testValue"); } @@ -49,7 +75,7 @@ public void testObjectWithProperties() { builder.property("key1", () -> builder.appendSimple("\"value1\"")); builder.property("key2", () -> builder.appendSimple("\"value2\"")); }); - String json = builder.toString(); + String json = builder.write(); assertEquals(json, "{\"key1\": \"value1\",\"key2\": \"value2\"}"); } @@ -60,7 +86,7 @@ public void testNestedObject() { builder.property("innerKey", () -> builder.appendSimple("\"innerValue\"")) )) ); - String json = builder.toString(); + String json = builder.write(); assertEquals(json, "{\"outerKey\": {\"innerKey\": \"innerValue\"}}"); } @@ -71,7 +97,7 @@ public void testArray() { builder.appendSimple("\"value2\""); builder.appendSimple("\"value3\""); }); - String json = builder.toString(); + String json = builder.write(); assertEquals(json, "[\"value1\",\"value2\",\"value3\"]"); } @@ -85,7 +111,7 @@ public void testNestedArray() { }); builder.appendSimple("\"value2\""); }); - String json = builder.toString(); + String json = builder.write(); assertEquals(json, "[\"value1\",[\"nestedValue1\",\"nestedValue2\"],\"value2\"]"); } @@ -100,7 +126,7 @@ public void testMixedStructure() { })); builder.property("key2", () -> builder.appendSimple("\"value2\"")); }); - String json = builder.toString(); + String json = builder.write(); assertEquals(json, "{\"key1\": [\"value1\",{\"nestedKey\": \"nestedValue\"}],\"key2\": \"value2\"}"); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java new file mode 100644 index 0000000000..fbcb4f0479 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java @@ -0,0 +1,217 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.math.BigDecimal; +import org.citrusframework.openapi.OpenApiConstants; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class RandomNumberGeneratorTest { + + private RandomNumberGenerator generator; + private RandomContext mockContext; + private RandomModelBuilder mockBuilder; + private OasSchema schema; + + @BeforeMethod + public void setUp() { + generator = new RandomNumberGenerator(); + mockContext = mock(RandomContext.class); + mockBuilder = mock(RandomModelBuilder.class); + schema = new Oas30Schema(); + + when(mockContext.getRandomModelBuilder()).thenReturn(mockBuilder); + } + + @Test + public void testGenerateDefaultBounds() { + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '-1000', '1000', 'false', 'false')"); + } + + @Test + public void testGenerateWithMinimum() { + schema.minimum = BigDecimal.valueOf(5); + generator.generate(mockContext, schema); + // Max is because of guessing a reasonable range + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '5', '1005', 'false', 'false')"); + } + + @Test + public void testGenerateWithMaximum() { + schema.maximum = BigDecimal.valueOf(15); + generator.generate(mockContext, schema); + // Min is because of guessing a reasonable range + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '-985', '15', 'false', 'false')"); + } + + @Test + public void testGenerateWithMinimumAndMaximum() { + schema.minimum = BigDecimal.valueOf(5); + schema.maximum = BigDecimal.valueOf(15); + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '5', '15', 'false', 'false')"); + } + + @Test + public void testGenerateWithExclusiveMinimum() { + schema.minimum = BigDecimal.valueOf(5); + schema.exclusiveMinimum = true; + generator.generate(mockContext, schema); + // Max is because of guessing a reasonable range + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '5', '1005', 'true', 'false')"); + } + + @Test + public void testGenerateWithExclusiveMaximum() { + schema.maximum = BigDecimal.valueOf(15); + schema.exclusiveMaximum = true; + generator.generate(mockContext, schema); + // Min is because of guessing a reasonable range + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '-985', '15', 'false', 'true')"); + } + + @Test + public void testGenerateWithMultipleOf() { + schema.multipleOf = BigDecimal.valueOf(5); + schema.minimum = BigDecimal.valueOf(10); + schema.maximum = BigDecimal.valueOf(50); + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('0', '10', '50', 'false', 'false', '5')"); + } + + @Test + public void testGenerateWithIntegerType() { + schema.type = "integer"; + schema.minimum = BigDecimal.valueOf(1); + schema.maximum = BigDecimal.valueOf(10); + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('0', '1', '10', 'false', 'false')"); + } + + @Test + public void testGenerateWithFloatType() { + schema.type = "number"; + schema.minimum = BigDecimal.valueOf(1.5); + schema.maximum = BigDecimal.valueOf(10.5); + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('2', '1.5', '10.5', 'false', 'false')"); + } + + @Test + public void testGenerateWithMultipleOfFloat() { + schema.type = "number"; + schema.multipleOf = BigDecimal.valueOf(0.5); + schema.minimum = BigDecimal.valueOf(1.0); + schema.maximum = BigDecimal.valueOf(5.0); + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimple("citrus:randomNumberGenerator('1', '1.0', '5.0', 'false', 'false', '0.5')"); + } + + @Test + public void testCalculateMinRelativeToMaxWithMultipleOf() { + BigDecimal max = new BigDecimal("1000"); + Number multipleOf = new BigDecimal("10"); + + BigDecimal result = RandomNumberGenerator.calculateMinRelativeToMax(max, multipleOf); + + BigDecimal expected = max.subtract(new BigDecimal(multipleOf.toString()).abs().multiply(RandomNumberGenerator.HUNDRED)); + assertEquals(result, expected); + } + + @Test + public void testCalculateMinRelativeToMaxWithoutMultipleOf() { + BigDecimal max = new BigDecimal("1000"); + + BigDecimal result = RandomNumberGenerator.calculateMinRelativeToMax(max, null); + + BigDecimal expected = max.subtract(max.multiply(BigDecimal.valueOf(2)).max(RandomNumberGenerator.THOUSAND)); + assertEquals(result, expected); + } + + @Test + public void testCalculateMaxRelativeToMinWithMultipleOf() { + BigDecimal min = new BigDecimal("1000"); + Number multipleOf = new BigDecimal("10"); + + BigDecimal result = RandomNumberGenerator.calculateMaxRelativeToMin(min, multipleOf); + + BigDecimal expected = min.add(new BigDecimal(multipleOf.toString()).abs().multiply(RandomNumberGenerator.HUNDRED)); + assertEquals(result, expected); + } + + @Test + public void testCalculateMaxRelativeToMinWithoutMultipleOf() { + BigDecimal min = new BigDecimal("1000"); + + BigDecimal result = RandomNumberGenerator.calculateMaxRelativeToMin(min, null); + + BigDecimal expected = min.add(min.multiply(BigDecimal.valueOf(2)).max(RandomNumberGenerator.THOUSAND)); + assertEquals(result, expected); + } + + @Test + public void testHandlesWithIntegerType() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_INTEGER; + + assertTrue(generator.handles(schema)); + } + + @Test + public void testHandlesWithNumberType() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_NUMBER; + + assertTrue(generator.handles(schema)); + } + + @Test + public void testHandlesWithOtherType() { + OasSchema schema = new Oas30Schema(); + schema.type = "string"; + + assertFalse(generator.handles(schema)); + } + + @Test + public void testHandlesWithNullType() { + OasSchema schema = new Oas30Schema(); + schema.type = null; + + assertFalse(generator.handles(schema)); + } + + @Test + public void testHandlesWithNullSchema() { + assertFalse(generator.handles(null)); + } + + @DataProvider(name = "findLeastSignificantDecimalPlace") + public static Object[][] findLeastSignificantDecimalPlace() { + return new Object[][]{ + {new BigDecimal("1234.5678"), 4}, + {new BigDecimal("123.567"), 3}, + {new BigDecimal("123.56"), 2}, + {new BigDecimal("123.5"), 1}, + {new BigDecimal("123.0"), 0}, + {new BigDecimal("123"), 0} + }; + } + + @Test(dataProvider = "findLeastSignificantDecimalPlace") + void findLeastSignificantDecimalPlace(BigDecimal number, int expectedSignificance) { + assertEquals(generator.findLeastSignificantDecimalPlace(number), + expectedSignificance); + } + +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java new file mode 100644 index 0000000000..a32809f2f9 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java @@ -0,0 +1,134 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import org.citrusframework.openapi.OpenApiConstants; +import org.citrusframework.openapi.OpenApiSpecification; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomObjectGeneratorTest { + + private RandomObjectGenerator generator; + private RandomContext contextMock; + private RandomModelBuilder randomModelBuilderSpy; + private OpenApiSpecification specificationMock; + + @BeforeMethod + public void setUp() { + generator = new RandomObjectGenerator(); + contextMock = mock(); + specificationMock = mock(); + + randomModelBuilderSpy = spy(new RandomModelBuilder(true)); + when(contextMock.getRandomModelBuilder()).thenReturn(randomModelBuilderSpy); + when(contextMock.getSpecification()).thenReturn(specificationMock); + when(contextMock.get(eq("OBJECT_STACK"), any())).thenReturn(new ArrayDeque<>()); + + } + + @Test + public void testHandlesObjectType() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + + assertTrue(generator.handles(schema)); + } + + @Test + public void testDoesNotHandleNonObjectType() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_STRING; + + assertFalse(generator.handles(schema)); + } + + @Test + public void testGenerateObjectWithoutProperties() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + + generator.generate(contextMock, schema); + + verify(randomModelBuilderSpy).object(any()); + } + + @Test + public void testGenerateObjectWithProperties() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + schema.properties = new HashMap<>(); + OasSchema propertySchema = new Oas30Schema(); + schema.properties.put("property1", propertySchema); + + when(specificationMock.isGenerateOptionalFields()).thenReturn(true); + + generator.generate(contextMock, schema); + + verify(randomModelBuilderSpy).object(any()); + verify(randomModelBuilderSpy).property(eq("property1"), any()); + verify(contextMock).generate(propertySchema); + } + + @Test + public void testGenerateObjectWithRequiredProperties() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + schema.properties = new HashMap<>(); + OasSchema propertySchema = new Oas30Schema(); + schema.properties.put("property1", propertySchema); + schema.required = List.of("property1"); + + when(specificationMock.isGenerateOptionalFields()).thenReturn(false); + + generator.generate(contextMock, schema); + + verify(randomModelBuilderSpy).object(any()); + verify(randomModelBuilderSpy).property(eq("property1"), any()); + verify(contextMock).generate(propertySchema); + } + + @Test + public void testGenerateObjectWithOptionalProperties() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + schema.properties = new HashMap<>(); + OasSchema propertySchema = new Oas30Schema(); + schema.properties.put("property1", propertySchema); + schema.required = List.of(); + when(specificationMock.isGenerateOptionalFields()).thenReturn(false); + generator.generate(contextMock, schema); + + verify(randomModelBuilderSpy).object(any()); + verify(randomModelBuilderSpy, never()).property(eq("property1"), any()); + verify(contextMock, never()).generate(propertySchema); + } + + @Test + public void testGenerateObjectWithRecursion() { + OasSchema schema = new Oas30Schema(); + schema.type = OpenApiConstants.TYPE_OBJECT; + Deque objectStack = new ArrayDeque<>(); + objectStack.push(schema); + + when(contextMock.get(eq("OBJECT_STACK"), any())).thenReturn(objectStack); + + generator.generate(contextMock, schema); + + verify(randomModelBuilderSpy, never()).object(any()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java new file mode 100644 index 0000000000..445a318bd9 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java @@ -0,0 +1,70 @@ +package org.citrusframework.openapi.random; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class RandomStringGeneratorTest { + + private RandomStringGenerator generator; + private RandomContext mockContext; + private RandomModelBuilder mockBuilder; + private OasSchema schema; + + @BeforeMethod + public void setUp() { + generator = new RandomStringGenerator(); + mockContext = mock(RandomContext.class); + mockBuilder = mock(RandomModelBuilder.class); + schema = new Oas30Schema(); + + when(mockContext.getRandomModelBuilder()).thenReturn(mockBuilder); + } + + @Test + public void testGenerateDefaultLength() { + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(10,MIXED,true,1)"); + } + + @Test + public void testGenerateWithMinLength() { + schema.minLength = 5; + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(10,MIXED,true,5)"); + } + + @Test + public void testGenerateWithMaxLength() { + schema.maxLength = 15; + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(15,MIXED,true,1)"); + } + + @Test + public void testGenerateWithMinAndMaxLength() { + schema.minLength = 3; + schema.maxLength = 8; + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(8,MIXED,true,3)"); + } + + @Test + public void testGenerateWithZeroMinLength() { + schema.minLength = 0; + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(10,MIXED,true,1)"); + } + + @Test + public void testGenerateWithZeroMaxLength() { + schema.maxLength = 0; + generator.generate(mockContext, schema); + verify(mockBuilder).appendSimpleQuoted("citrus:randomString(10,MIXED,true,1)"); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java index 80d901395d..04a0d47086 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java @@ -85,7 +85,7 @@ public void shouldValidateHttpMessage() { processor.validate(httpMessageMock, contextMock); - verify(openApiRequestValidatorSpy, times(1)).validateRequest(operationPathAdapterMock, httpMessageMock); + verify(openApiRequestValidatorSpy).validateRequest(operationPathAdapterMock, httpMessageMock); } @Test @@ -100,7 +100,7 @@ public void shouldCallValidateRequest() { processor.validate(httpMessageMock, contextMock); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), + verify(openApiSpecificationMock).getOperation(anyString(), any(TestContext.class)); verify(openApiRequestValidatorSpy, times(0)).validateRequest(operationPathAdapterMock, httpMessageMock); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java index f79a8a9887..3716b503c7 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -19,7 +19,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -113,8 +112,8 @@ public void shouldValidateRequestWithNoErrors() { openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); // Then - verify(openApiInteractionValidatorMock, times(1)).validateRequest(any(Request.class)); - verify(validationReportMock, times(1)).hasErrors(); + verify(openApiInteractionValidatorMock).validateRequest(any(Request.class)); + verify(validationReportMock).hasErrors(); } @Test(expectedExceptions = ValidationException.class) @@ -131,8 +130,8 @@ public void shouldValidateRequestWithErrors() { openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); // Then - verify(openApiInteractionValidatorMock, times(1)).validateRequest(any(Request.class)); - verify(validationReportMock, times(1)).hasErrors(); + verify(openApiInteractionValidatorMock).validateRequest(any(Request.class)); + verify(validationReportMock).hasErrors(); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java index 671560ba9f..2058af2558 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java @@ -85,7 +85,7 @@ public void shouldCallValidateResponse() { processor.validate(httpMessageMock, contextMock); - verify(openApiResponseValidatorSpy, times(1)).validateResponse(operationPathAdapterMock, httpMessageMock); + verify(openApiResponseValidatorSpy).validateResponse(operationPathAdapterMock, httpMessageMock); } @Test @@ -100,7 +100,7 @@ public void shouldNotValidateWhenNoOperation() { processor.validate(httpMessageMock, contextMock); - verify(openApiSpecificationMock, times(1)).getOperation(anyString(), + verify(openApiSpecificationMock).getOperation(anyString(), any(TestContext.class)); verify(openApiResponseValidatorSpy, times(0)).validateResponse(operationPathAdapterMock, httpMessageMock); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java index e59f1f2821..cfccf76d92 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -16,11 +16,24 @@ package org.citrusframework.openapi.validation; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.model.Response; import com.atlassian.oai.validator.report.ValidationReport; import io.apicurio.datamodels.openapi.models.OasOperation; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.OpenApiSpecification; @@ -34,21 +47,6 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Map; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - public class OpenApiResponseValidatorTest { @Mock @@ -120,8 +118,8 @@ public void shouldValidateWithNoErrors() { openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); // Then - verify(openApiInteractionValidatorMock, times(1)).validateResponse(anyString(), any(Method.class), any(Response.class)); - verify(validationReportMock, times(1)).hasErrors(); + verify(openApiInteractionValidatorMock).validateResponse(anyString(), any(Method.class), any(Response.class)); + verify(validationReportMock).hasErrors(); } @Test(expectedExceptions = ValidationException.class) @@ -141,8 +139,8 @@ public void shouldValidateWithErrors() { openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); // Then - verify(openApiInteractionValidatorMock, times(1)).validateResponse(anyString(), any(Method.class), any(Response.class)); - verify(validationReportMock, times(1)).hasErrors(); + verify(openApiInteractionValidatorMock).validateResponse(anyString(), any(Method.class), any(Response.class)); + verify(validationReportMock).hasErrors(); } @Test diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java index f3542428bd..8b30bfd3b9 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java @@ -68,7 +68,7 @@ public DefaultFunctionLibrary() { getMembers().put("randomNumber", new RandomNumberFunction()); getMembers().put("randomNumberGenerator", new AdvancedRandomNumberFunction()); getMembers().put("randomString", new RandomStringFunction()); - getMembers().put("randomValue", new RandomPatternFunction()); + getMembers().put("randomPattern", new RandomPatternFunction()); getMembers().put("concat", new ConcatFunction()); getMembers().put("currentDate", new CurrentDateFunction()); getMembers().put("substring", new SubstringFunction()); diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java index bc7252e057..6cde8506c4 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java @@ -21,8 +21,9 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; -import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; @@ -37,71 +38,72 @@ *
  • Min value: The minimum value for the generated random number (optional, default: Double.MIN_VALUE).
  • *
  • Max value: The maximum value for the generated random number (optional, default: Double.MAX_VALUE).
  • *
  • Exclude min: Whether to exclude the minimum value (optional, default: false).
  • - *
  • Exclude man: Whether to exclude the maximum value (optional, default: false).
  • + *
  • Exclude max: Whether to exclude the maximum value (optional, default: false).
  • + *
  • Multiple of: The generated number will be a multiple of this value (optional).
  • * *

    - * This function differs from the {@link RandomNumberFunction} in several key ways: - *

      + * This function differs from the {@link RandomNumberFunction} in several key ways: + *
        *
      • It allows to specify several aspects of a number (see above).
      • *
      • The length of the number is restricted to the range and precision of a double, whereas RandomNumberFunction can create arbitrarily long integer values.
      • - *
      + *
    */ public class AdvancedRandomNumberFunction implements Function { - /** - * Basic seed generating random number - */ - private static final Random generator = new Random(System.currentTimeMillis()); + public static final BigDecimal DEFAULT_MAX_VALUE = new BigDecimal(1000000); + public static final BigDecimal DEFAULT_MIN_VALUE = DEFAULT_MAX_VALUE.negate(); public String execute(List parameterList, TestContext context) { - int decimalPlaces = 0; - double minValue = -1000000; - double maxValue = 1000000; - boolean excludeMin = false; - boolean excludeMax = false; - if (parameterList == null) { throw new InvalidFunctionUsageException("Function parameters must not be null."); } - if (!parameterList.isEmpty()) { - decimalPlaces = parseParameter(1, parameterList.get(0), Integer.class, - Integer::parseInt); - if (decimalPlaces < 0) { - throw new InvalidFunctionUsageException( - "Invalid parameter definition. Decimal places must be a non-negative integer value."); - } + int decimalPlaces = getParameter(parameterList, 0, Integer.class, Integer::parseInt, 2); + if (decimalPlaces < 0) { + throw new InvalidFunctionUsageException( + "Decimal places must be a non-negative integer value."); } - if (parameterList.size() > 1) { - minValue = parseParameter(2, parameterList.get(1), Double.class, Double::parseDouble); + BigDecimal minValue = getParameter(parameterList, 1, BigDecimal.class, BigDecimal::new, + DEFAULT_MIN_VALUE); + BigDecimal maxValue = getParameter(parameterList, 2, BigDecimal.class, BigDecimal::new, + DEFAULT_MAX_VALUE); + if (minValue.compareTo(maxValue) > 0) { + throw new InvalidFunctionUsageException("Min value must be less than max value."); } - if (parameterList.size() > 2) { - maxValue = parseParameter(3, parameterList.get(2), Double.class, Double::parseDouble); - if (minValue > maxValue) { - throw new InvalidFunctionUsageException( - "Invalid parameter definition. Min value must be less than max value."); - } - } + boolean excludeMin = getParameter(parameterList, 3, Boolean.class, Boolean::parseBoolean, + false); + boolean excludeMax = getParameter(parameterList, 4, Boolean.class, Boolean::parseBoolean, + false); + BigDecimal multiple = getParameter(parameterList, 5, BigDecimal.class, BigDecimal::new, + null); - if (parameterList.size() > 3) { - excludeMin = parseParameter(4, parameterList.get(3), Boolean.class, - Boolean::parseBoolean); - } + return getRandomNumber(decimalPlaces, minValue, maxValue, excludeMin, excludeMax, multiple); + } - if (parameterList.size() > 4) { - excludeMax = parseParameter(5, parameterList.get(4), Boolean.class, - Boolean::parseBoolean); + private T getParameter(List params, int index, Class type, + java.util.function.Function parser, T defaultValue) { + if (index < params.size()) { + String param = params.get(index); + return "null".equals(param) ? defaultValue + : parseParameter(index + 1, param, type, parser); } - - return getRandomNumber(decimalPlaces, minValue, maxValue, excludeMin, excludeMax); + return defaultValue; } private T parseParameter(int index, String text, Class type, java.util.function.Function parseFunction) { + T value; try { - return parseFunction.apply(text); + + value = parseFunction.apply(text); + if (value == null) { + throw new CitrusRuntimeException( + "Text '%s' could not be parsed to '%s'. Resulting value is null".formatted(text, + type.getSimpleName())); + } + return value; } catch (Exception e) { throw new InvalidFunctionUsageException( format("Invalid parameter at index %d. %s must be parsable to %s.", index, text, @@ -112,33 +114,114 @@ private T parseParameter(int index, String text, Class type, /** * Static number generator method. */ - private String getRandomNumber(int decimalPlaces, double minValue, double maxValue, - boolean excludeMin, boolean excludeMax) { - double adjustment = Math.pow(10, -decimalPlaces); + private String getRandomNumber(int decimalPlaces, BigDecimal minValue, BigDecimal maxValue, + boolean excludeMin, boolean excludeMax, BigDecimal multiple) { - if (excludeMin) { - minValue += adjustment; - } + minValue = excludeMin ? incrementToExclude(minValue) : minValue; + maxValue = excludeMax ? decrementToExclude(maxValue) : maxValue; - if (excludeMax) { - maxValue -= adjustment; - } + BigDecimal range = maxValue.subtract(minValue); - BigDecimal range = BigDecimal.valueOf(maxValue).subtract(BigDecimal.valueOf(minValue)); + BigDecimal randomValue; + if (multiple != null) { + randomValue = createMultipleOf(minValue, maxValue, multiple); + } else { + randomValue = createRandomValue(minValue, range, + ThreadLocalRandom.current().nextDouble()); + randomValue = randomValue.setScale(decimalPlaces, RoundingMode.HALF_UP); + } - double randomValue = getRandomValue(minValue, range, generator.nextDouble()); - BigDecimal bd = new BigDecimal(Double.toString(randomValue)); - bd = bd.setScale(2, RoundingMode.HALF_UP); + if (randomValue == null) { + // May only happen if multiple is out of range of min/max + return format("%s", Double.POSITIVE_INFINITY); + } return decimalPlaces == 0 ? - format("%s", bd.longValue()) : - format(format("%%.%sf", decimalPlaces), bd.doubleValue()); + format("%s", randomValue.longValue()) : + format(format("%%.%sf", decimalPlaces), randomValue.doubleValue()); } - double getRandomValue(double minValue, BigDecimal range, double random) { + // Pass in random for testing + BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { BigDecimal offset = range.multiply(BigDecimal.valueOf(random)); - BigDecimal value = BigDecimal.valueOf(minValue).add(offset); - return value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ? Double.MAX_VALUE : value.doubleValue(); + BigDecimal value = minValue.add(offset); + return value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ? BigDecimal.valueOf( + Double.MAX_VALUE) : value; + } + + private BigDecimal largestMultipleOf(BigDecimal highest, BigDecimal multipleOf) { + RoundingMode roundingMode = + highest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.UP : RoundingMode.DOWN; + BigDecimal factor = highest.divide(multipleOf, 0, roundingMode); + return multipleOf.multiply(factor); + } + + private BigDecimal lowestMultipleOf(BigDecimal lowest, BigDecimal multipleOf) { + RoundingMode roundingMode = + lowest.compareTo(java.math.BigDecimal.ZERO) < 0 ? RoundingMode.DOWN : RoundingMode.UP; + BigDecimal factor = lowest.divide(multipleOf, 0, roundingMode); + return multipleOf.multiply(factor); + } + + private BigDecimal incrementToExclude(BigDecimal val) { + return val.add(determineIncrement(val)) + .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); + } + + private BigDecimal decrementToExclude(BigDecimal val) { + return val.subtract(determineIncrement(val)) + .setScale(findLeastSignificantDecimalPlace(val), RoundingMode.HALF_DOWN); + } + + private BigDecimal determineIncrement(BigDecimal number) { + return java.math.BigDecimal.valueOf( + 1.0d / (Math.pow(10d, findLeastSignificantDecimalPlace(number)))); + } + + private int findLeastSignificantDecimalPlace(BigDecimal number) { + number = number.stripTrailingZeros(); + + String[] parts = number.toPlainString().split("\\."); + + if (parts.length == 1) { + return 0; + } + + return parts[1].length(); + } + + private BigDecimal createMultipleOf( + BigDecimal minimum, + BigDecimal maximum, + BigDecimal multipleOf + ) { + + BigDecimal lowestMultiple = lowestMultipleOf(minimum, multipleOf); + BigDecimal largestMultiple = largestMultipleOf(maximum, multipleOf); + + // Check if there are no valid multiples in the range + if (lowestMultiple.compareTo(largestMultiple) > 0) { + return null; + } + + BigDecimal range = largestMultiple.subtract(lowestMultiple) + .divide(multipleOf, RoundingMode.DOWN); + + // Don't go for incredible large numbers + if (range.compareTo(BigDecimal.valueOf(11)) > 0) { + range = BigDecimal.valueOf(10); + } + + long factor = 0; + if (range.compareTo(BigDecimal.ZERO) != 0) { + factor = ThreadLocalRandom.current().nextLong(1, range.longValue() + 1); + } + BigDecimal randomMultiple = lowestMultiple.add( + multipleOf.multiply(BigDecimal.valueOf(factor))); + randomMultiple = randomMultiple.setScale(findLeastSignificantDecimalPlace(multipleOf), + RoundingMode.HALF_UP); + + return randomMultiple; } } \ No newline at end of file diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java index 4720921c7e..377b2d5fe7 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java @@ -25,9 +25,8 @@ import org.citrusframework.functions.Function; /** - * The RandomPatternFunction class implements the Function interface. This function generates a - * random string based on a provided regular expression pattern. It uses the Generex library to - * generate the random string. + * The RandomPatternFunction generates a random string based on a provided regular expression pattern. + * It uses the Generex library to generate the random string. *

    * Note: The Generex library has limitations in its ability to generate all possible expressions * from a given regular expression. It may not support certain complex regex features or produce all diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java index 099c13df55..326471a2b5 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; @@ -32,7 +33,7 @@ * */ public class RandomStringFunction implements Function { - private static Random generator = new Random(System.currentTimeMillis()); + private static final Random generator = new Random(System.currentTimeMillis()); private static final char[] ALPHABET_UPPER = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', @@ -67,12 +68,13 @@ public String execute(List parameterList, TestContext context) { int numberOfLetters; String notationMethod = MIXED; boolean includeNumbers = false; + int minNumberOfLetters = -1; if (parameterList == null || parameterList.isEmpty()) { throw new InvalidFunctionUsageException("Function parameters must not be empty"); } - if (parameterList.size() > 3) { + if (parameterList.size() > 4) { throw new InvalidFunctionUsageException("Too many parameters for function"); } @@ -89,12 +91,16 @@ public String execute(List parameterList, TestContext context) { includeNumbers = parseBoolean(parameterList.get(2)); } + if (parameterList.size() > 3) { + minNumberOfLetters = parseInt(parameterList.get(3)); + } + if (notationMethod.equals(UPPERCASE)) { - return getRandomString(numberOfLetters, ALPHABET_UPPER, includeNumbers); + return getRandomString(numberOfLetters, ALPHABET_UPPER, includeNumbers, minNumberOfLetters); } else if (notationMethod.equals(LOWERCASE)) { - return getRandomString(numberOfLetters, ALPHABET_LOWER, includeNumbers); + return getRandomString(numberOfLetters, ALPHABET_LOWER, includeNumbers, minNumberOfLetters); } else { - return getRandomString(numberOfLetters, ALPHABET_MIXED, includeNumbers); + return getRandomString(numberOfLetters, ALPHABET_MIXED, includeNumbers, minNumberOfLetters); } } @@ -105,7 +111,7 @@ public String execute(List parameterList, TestContext context) { * @param includeNumbers * @return */ - public static String getRandomString(int numberOfLetters, char[] alphabet, boolean includeNumbers) { + public static String getRandomString(int numberOfLetters, char[] alphabet, boolean includeNumbers, int minNumberOfLetters) { StringBuilder builder = new StringBuilder(); int upperRange = alphabet.length - 1; @@ -117,6 +123,11 @@ public static String getRandomString(int numberOfLetters, char[] alphabet, boole upperRange += NUMBERS.length; } + if (minNumberOfLetters > -1) { + numberOfLetters = ThreadLocalRandom.current() + .nextInt(minNumberOfLetters, numberOfLetters + 1); + } + for (int i = 1; i < numberOfLetters; i++) { int letterIndex = generator.nextInt(upperRange); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 3d6be1f9b3..21cf207378 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -63,7 +63,7 @@ public static String appendSegmentToUrlPath(String path, String segment) { } public static String quote(String text, boolean quote) { - return quote ? String.format("\"%s\"", text) : text; + return quote ? "\"" + text + "\"" : text; } /** diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java new file mode 100644 index 0000000000..82cf51cfa7 --- /dev/null +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java @@ -0,0 +1,416 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.functions.core; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +import java.math.BigDecimal; +import java.util.List; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +public class AdvancedRandomNumberFunctionTest { + + private AdvancedRandomNumberFunction function; + private TestContext context; + + @BeforeMethod + public void setUp() { + function = new AdvancedRandomNumberFunction(); + context = new TestContext(); + } + + @Test + public void testRandomNumberWithNullParameter() { + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(null, context)); + assertEquals(exception.getMessage(), + "Function parameters must not be null."); + } + + @Test + public void testRandomNumberWithDefaultValues() { + List params = List.of(); + String result = function.execute(params, context); + assertNotNull(result); + assertTrue(result.matches("-?\\d*\\.\\d{2}")); + } + + @Test + public void testRandomNumberWithDecimalPlaces() { + List params = List.of("2"); + String result = function.execute(params, context); + assertNotNull(result); + assertTrue(result.matches("-?\\d*\\.\\d{2}"), "result does not match pattern: " + result); + } + + @Test + public void testRandomNumberWithinRange() { + List params = List.of("2", "10.5", "20.5"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= 10.5 && randomValue <= 20.5); + } + + @Test + public void testRandomNumberIncludesMin() { + List params = List.of("1", "10.5", "20.5"); + function = new AdvancedRandomNumberFunction() { + @Override + BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { + random = 0.0; + return super.createRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertEquals(result, "10.5"); + } + + @Test + public void testRandomNumberIncludesMax() { + List params = List.of("1", "10.5", "20.5"); + function = new AdvancedRandomNumberFunction() { + @Override + BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { + random = 1.0; + return super.createRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertEquals(result, "20.5"); + } + + @Test + public void testRandomNumberExcludeMin() { + List params = List.of("1", "10.5", "20.5", "true", "false"); + function = new AdvancedRandomNumberFunction() { + @Override + BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { + random = 0.0; + return super.createRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue > 10.5 && randomValue <= 20.5); + } + + @Test + public void testRandomNumberExcludeMax() { + List params = List.of("2", "10.5", "20.5", "false", "true"); + function = new AdvancedRandomNumberFunction() { + @Override + BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { + random = 1.0; + return super.createRandomValue(minValue, range, random); + } + }; + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= 10.5 && randomValue < 20.5); + } + + @Test + public void testRandomInteger32EdgeCase() { + List params = List.of("0", "-2147483648", "2147483647", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Integer.MAX_VALUE && randomValue < Integer.MAX_VALUE); + } + + @Test + public void testRandomInteger32MinEqualsMaxEdgeCase() { + List params = List.of("0", "3", "3", "false", "false"); + for (int i = 0; i < 100; i++) { + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertEquals(randomValue, 3); + } + } + + // randomDouble('0','3','3','true','true') + // randomDouble('0','3','3','true','true') + + @Test + public void testRandomDouble32MinEqualsMaxEdgeCase() { + List params = List.of("2", "3.0", "3.0", "false", "false"); + for (int i = 0; i < 100; i++) { + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertEquals(randomValue, 3); + } + } + + @Test + public void testRandomInteger64EdgeCase() { + List params = List.of("0", "-9223372036854775808", "9223372036854775807", "false", + "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Long.MAX_VALUE && randomValue < Long.MAX_VALUE); + } + + @Test + public void testRandomNumberFloatEdgeCase() { + List params = List.of("0", "-3.4028235E38", "3.4028235E38", "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Float.MAX_VALUE && randomValue < Float.MAX_VALUE); + } + + @Test + public void testRandomNumberDoubleEdgeCase() { + List params = List.of("0", "-1.7976931348623157E308", "1.7976931348623157E308", + "false", "false"); + String result = function.execute(params, context); + assertNotNull(result); + double randomValue = Double.parseDouble(result); + assertTrue(randomValue >= -Double.MAX_VALUE && randomValue < Double.MAX_VALUE); + } + + @Test + public void testInvalidDecimalPlaces() { + List params = List.of("-1"); // invalid decimalPlaces + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Decimal places must be a non-negative integer value."); + } + + @Test + public void testInvalidRange() { + List params = List.of("2", "20.5", "10.5"); // invalid range + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Min value must be less than max value."); + } + + @Test + public void testInvalidDecimalPlacesFormat() { + List params = List.of("xxx"); // invalid decimalPlaces + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Invalid parameter at index 1. xxx must be parsable to Integer."); + } + + @Test + public void testInvalidMinValueFormat() { + List params = List.of("1", "xxx"); // invalid min value + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Invalid parameter at index 2. xxx must be parsable to BigDecimal."); + } + + @Test + public void testInvalidMaxValueFormat() { + List params = List.of("1", "1.1", "xxx"); // invalid max value + InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, + () -> function.execute(params, context)); + assertEquals(exception.getMessage(), + "Invalid parameter at index 3. xxx must be parsable to BigDecimal."); + } + + @DataProvider(name = "testRandomNumber") + public static Object[][] testRandomNumber() { + return new Object[][]{ + + {0, 12, null, null, false, false}, + {0, null, 0, 2, true, true}, + {0, null, null, null, false, false}, + {0, null, 0, 100, false, false}, + {0, null, 0, 2, false, false}, + {0, null, -100, 0, false, false}, + {0, null, -2, 0, false, false}, + {0, null, 0, 100, true, true}, + {0, null, -100, 0, true, true}, + {0, null, -2, 0, true, true}, + {0, null, 0, null, false, false}, + {0, null, 0, 0, false, false}, + {0, 11, 0, 12, true, true}, + + {0, 13, 0, 100, false, false}, + {0, 14, 0, 14, false, false}, + {0, 15, -100, 0, false, false}, + {0, 16, -16, 0, false, false}, + {0, 17, 0, 100, true, true}, + {0, 18, -100, 0, true, true}, + {0, 19, -20, 0, true, true}, + {0, 20, 0, null, false, false}, + {0, 21, 21, 21, false, false}, + + {0, null, 0, 2, true, true}, + {0, null, null, null, false, false}, + {0, null, 0, 100, false, false}, + {0, null, 0, 2, false, false}, + {0, null, -100, 0, false, false}, + {0, null, -2, 0, false, false}, + {0, null, 0, 100, true, true}, + {0, null, -100, 0, true, true}, + {0, null, -2, 0, true, true}, + {0, null, 0, null, false, false}, + {0, null, 0, 0, false, false}, + {0, 11, 0, 12, true, true}, + {0, 12, null, null, false, false}, + {0, 13, 0, 100, false, false}, + {0, 14, 0, 14, false, false}, + {0, 15, -100, 0, false, false}, + {0, 16, -16, 0, false, false}, + {0, 17, 0, 100, true, true}, + {0, 18, -100, 0, true, true}, + {0, 19, -20, 0, true, true}, + {0, 20, 0, null, false, false}, + {0, 21, 21, 21, false, false}, + + {3, null, 0, 2, true, true}, + {3, null, null, null, false, false}, + {3, null, 0, 100, false, false}, + {3, null, 0, 2, false, false}, + {3, null, -100, 0, false, false}, + {3, null, -2, 0, false, false}, + {3, null, 0, 100, true, true}, + {3, null, -100, 0, true, true}, + {3, null, -2, 0, true, true}, + {3, null, 0, null, false, false}, + {3, null, 0, 0, false, false}, + {3, 11.123f, 0, 13, true, true}, + {3, 12.123f, null, null, false, false}, + {3, 13.123f, 0, 100, false, false}, + {3, 14.123f, 0, 14, false, false}, + {3, 15.123f, -100, 0, false, false}, + {3, 16.123f, -16, 0, false, false}, + {3, 17.123f, 0, 100, true, true}, + {3, 18.123f, -100, 0, true, true}, + {3, 19.123f, -21, 0, true, true}, + {3, 20.123f, 0, null, false, false}, + {3, 21.123f, 21.122f, 21.124f, false, false}, + + {5, null, 0, 2, true, true}, + {5, null, null, null, false, false}, + {5, null, 0, 100, false, false}, + {5, null, 0, 2, false, false}, + {5, null, -100, 0, false, false}, + {5, null, -2, 0, false, false}, + {5, null, 0, 100, true, true}, + {5, null, -100, 0, true, true}, + {5, null, -2, 0, true, true}, + {5, null, 0, null, false, false}, + {5, null, 0, 0, false, false}, + {5, 11.123d, 0, 13, true, true}, + {5, 12.123d, null, null, false, false}, + {5, 13.123d, 0, 100, false, false}, + {5, 14.123d, 0, 14, false, false}, + {5, 15.123d, -100, 0, false, false}, + {5, 16.123d, -16, 0, false, false}, + {5, 17.123d, 0, 100, true, true}, + {5, 18.123d, -100, 0, true, true}, + {5, 19.123d, -21, 0, true, true}, + {5, 20.123d, 0, null, false, false}, + {5, 21.123d, 21.122d, 21.124d, false, false}, + + }; + } + + @Test(dataProvider = "testRandomNumber") + void testRandomNumber(Number decimalPlaces, Number multipleOf, Number minimum, Number maximum, + boolean exclusiveMinimum, boolean exclusiveMaximum) { + + TestContext testContext = new TestContext(); + AdvancedRandomNumberFunction advancedRandomNumberFunction = new AdvancedRandomNumberFunction(); + try { + for (int i = 0; i < 1000; i++) { + + BigDecimal value = new BigDecimal(advancedRandomNumberFunction.execute( + List.of(toString(decimalPlaces), toString(minimum), toString(maximum), + toString(exclusiveMinimum), toString(exclusiveMaximum), toString(multipleOf)), testContext)); + + if (multipleOf != null) { + BigDecimal remainder = value.remainder(new BigDecimal(multipleOf.toString())); + + assertEquals( + remainder.compareTo(BigDecimal.ZERO), 0, + "Expected %s to be a multiple of %s! Remainder is %s".formatted( + value, multipleOf, + remainder)); + } + + if (maximum != null) { + if (exclusiveMaximum) { + assertTrue(value.doubleValue() < maximum.doubleValue(), + "Expected %s to be lower than %s!".formatted( + value, maximum)); + } else { + assertTrue(value.doubleValue() <= maximum.doubleValue(), + "Expected %s to be lower or equal than %s!".formatted( + value, maximum)); + } + } + + if (minimum != null) { + if (exclusiveMinimum) { + assertTrue(value.doubleValue() > minimum.doubleValue(), + "Expected %s to be larger than %s!".formatted( + value, minimum)); + } else { + assertTrue(value.doubleValue() >= minimum.doubleValue(), + "Expected %s to be larger or equal than %s!".formatted( + value, minimum)); + } + } + } + } catch (Exception e) { + Assert.fail("Creation of multiple float threw an exception: " + e.getMessage(), e); + } + } + + private String toString(Object obj) { + if (obj == null) { + return "null"; + } + return obj.toString(); + + } + + private T expectThrows(Class exceptionClass, Runnable runnable) { + try { + runnable.run(); + } catch (Throwable throwable) { + if (exceptionClass.isInstance(throwable)) { + return exceptionClass.cast(throwable); + } else { + throw new AssertionError("Unexpected exception type", throwable); + } + } + throw new AssertionError("Expected exception not thrown"); + } +} \ No newline at end of file diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java deleted file mode 100644 index 1452fb881b..0000000000 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomDoubleFunctionTest.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.functions.core; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - -import java.math.BigDecimal; -import java.util.List; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.InvalidFunctionUsageException; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -public class RandomDoubleFunctionTest { - - private AdvancedRandomNumberFunction function; - private TestContext context; - - @BeforeMethod - public void setUp() { - function = new AdvancedRandomNumberFunction(); - context = new TestContext(); - } - - @Test - public void testRandomNumberWithNullParameter() { - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, - () -> function.execute(null, context)); - assertEquals(exception.getMessage(), - "Function parameters must not be null."); - } - - @Test - public void testRandomNumberWithDefaultValues() { - List params = List.of(); - String result = function.execute(params, context); - assertNotNull(result); - assertTrue(result.matches("-?\\d*")); - } - - @Test - public void testRandomNumberWithDecimalPlaces() { - List params = List.of("2"); - String result = function.execute(params, context); - assertNotNull(result); - assertTrue(result.matches("-?\\d*\\.\\d{2}"), "result does not match pattern: "+result); - } - - @Test - public void testRandomNumberWithinRange() { - List params = List.of("2", "10.5", "20.5"); - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >= 10.5 && randomValue <= 20.5); - } - - @Test - public void testRandomNumberIncludesMin() { - List params = List.of("1", "10.5", "20.5"); - function = new AdvancedRandomNumberFunction() { - @Override - double getRandomValue(double minValue, BigDecimal range, double random) { - random = 0.0; - return super.getRandomValue(minValue, range, random); - } - }; - String result = function.execute(params, context); - assertEquals(result, "10.5"); - } - - @Test - public void testRandomNumberIncludesMax() { - List params = List.of("1", "10.5", "20.5"); - function = new AdvancedRandomNumberFunction() { - @Override - double getRandomValue(double minValue, BigDecimal range, double random) { - random = 1.0; - return super.getRandomValue(minValue, range, random); - } - }; - String result = function.execute(params, context); - assertEquals(result, "20.5"); - } - - @Test - public void testRandomNumberExcludeMin() { - List params = List.of("1", "10.5", "20.5", "true", "false"); - function = new AdvancedRandomNumberFunction() { - @Override - double getRandomValue(double minValue, BigDecimal range, double random) { - random = 0.0; - return super.getRandomValue(minValue, range, random); - } - }; - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue > 10.5 && randomValue <= 20.5); - } - - @Test - public void testRandomNumberExcludeMax() { - List params = List.of("2", "10.5", "20.5", "false", "true"); - function = new AdvancedRandomNumberFunction() { - @Override - double getRandomValue(double minValue, BigDecimal range, double random) { - random = 1.0; - return super.getRandomValue(minValue, range, random); - } - }; - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >= 10.5 && randomValue < 20.5); - } - - @Test - public void testRandomInteger32EdgeCase() { - List params = List.of("0", "-2147483648", "2147483647", "false", "false"); - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >= -Integer.MAX_VALUE && randomValue < Integer.MAX_VALUE); - } - - @Test - public void testRandomInteger32MinEqualsMaxEdgeCase() { - List params = List.of("0", "3", "3", "false", "false"); - for (int i =0;i<100;i++) { - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertEquals(randomValue, 3); - } - } - - - - // randomDouble('0','3','3','true','true') - // randomDouble('0','3','3','true','true') - - @Test - public void testRandomDouble32MinEqualsMaxEdgeCase() { - List params = List.of("2", "3.0", "3.0", "false", "false"); - for (int i =0;i<100;i++) { - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertEquals(randomValue, 3); - } - } - - @Test - public void testRandomInteger64EdgeCase() { - List params = List.of("0", "-9223372036854775808", "9223372036854775807", "false", "false"); - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >=-Long.MAX_VALUE && randomValue < Long.MAX_VALUE); - } - - @Test - public void testRandomNumberFloatEdgeCase() { - List params = List.of("0", "-3.4028235E38", "3.4028235E38", "false", "false"); - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >= -Float.MAX_VALUE && randomValue < Float.MAX_VALUE); - } - - @Test - public void testRandomNumberDoubleEdgeCase() { - List params = List.of("0", "-1.7976931348623157E308", "1.7976931348623157E308", "false", "false"); - String result = function.execute(params, context); - assertNotNull(result); - double randomValue = Double.parseDouble(result); - assertTrue(randomValue >= -Double.MAX_VALUE && randomValue < Double.MAX_VALUE); - } - - @Test - public void testInvalidDecimalPlaces() { - List params = List.of("-1"); // invalid decimalPlaces - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); - assertEquals(exception.getMessage(), "Invalid parameter definition. Decimal places must be a non-negative integer value."); - } - - @Test - public void testInvalidRange() { - List params = List.of("2", "20.5", "10.5"); // invalid range - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); - assertEquals(exception.getMessage(), "Invalid parameter definition. Min value must be less than max value."); - } - - @Test - public void testInvalidDecimalPlacesFormat() { - List params = List.of("xxx"); // invalid decimalPlaces - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); - assertEquals(exception.getMessage(), "Invalid parameter at index 1. xxx must be parsable to Integer."); - } - - @Test - public void testInvalidMinValueFormat() { - List params = List.of("1","xxx"); // invalid min value - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, () -> function.execute(params, context)); - assertEquals(exception.getMessage(), "Invalid parameter at index 2. xxx must be parsable to Double."); - } - - @Test - public void testInvalidMaxValueFormat() { - List params = List.of("1", "1.1", "xxx"); // invalid max value - InvalidFunctionUsageException exception = expectThrows(InvalidFunctionUsageException.class, - () -> function.execute(params, context)); - assertEquals(exception.getMessage(), - "Invalid parameter at index 3. xxx must be parsable to Double."); - } - - private T expectThrows(Class exceptionClass, Runnable runnable) { - try { - runnable.run(); - } catch (Throwable throwable) { - if (exceptionClass.isInstance(throwable)) { - return exceptionClass.cast(throwable); - } else { - throw new AssertionError("Unexpected exception type", throwable); - } - } - throw new AssertionError("Expected exception not thrown"); - } -} \ No newline at end of file diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java index 34b982a486..381adc2825 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java @@ -17,8 +17,10 @@ package org.citrusframework.functions.core; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.testng.Assert; @@ -28,7 +30,8 @@ import static java.util.Collections.singletonList; public class RandomStringFunctionTest extends UnitTestSupport { - private RandomStringFunction function = new RandomStringFunction(); + + private final RandomStringFunction function = new RandomStringFunction(); @Test public void testFunction() { @@ -110,8 +113,31 @@ public void testTooManyParameters() { params.add("3"); params.add("UPPERCASE"); params.add("true"); - params.add("too much"); + params.add("0"); + params.add("too many"); function.execute(params, context); } -} + + @Test + public void testRandomSize() { + List params; + params = new ArrayList<>(); + params.add("10"); + params.add("UPPERCASE"); + params.add("true"); + params.add("8"); + + Set sizes = new HashSet<>(); + + for (int i = 0; i < 1000; i++) { + String text = function.execute(params, context); + sizes.add(text.length()); + } + + Assert.assertTrue(sizes.contains(8)); + Assert.assertTrue(sizes.contains(9)); + Assert.assertTrue(sizes.contains(10)); + + } +} \ No newline at end of file From f0b180180fb981b4cc43fd21ccea3ab8298a8953 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Mon, 13 May 2024 11:45:01 +0200 Subject: [PATCH 08/47] feat(#1156): provide test api generator --- .../message/MessagePayloadUtils.java | 34 + .../citrusframework/testapi/GeneratedApi.java | 45 + .../testapi/GeneratedApiRequest.java | 29 + .../message/MessagePayloadUtilsTest.java | 67 +- .../ApiActionBuilderCustomizerService.java | 13 + pom.xml | 20 + src/manual/connector-openapi.adoc | 398 ++++++++ src/manual/index.adoc | 2 + .../citrus-test-api-generator-core/pom.xml | 202 ++++ .../openapi/generator/JavaCitrusCodegen.java | 345 +++++++ .../SimpleWsdlToOpenApiTransformer.java | 187 ++++ .../WsdlToOpenApiTransformationException.java | 8 + .../org.openapitools.codegen.CodegenConfig | 1 + .../resources/java-citrus/api-model.mustache | 2 + .../main/resources/java-citrus/api.mustache | 265 ++++++ .../resources/java-citrus/api_doc.mustache | 1 + .../resources/java-citrus/api_soap.mustache | 165 ++++ .../resources/java-citrus/api_test.mustache | 1 + .../java-citrus/bean_configuration.mustache | 38 + .../bean_definition_parser.mustache | 215 +++++ .../main/resources/java-citrus/model.mustache | 1 + .../resources/java-citrus/model_doc.mustache | 1 + .../java-citrus/namespace_handler.mustache | 36 + .../resources/java-citrus/schema.mustache | 217 +++++ .../java-citrus/schema_soap.mustache | 107 +++ .../resources/java-citrus/test_base.mustache | 245 +++++ .../java-citrus/test_base_soap.mustache | 187 ++++ .../openapi/generator/GeneratedApiIT.java | 626 +++++++++++++ .../openapi/generator/GetPetByIdTest.java | 254 ++++++ .../generator/JavaCitrusCodegenIT.java | 93 ++ .../generator/JavaCitrusCodegenTest.java | 166 ++++ .../openapi/generator/ServiceLoaderTest.java | 24 + .../SimpleWsdlToOpenApiTransformerTest.java | 29 + .../generator/SpringBeanConfigurationIT.java | 55 ++ .../util/TestApiActionBuilderCustomizer.java | 22 + ....testapi.ApiActionBuilderCustomizerService | 1 + .../test/resources/META-INF/spring.handlers | 3 + .../test/resources/META-INF/spring.schemas | 3 + .../apis/multiparttest-rest-resource.yaml | 249 +++++ .../src/test/resources/apis/petstore.yaml | 700 ++++++++++++++ .../apis/petstore_reservedWords.yaml | 120 +++ .../src/test/resources/citrus-context.xml | 7 + .../defaultOas3SchemaValidationTest.xml | 25 + .../failOnReasonPhraseTest.xml | 25 + .../GeneratedApiTest/failOnStatusTest.xml | 25 + .../GeneratedApiTest/failOnVersionTest.xml | 25 + .../getPetByIdRequestTest.xml | 24 + .../jsonDeactivatedSchemaValidationTest.xml | 26 + .../GeneratedApiTest/jsonPathExtractTest.xml | 25 + .../jsonPathExtractionTest.xml | 25 + .../jsonPathValidationFailureTest.xml | 25 + .../jsonPathValidationTest.xml | 25 + .../jsonSchemaValidationFailureTest.xml | 25 + .../jsonSchemaValidationTest.xml | 25 + .../multipartWithFileAttributesTest.xml | 22 + .../multipartWithMultipleDatatypesTest.xml | 24 + .../multipartWithPlainTextTest.xml | 32 + .../payloads/AdditionalData.json | 6 + .../payloads/MultipartTemplate.xml | 4 + .../GeneratedApiTest/payloads/Schema.json | 1 + .../payloads/addPetMessage.json | 6 + .../payloads/getPetByIdControlMessage1.json | 6 + .../payloads/getPetByIdControlMessage2.json | 6 + .../GeneratedApiTest/postFileTest.xml | 22 + .../GeneratedApiTest/scriptValidationTest.xml | 25 + .../sendWithBodyLiteralTest.xml | 20 + .../sendWithBodyLiteralWithVariableTest.xml | 23 + .../GeneratedApiTest/sendWithBodyTest.xml | 20 + .../sendWithExtraHeaderTest.xml | 22 + .../MultipartTestAbstractTestRequest.java | 245 +++++ .../MultipartTestBeanDefinitionParser.java | 215 +++++ .../MultipartTestNamespaceHandler.java | 29 + .../rest/multiparttest/model/Metadata.java | 1 + .../multiparttest/model/PutObjectResult.java | 1 + .../request/MultiparttestControllerApi.java | 750 +++++++++++++++ .../MultipartTestBeanConfiguration.java | 56 ++ .../citrus/PetStoreAbstractTestRequest.java | 245 +++++ .../citrus/PetStoreBeanDefinitionParser.java | 215 +++++ .../extension/PetStoreNamespaceHandler.java | 45 + .../rest/petstore/model/Category.java | 1 + .../rest/petstore/model/ModelApiResponse.java | 1 + .../rest/petstore/model/Order.java | 1 + .../expectedgen/rest/petstore/model/Pet.java | 1 + .../expectedgen/rest/petstore/model/Tag.java | 1 + .../expectedgen/rest/petstore/model/User.java | 1 + .../rest/petstore/request/PetApi.java | 862 ++++++++++++++++++ .../rest/petstore/request/StoreApi.java | 433 +++++++++ .../rest/petstore/request/UserApi.java | 819 +++++++++++++++++ .../spring/PetStoreBeanConfiguration.java | 142 +++ .../OpenApiFromWsdlAbstractTestRequest.java | 187 ++++ .../OpenApiFromWsdlBeanDefinitionParser.java | 215 +++++ .../OpenApiFromWsdlNamespaceHandler.java | 26 + .../request/BookServiceSoapApi.java | 330 +++++++ .../OpenApiFromWsdlBeanConfiguration.java | 38 + .../BookDatatypes.xsd | 67 ++ .../BookService-generated.yaml | 33 + .../BookService.wsdl | 110 +++ .../pom.xml | 111 +++ .../maven/plugin/CodeGenMojoWrapper.java | 86 ++ .../maven/plugin/SpringMetaFileGenerator.java | 156 ++++ .../maven/plugin/TestApiGeneratorMojo.java | 412 +++++++++ .../TestApiGeneratorMojoIntegrationTest.java | 314 +++++++ .../plugin/TestApiGeneratorMojoUnitTest.java | 286 ++++++ ...itrusOpenApiGeneratorMavenProjectStub.java | 42 + .../pom-full-config.xml | 42 + .../pom-full-with-version-config.xml | 42 + .../pom-minimal-config.xml | 32 + .../pom-minimal-with-version-config.xml | 33 + .../pom-missing-prefix.xml | 32 + .../pom-missing-source.xml | 32 + .../pom-multi-config.xml | 40 + .../pom-soap-config.xml | 33 + .../src/test/resources/api/test-api.yml | 125 +++ test-api-generator/pom.xml | 37 + .../text/PlainTextMessageValidator.java | 44 +- 115 files changed, 12632 insertions(+), 60 deletions(-) create mode 100644 core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java create mode 100644 core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java create mode 100644 core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java create mode 100644 test-api-generator/citrus-test-api-generator-core/pom.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_doc.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_test.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/citrus-context.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-with-version-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-prefix.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-source.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-multi-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/test-api.yml create mode 100644 test-api-generator/pom.xml diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java index 09145650a7..4c2a8824c8 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java @@ -212,4 +212,38 @@ public static String prettyPrintJson(String payload) { } return sb.toString(); } + + /** + * Normalizes the given text by replacing all whitespace characters (identified by {@link Character#isWhitespace) by a single space + * and replacing windows style line endings with unix style line endings. + */ + public static String normalizeWhitespace(String text, boolean normalizeWhitespace, boolean normalizeLineEndingsToUnix) { + if (text == null || text.isEmpty()) { + return text; + } + + if (normalizeWhitespace) { + StringBuilder result = new StringBuilder(); + boolean lastWasSpace = true; + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + if (Character.isWhitespace(c)) { + if (!lastWasSpace) { + result.append(' '); + } + lastWasSpace = true; + } else { + result.append(c); + lastWasSpace = false; + } + } + return result.toString().trim(); + } + + if (normalizeLineEndingsToUnix) { + return text.replaceAll("\\r(\\n)?", "\n"); + } + + return text; + } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java new file mode 100644 index 0000000000..a3d6bfdad2 --- /dev/null +++ b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java @@ -0,0 +1,45 @@ +package org.citrusframework.testapi; + +import java.util.Map; + +/** + * Interface representing a generated API from an OpenAPI specification. + * Provides methods to retrieve metadata about the API such as title, version, + * prefix, and information extensions. + */ +public interface GeneratedApi { + + /** + * Retrieves the title of the OpenAPI specification, as specified in the info section of the API. + * + * @return the title of the OpenAPI specification + */ + String getApiTitle(); + + /** + * Retrieves the version of the OpenAPI specification, as specified in the info section of the API. + * + * @return the version of the OpenAPI specification + */ + String getApiVersion(); + + /** + * Retrieves the prefix used for the API, as specified in the API generation configuration. + * + * @return the prefix used for the API + */ + String getApiPrefix(); + + /** + * Retrieves the specification extensions of the OpenAPI defined in the "info" section. + *

    + * Specification extensions, also known as vendor extensions, are custom key-value pairs used to describe extra + * functionality not covered by the standard OpenAPI Specification. These properties start with "x-". + * This method collects only the extensions defined in the "info" section of the API. + *

    + * + * @return a map containing the specification extensions defined in the "info" section of the API, + * where keys are extension names and values are extension values + */ + Map getApiInfoExtensions(); +} \ No newline at end of file diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java new file mode 100644 index 0000000000..5b519ac118 --- /dev/null +++ b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java @@ -0,0 +1,29 @@ +package org.citrusframework.testapi; + +/** + * Interface representing a generated API request corresponding to an operation in an OpenAPI specification. + * Provides methods to retrieve metadata about the request such as operation name, HTTP method, and path. + */ +public interface GeneratedApiRequest { + + /** + * Retrieves the name of the OpenAPI operation associated with the request. + * + * @return the name of the OpenAPI operation + */ + String getOperationName(); + + /** + * Retrieves the HTTP method used for the request. + * + * @return the HTTP method used for the request (e.g., GET, POST) + */ + String getMethod(); + + /** + * Retrieves the path used for the request. + * + * @return the path used for the request + */ + String getPath(); +} diff --git a/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java b/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java index 369385adc4..d89f582038 100644 --- a/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java +++ b/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java @@ -16,56 +16,79 @@ package org.citrusframework.message; +import static org.testng.Assert.assertEquals; + import org.testng.Assert; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class MessagePayloadUtilsTest { @Test public void shouldPrettyPrintJson() { - Assert.assertEquals(MessagePayloadUtils.prettyPrint(""), ""); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{}"), "{}"); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("[]"), "[]"); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\"}"), + assertEquals(MessagePayloadUtils.prettyPrint(""), ""); + assertEquals(MessagePayloadUtils.prettyPrint("{}"), "{}"); + assertEquals(MessagePayloadUtils.prettyPrint("[]"), "[]"); + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\"}"), String.format("{%n \"user\": \"citrus\"%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"text\":\"\"}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"text\":\"\"}"), String.format("{%n \"text\": \"\"%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n { \"user\":%n%n \"citrus\" }")), + assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n { \"user\":%n%n \"citrus\" }")), String.format("{%n \"user\": \"citrus\"%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32}"), String.format("{%n \"user\": \"citrus\",%n \"age\": 32%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("[22, 32]"), + assertEquals(MessagePayloadUtils.prettyPrint("[22, 32]"), String.format("[%n22,%n32%n]")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}]"), + assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}]"), String.format("[%n {%n \"user\": \"citrus\",%n \"age\": 32%n }%n]")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}, {\"user\":\"foo\",\"age\": 99}]"), + assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}, {\"user\":\"foo\",\"age\": 99}]"), String.format("[%n {%n \"user\": \"citrus\",%n \"age\": 32%n },%n {%n \"user\": \"foo\",%n \"age\": 99%n }%n]")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pet\":{\"name\": \"fluffy\", \"age\": 4}}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pet\":{\"name\": \"fluffy\", \"age\": 4}}"), String.format("{%n \"user\": \"citrus\",%n \"age\": 32,%n \"pet\": {%n \"name\": \"fluffy\",%n \"age\": 4%n }%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pets\":[\"fluffy\",\"hasso\"]}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pets\":[\"fluffy\",\"hasso\"]}"), String.format("{%n \"user\": \"citrus\",%n \"age\": 32,%n \"pets\": [%n \"fluffy\",%n \"hasso\"%n ]%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[\"fluffy\",\"hasso\"],\"age\": 32}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[\"fluffy\",\"hasso\"],\"age\": 32}"), String.format("{%n \"user\": \"citrus\",%n \"pets\": [%n \"fluffy\",%n \"hasso\"%n ],%n \"age\": 32%n}")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[{\"name\": \"fluffy\", \"age\": 4},{\"name\": \"hasso\", \"age\": 2}],\"age\": 32}"), + assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[{\"name\": \"fluffy\", \"age\": 4},{\"name\": \"hasso\", \"age\": 2}],\"age\": 32}"), String.format("{%n \"user\": \"citrus\",%n \"pets\": [%n {%n \"name\": \"fluffy\",%n \"age\": 4%n },%n {%n \"name\": \"hasso\",%n \"age\": 2%n }%n ],%n \"age\": 32%n}")); } @Test public void shouldPrettyPrintXml() { - Assert.assertEquals(MessagePayloadUtils.prettyPrint(""), ""); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(""), + assertEquals(MessagePayloadUtils.prettyPrint(""), ""); + assertEquals(MessagePayloadUtils.prettyPrint(""), String.format("%n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("Citrus rocks!"), + assertEquals(MessagePayloadUtils.prettyPrint("Citrus rocks!"), String.format("%n Citrus rocks!%n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint("Citrus rocks!"), + assertEquals(MessagePayloadUtils.prettyPrint("Citrus rocks!"), String.format("%n%n Citrus rocks!%n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%nCitrus rocks!%n%n")), + assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%nCitrus rocks!%n%n")), String.format("%n Citrus rocks!%n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n %nCitrus rocks!%n %n")), + assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n %nCitrus rocks!%n %n")), String.format("%n Citrus rocks!%n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n ")), + assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n ")), String.format("%n %n %n %n%n")); - Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("")), + assertEquals(MessagePayloadUtils.prettyPrint(String.format("")), String.format("%n %n %n %n%n")); } + + @DataProvider + public Object[][] normalizeWhitespaceProvider() { + return new Object[][] { + // Test data: payload, ignoreWhitespace, ignoreNewLineType, expected result + {"Hello \t\r\nWorld\r\n", true, true, "Hello World"}, + {"Hello \t\r\nWorld\r\n", true, false, "Hello World"}, + {"Hello \t\r\nWorld\r\n", false, true, "Hello \t\nWorld\n"}, + {"Hello \t\r\nWorld\r\n", false, false, "Hello \t\r\nWorld\r\n"}, + {"", true, true, ""}, + {"", false, false, ""}, + {null, true, true, null}, + {null, false, false, null} + }; + } + + @Test(dataProvider = "normalizeWhitespaceProvider") + public void normalizeWhitespace(String text, boolean normalizeWhitespace, boolean normalizeLineEndingsToUnix, String expected) { + assertEquals(MessagePayloadUtils.normalizeWhitespace(text, normalizeWhitespace, normalizeLineEndingsToUnix), expected); + } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java b/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java new file mode 100644 index 0000000000..2b77d97f7b --- /dev/null +++ b/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java @@ -0,0 +1,13 @@ +package org.citrusframework.testapi; + +import org.citrusframework.TestAction; +import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; +import org.citrusframework.context.TestContext; + +/** + * Implementors of this interface are used to customize the SendMessageActionBuilder with application specific information. E.g. cookies + * or transactionIds. + */ +public interface ApiActionBuilderCustomizerService { + > T build(GeneratedApi generatedApi, TestAction action, TestContext context, T builder); +} diff --git a/pom.xml b/pom.xml index c007ae01ac..28a484cd68 100644 --- a/pom.xml +++ b/pom.xml @@ -175,6 +175,7 @@ 1.6.13 3.9.0 3.13.1 + 3.3.0 3.0.1 3.3.1 1.11.2 @@ -250,6 +251,7 @@ 3.2.0 4.1.105.Final 4.12.0 + 7.5.0 4.7.6 42.7.5 3.17.4 @@ -523,6 +525,19 @@ awaitility ${awaitility.version} + + + org.openapitools + openapi-generator + ${openapi-generator-maven-plugin} + provided + + + + org.springframework + spring-test + ${spring.version} + org.testng testng @@ -1007,6 +1022,11 @@ jackson-databind ${jackson.version} + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.version} + com.fasterxml.jackson.module jackson-module-jaxb-annotations diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc index 810fda6a05..8bf9511afa 100644 --- a/src/manual/connector-openapi.adoc +++ b/src/manual/connector-openapi.adoc @@ -309,3 +309,401 @@ Also, the server will verify the HTTP request method, the Content-Type header as The given HTTP status code defines the response that should be sent by the server. The server will generate a proper response according to the OpenAPI specification. This also includes a potential response message body (e.g. pet object). + +[[openapi-server]] +=== OpenAPI Test API Generator + +For an even deeper integration with a given OpenAPI, Citrus offers the possibility to generate a dedicated Test API which provides test actions tailored to the specific operations of the OpenAPI under evaluation. +These actions can be used in XML or Java DSL. +This functionality is provided by the `Citrus OpenAPI Test API Generator` which leverages the link:https://github.com/swagger-api/swagger-codegen/tree/master[OpenAPI Code Generator] to generate code, but provides custom templates tailored for seamless integration within the Citrus framework. + +The generator provides the following features: + +* generation of a Test API +** from OpenAPI Specification +** [TODO #1163] from WSDL via an intermediate step that generates a "light" OpenApi specification from a WSDL +* integration into Citrus XML test cases +** integration into XML editors via generated XSD +*** schema validation +*** auto completion +* integration into Citrus Java test cases via Java DSL [TODO #1161] + +The following directory structure/table specifies the files, which are generated by the generator. +Note that the `Prefix` is a configuration parameter which should uniquely identify a generated API. +It is specified in the build configuration for the Test API. +``` +target/ +├───generated-test-resources/ +│ ├───META-INF/ +│ │ ├───spring.handlers +│ │ └───spring.schemas +│ └───schema/ +│ └───xsd/ +│ └───prefix-api.xsd +└───generated-test-sources/ + └───org/ + └───citrusframework/ + └───automation/ + └───prefix/ + ├───api/ + │ └───MyApi.java + ├───citrus/ + │ ├───extension/ + │ │ └───PrefixNamespaceHandler.java + │ ├───PrefixAbstractTestRequest.java + │ └───PrefixBeanDefinitionParser.java + ├───model/ + │ ├───MyReqTypeA.java + │ └───MyReqTypeB.java + └───spring/ + └───PrefixBeanConfiguration.java +``` + +|=== +| File | Content + +| `spring.handlers` | Spring namespace handler configuration, that contains all NamespaceHandlers for all generated APIs. +| `spring.schemas` | Spring schema definitions, with mappings of namespaces to schemas for all generated APIs. +| `prefix-api.xsd` | XSD schema for the integration of the Test API into XML. +| `PrefixNamespaceHandler.java` | A Spring class, that registers bean definition parsers for Test API XML elements. +| `PrefixAbstractTestRequest.java` | Abstract superclass of all Test API actions. +| `PrefixBeanDefinitionParser.java` | Spring bean definition parser, responsible for parsing Test API XML elements into test actions. +| `MyReqTypeA.java, MyReqTypeB.java` | Model files generated with respect to the schema definition of the OpenAPI. +| `PrefixBeanConfiguration.java` | A Spring @Configuration class, that registers all Test API actions as Spring beans. +|=== + +==== Configuration of Test API generation + +Code generation is typically performed during the build process. +For the Citrus Test API Generator, it is carried out by a Maven plugin. +While the standard generator plugin, `org.openapitools:openapi-generator-maven-plugin`, can be employed for this purpose, configuring it can be cumbersome, especially when dealing with multiple APIs. +To address this challenge, Citrus offers its adaptation of this standard generator Maven plugin. +This `Citrus OpenAPI Generator Plugin` simplifies the configuration of test API generation by providing predefined defaults and supporting the generation of multiple APIs. +Additionally, it enhances support for generating Spring integration files (`spring.handlers` and `spring.schemas`), thereby facilitating the integration of generated APIs into Spring-based applications. +Consequently, utilizing the Citrus Generator Plugin is recommended in most scenarios. + +The following shows the configuration of test api generation for different scenarios: + +.Citrus OpenAPI Generator Plugin - multiple APIs, minimal configuration +[source,xml,indent=0,role="primary"] +---- + + citrus-test-api-generator-maven-plugin + + + + + Multi1 + api/test-api.yml + + + Multi2 + api/test-api.yml + + + Multi3 + api/test-api.yml + + + + + + + create-test-api + + + + + +---- + +.Citrus OpenAPI Generator Plugin - single API full configuration +[source,xml,indent=0,role="secondary"] +---- + + citrus-test-api-generator-maven-plugin + + + + my-generated-sources + my-generated-resources + myschema/xsd + src/main/resources/META-INF + + Full + api/test-api.yml + org.mypackage.%PREFIX%.api + myEndpoint + org.mypackage.%PREFIX%.invoker + org.mypackage.%PREFIX%.model + "http://company/citrus-test-api/myNamespace" + + + + + + + + create-test-api + + + + +---- + +.Standard OpenAPI Generator Plugin +[source,xml,indent=0,role="secondary"] +---- + + + org.openapitools + openapi-generator-maven-plugin + + + + org.citrusframework + citrus-test-api-generator-core + ${project.version} + + + + + REST + generated-test-resources + generated-test-sources + true + + true + + java-citrus + ${project.build.directory} + + + + generate-openapi-petstore-files + compile + + generate + + + ${project.basedir}/src/test/resources/apis/petstore.yaml + + org.citrusframework.openapi.generator.rest.petstore + org.citrusframework.openapi.generator.rest.petstore.request + org.citrusframework.openapi.generator.rest.petstore.model + PetStore + petStoreEndpoint + + + + + generate-openapi-files-for-soap + compile + + generate + + + ${project.basedir}/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml + + SOAP + org.citrusframework.openapi.generator.soap.bookservice + org.citrusframework.openapi.generator.soap.bookservice.request + org.citrusframework.openapi.generator.soap.bookservice.model + SoapSample + OpenApiFromWsdl + soapSampleEndpoint + + + + + +---- + +These are the primary elements you can configure in the `` section: + +|=== +| Configuration element | Maven Property | Description | Default Value + +| `schemaFolder` | `citrus.test.api.generator.schema.folder` | Location for the generated XSD schemas | `schema/xsd/%VERSION%` +| `resourceFolder` | `citrus.test.api.generator.resource.folder` | Location to which resources are generated | `generated-resources` +| `sourceFolder` | `citrus.test.api.generator.source.folder` | Location to which sources are generated | `generated-sources` +| `metaInfFolder` | `citrus.test.api.generator.meta.inf.folder` | Location to which spring meta files are generated/updated | `target/generated-test-resources/META-INF` +| `generateSpringIntegrationFiles` | `citrus.test.api.generator.generate.spring.integration.files` | Specifies whether spring integration files should be generated | `true` +| Nested api element | | | +| `prefix` | `citrus.test.api.generator.prefix` | Specifies the prefix used for the test API, typically an acronym | (no default, required) +| `source` | `citrus.test.api.generator.source` | Specifies the source of the test API | (no default, required) +| `version` | `citrus.test.api.generator.version` | Specifies the version of the API, may be null | (none) +| `endpoint` | `citrus.test.api.generator.endpoint` | Specifies the endpoint of the test API | `applicationServiceClient` +| `type` | `citrus.test.api.generator.type` | Specifies the type of the test API | `REST`, other option is `SOAP` +| `useTags` | `citrus.test.api.generator.use.tags` | Specifies whether tags should be used by the generator | `true` +| `invokerPackage` | `citrus.test.api.generator.invoker.package` | Package for the test API classes | `org.citrusframework.automation.%PREFIX%.%VERSION%` +| `apiPackage` | `citrus.test.api.generator.api.package` | Package for the test API interface classes | `org.citrusframework.automation.%PREFIX%.%VERSION%.api` +| `modelPackage` | `citrus.test.api.generator.model.package` | Package for the test API model classes | `org.citrusframework.automation.%PREFIX%.%VERSION%.model` +| `targetXmlnsNamespace` | `citrus.test.api.generator.namespace` | XML namespace used by the API | `http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api` +|=== + + +Note: `%PREFIX%` and `%VERSION%` are placeholders that will be replaced by their specific values as configured. +The plugin performs a conversion to lowercase for `PREFIX` used in package names and in `targetXmlnsNamespace`. + +==== Running the generator + +To run the generator, execute the following command in your project directory: + +[source,bash] +---- +mvn citrus-test-api-generator-maven-plugin:create-test-api +---- + + +This command will generate the classes and XSD files as configured for your APIs in the specified locations. + +==== Spring meta file generation + +The `citrus-test-api-generator-maven-plugin` supports the generation of Spring integration files, specifically `spring.handlers` and `spring.schemas`. +These files are essential for Spring applications utilizing XML configuration, as they provide mapping information for custom XML namespaces. + +===== Purpose + +The generated Spring integration files serve the purpose of mapping custom XML namespaces to their corresponding namespace handler and schema locations. +This mapping allows Spring to properly parse and validate XML configuration files containing custom elements and attributes. + +===== Configuration + +The maven plugin generates these Spring integration files based on the provided configuration in the `citrus-test-api-generator-maven-plugin` section of the pom.xml file. +For each API specified, the plugin writes entries into the `spring.handlers` and `spring.schemas` files according to the configured XML namespaces and their corresponding handlers and schemas. + +===== Important Consideration + +When there are other non-generated Spring schemas or handlers present in the `META-INF` folder, it's crucial to ensure that the `metaInfFolder` configuration points to the existing `META-INF` directory in the main resources, which is usually `src/main/resources/META-INF`. +This ensures that the plugin correctly updates the existing files without overwriting them. + +To identify generated schemas, their namespace should include the following segment `citrus-test-schema`. +During updates of the meta files, the generator filters out lines containing this segment from existing files and then re-adds them, preserving any non-generated content. + +==== Usage + +Once generated, the `spring.handlers` and `spring.schemas` files, along with any existing non-generated content, should be included in the resources of your Spring application. +During runtime, Spring will use these files to resolve custom XML namespaces and handle elements accordingly. +This automatically happens if one of the following folders is chosen: + +- `target/generated-test-resources/META-INF` (default) +- `target/generated-resources/META-INF` for pure testing projects that provide their code on main rather than test +- `src/main/resources/META-INF` - for mixing existing meta files with generated + +==== Configuration of the Test Classpath + +In case you choose to generate the API into `generated-test` folders, the maven build requires further configuration to add the `generated-test` folders to the classpath. +The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-helper-maven-plugin] is used to accomplish this configuration step. + +[source,xml] +---- + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-test-sources + generate-test-sources + + add-test-source + + + + ${project.build.directory}/generated-test-sources + + + + + add-test-resource + generate-test-resources + + add-test-resource + + + + + ${project.build.directory}/generated-test-resources + + + + + + + + +---- + +==== Sample usage + +To utilize the test API in XML, it's necessary to import the respective namespace. Once imported, requests can be directly employed as actions, as illustrated in the sample below. +Further examples can be found here `org.citrusframework.openapi.generator.GeneratedApiIT`. + +.XML DSL +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + + + + + +---- + +To utilize the test API in Java, it's necessary to import the API configuration, that provides the respective request actions. +The request to test can then be autowired, configured and autowired, as illustrated in the sample below. +Further examples can be found here `org.citrusframework.openapi.generator.GetPetByIdTest`. + +.Java DSL +[source,java,indent=0,role="secondary"] +---- +@ExtendWith(CitrusSpringExtension.class) +@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class}) +class GetPetByIdTest { + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private GetPetByIdRequest getPetByIdRequest; + + @Test + @CitrusTest + void testByJsonPath(@CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + + // Assert body by json path + getPetByIdRequest.setResponseValue(Map.of("$.name", "Snoopy")); + + // When + runner.$(getPetByIdRequest); + } +} + +---- diff --git a/src/manual/index.adoc b/src/manual/index.adoc index 1666180857..84b6029c74 100644 --- a/src/manual/index.adoc +++ b/src/manual/index.adoc @@ -61,6 +61,8 @@ include::endpoint-restdocs.adoc[] include::endpoint-component.adoc[] include::endpoint-adapter.adoc[] +include::testapi.adoc[] + include::connectors.adoc[] include::connector-openapi.adoc[] include::connector-jbang.adoc[] diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml new file mode 100644 index 0000000000..c74f91249a --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -0,0 +1,202 @@ + + 4.0.0 + + citrus-test-api-generator + org.citrusframework + 4.3.0-SNAPSHOT + ../pom.xml + + + citrus-test-api-generator-core + jar + + Citrus :: Test API Generator :: Core + Generates a Citrus Test-API for OpenAPI and WSDL specifications. + + + + + org.citrusframework + citrus-api + ${project.version} + + + org.citrusframework + citrus-http + ${project.version} + + + org.citrusframework + citrus-spring + ${project.version} + test + + + org.citrusframework + citrus-ws + ${project.version} + + + + org.assertj + assertj-core + ${assertj.version} + test + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + org.openapitools + openapi-generator + + + wsdl4j + wsdl4j + + + + + org.citrusframework + citrus-junit5 + ${project.version} + test + + + org.springframework.boot + spring-boot-test + ${spring.boot.test.version} + test + + + org.citrusframework + citrus-validation-json + ${project.version} + test + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + ${maven.helper.plugin.version} + + + add-generated-specs + generate-test-resources + + add-test-resource + + + + + ${project.build.directory}/generated-test-resources + ${project.build.outputDirectory} + + + + + + add-generated-classes + generate-test-sources + + add-test-source + + + + ${project.build.directory}/generated-test-sources + + + + + + + + org.openapitools + openapi-generator-maven-plugin + + + org.citrusframework + citrus-test-api-generator-core + ${project.version} + + + + + REST + generated-test-resources + generated-test-sources + true + + true + java-citrus + ${project.build.directory} + + + + generate-openapi-petstore-files + compile + + generate + + + ${project.basedir}/src/test/resources/apis/petstore.yaml + + org.citrusframework.openapi.generator.rest.petstore + org.citrusframework.openapi.generator.rest.petstore.request + org.citrusframework.openapi.generator.rest.petstore.model + PetStore + petStoreEndpoint + + + + + generate-openapi-files-for-soap + compile + + generate + + + ${project.basedir}/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml + + SOAP + org.citrusframework.openapi.generator.soap.bookservice + org.citrusframework.openapi.generator.soap.bookservice.request + org.citrusframework.openapi.generator.soap.bookservice.model + SoapSample + OpenApiFromWsdl + soapSampleEndpoint + + + + + + + generate-openapi-multiparttest-files + compile + + generate + + + ${project.basedir}/src/test/resources/apis/multiparttest-rest-resource.yaml + + org.citrusframework.openapi.generator.rest.multiparttest + org.citrusframework.openapi.generator.rest.multiparttest.request + org.citrusframework.openapi.generator.rest.multiparttest.model + MultipartTest + multipartTestEndpoint + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java new file mode 100644 index 0000000000..7aa18331b5 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java @@ -0,0 +1,345 @@ +package org.citrusframework.openapi.generator; + +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toMap; +import static org.openapitools.codegen.CliOption.newString; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Info; +import java.io.File; +import java.util.ArrayList; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.languages.AbstractJavaCodegen; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Thorsten Schlathoelter + */ +public class JavaCitrusCodegen extends AbstractJavaCodegen { + + private static final Logger logger = LoggerFactory.getLogger(JavaCitrusCodegen.class); + + private static final String ABSTRACT_TEST_REQUEST_JAVA = "AbstractTestRequest.java"; + private static final String API_TYPE_REST = "REST"; + private static final String API_TYPE_SOAP = "SOAP"; + public static final String CODEGEN_NAME = "java-citrus"; + + // possible optional parameters + public static final String API_ENDPOINT = "apiEndpoint"; + public static final String API_TYPE = "apiType"; + public static final String GENERATED_SCHEMA_FOLDER = "generatedSchemaFolder"; + public static final String HTTP_PATH_PREFIX = "httpPathPrefix"; + public static final String OPENAPI_SCHEMA = "openapiSchema"; + public static final String PREFIX = "prefix"; + public static final String RESOURCE_FOLDER = "resourceFolder"; + public static final String SOURCE_FOLDER = "sourceFolder"; + public static final String TARGET_XMLNS_NAMESPACE = "targetXmlnsNamespace"; + + // default values for optional parameters + protected String apiPrefix = "Api"; + + protected String httpClient = API_ENDPOINT; + protected String httpPathPrefix = "api"; + protected String openapiSchema = "oas3"; + protected String resourceFolder = + "src" + File.separator + "main" + File.separator + "resources"; + protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; + protected String targetXmlnsNamespace; + + protected String apiVersion = "1.0.0"; + + public JavaCitrusCodegen() { + super(); + // the root folder where all files are emitted + outputFolder = "generated-code" + File.separator + "java"; + + // this is the location which templates will be read from in the - resources - directory + templateDir = CODEGEN_NAME; + + // register additional properties which will be available in the templates + additionalProperties.put("apiVersion", apiVersion); + + // set default + additionalProperties.put(API_TYPE, API_TYPE_REST); + + // add additional reserved words used in CitrusAbstractTestRequest and its base class to prevent name collisions + Set reservedWordsTemp = reservedWords(); + reservedWordsTemp.addAll( + asList( + "name", + "description", + "actor", + "httpClient", + "dataSource", + "schemaValidation", + "schema", + "headerContentType", + "headerAccept", + "bodyFile", + "responseType", + "responseStatus", + "responseReasonPhrase", + "responseVersion", + "resource", + "responseVariable", + "responseValue", + "cookies", + "script", + "type" + ) + ); + setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); + + // add posibility to set a new value for the properties + cliOptions.add(newString(API_ENDPOINT, + "Which http client should be used (default " + httpClient + ").")); + cliOptions.add( + newString( + API_TYPE, + "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" + ) + ); + cliOptions.add( + newString(GENERATED_SCHEMA_FOLDER, + "The schema output directory (default " + generatedSchemaFolder + ").") + ); + cliOptions.add(newString(HTTP_PATH_PREFIX, + "Add a prefix to http path for all APIs (default " + httpPathPrefix + ").")); + cliOptions.add(newString(OPENAPI_SCHEMA, + "Which OpenAPI schema should be used (default " + openapiSchema + ").")); + cliOptions.add( + newString( + PREFIX, + "Add a prefix before the name of the files. First character should be upper case (default " + + apiPrefix + ")." + ) + ); + cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); + cliOptions.add(newString(RESOURCE_FOLDER, + "Where the resource files are emitted (default " + resourceFolder + ").")); + cliOptions.add( + newString(TARGET_XMLNS_NAMESPACE, + "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") + ); + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help tips, + * parameters here + * + * @return A string value for the help message + */ + @Override + public String getHelp() { + return "Generates citrus api requests."; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator to select + * the library with the -g flag. + * + * @return the friendly name for the generator + */ + @Override + public String getName() { + return CODEGEN_NAME; + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see org.openapitools.codegen.CodegenType + */ + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public void processOpts() { + super.processOpts(); + + if (additionalProperties.containsKey(API_ENDPOINT)) { + this.setHttpClient(additionalProperties.get(API_ENDPOINT).toString()); + } + additionalProperties.put(API_ENDPOINT, httpClient); + + if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { + this.setGeneratedSchemaFolder( + additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); + } + additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); + + if (additionalProperties.containsKey(HTTP_PATH_PREFIX)) { + this.setHttpPathPrefix(additionalProperties.get(HTTP_PATH_PREFIX).toString()); + additionalProperties.put(HTTP_PATH_PREFIX, httpPathPrefix); + } else { + logger.warn( + "Using empty http-path-prefix for code generation. A http-path-prefix can be configured using \"{}\" property.", + HTTP_PATH_PREFIX + ); + httpPathPrefix = ""; + } + + if (additionalProperties.containsKey(OPENAPI_SCHEMA)) { + this.setOpenapiSchema(additionalProperties.get(OPENAPI_SCHEMA).toString()); + } + additionalProperties.put(OPENAPI_SCHEMA, openapiSchema); + + if (additionalProperties.containsKey(PREFIX)) { + this.setApiPrefix(additionalProperties.get(PREFIX).toString()); + additionalProperties.put(PREFIX, apiPrefix); + additionalProperties.put(PREFIX + "LowerCase", apiPrefix.toLowerCase()); + } else { + logger.warn( + "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", + PREFIX); + apiPrefix = ""; + } + + if (additionalProperties.containsKey(RESOURCE_FOLDER)) { + this.setResourceFolder(additionalProperties.get(RESOURCE_FOLDER).toString()); + } + additionalProperties.put(RESOURCE_FOLDER, resourceFolder); + + if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { + this.setTargetXmlnsNamespace( + additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); + } else { + this.targetXmlnsNamespace = String.format( + "http://www.citrusframework.org/citrus-test-schema/%s-api", apiPrefix.toLowerCase()); + } + additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); + + // define different folders where the files will be emitted + final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", + File.separator); + final String citrusFolder = invokerFolder + File.separator + "citrus"; + final String extensionFolder = citrusFolder + File.separator + "extension"; + final String springFolder = invokerFolder + File.separator + "spring"; + final String schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; + + Object apiType = additionalProperties.get(API_TYPE); + if (API_TYPE_REST.equals(apiType)) { + addRestSupportingFiles(citrusFolder, schemaFolder); + } else if (API_TYPE_SOAP.equals(apiType)) { + addSoapSupportingFiles(citrusFolder, schemaFolder); + } else { + throw new IllegalArgumentException(String.format("Unknown API_TYPE: '%s'", apiType)); + } + + addDefaultSupportingFiles(citrusFolder, extensionFolder, springFolder); + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + Info info = openAPI.getInfo(); + Map extensions = info.getExtensions(); + if (extensions != null) { + additionalProperties.putAll(extensions); + + Map infoExtensions = extensions.entrySet().stream() + .filter(entry -> entry.getKey().toUpperCase( + ).startsWith("X-")) + .collect(toMap(Entry::getKey, Entry::getValue)); + additionalProperties.put("infoExtensions", infoExtensions); + } + } + + public void setApiPrefix(String apiPrefix) { + this.apiPrefix = apiPrefix; + } + + public String getHttpClient() { + return httpClient; + } + + public void setHttpClient(String httpClient) { + this.httpClient = httpClient; + } + + public String getHttpPathPrefix() { + return httpPathPrefix; + } + + public void setHttpPathPrefix(String httpPathPrefix) { + this.httpPathPrefix = httpPathPrefix; + } + + public String getOpenapiSchema() { + return openapiSchema; + } + + public void setOpenapiSchema(String openapiSchema) { + this.openapiSchema = openapiSchema; + } + + public String getResourceFolder() { + return resourceFolder; + } + + public void setResourceFolder(String resourceFolder) { + this.resourceFolder = resourceFolder; + } + + public String getGeneratedSchemaFolder() { + return generatedSchemaFolder; + } + + public void setGeneratedSchemaFolder(String generatedSchemaFolder) { + this.generatedSchemaFolder = generatedSchemaFolder; + } + + public String getTargetXmlnsNamespace() { + return targetXmlnsNamespace; + } + + public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { + this.targetXmlnsNamespace = targetXmlnsNamespace; + } + + public String getApiPrefix() { + return apiPrefix; + } + + private void addRestSupportingFiles(final String citrusFolder, String schemaFolder) { + supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, + apiPrefix.toLowerCase() + "-api.xsd")); + supportingFiles.add(new SupportingFile("test_base.mustache", citrusFolder, + apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + } + + private void addSoapSupportingFiles(final String citrusFolder, String schemaFolder) { + // Remove the default api template file + apiTemplateFiles().remove("api.mustache"); + apiTemplateFiles().put("api_soap.mustache", ".java"); + + supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, + apiPrefix.toLowerCase() + "-api.xsd")); + supportingFiles.add(new SupportingFile("api_soap.mustache", citrusFolder, + apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + supportingFiles.add(new SupportingFile("test_base_soap.mustache", citrusFolder, + apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + } + + private void addDefaultSupportingFiles(final String citrusFolder, final String extensionFolder, + final String springFolder) { + supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, + apiPrefix + "BeanConfiguration.java")); + supportingFiles.add(new SupportingFile("bean_definition_parser.mustache", citrusFolder, + apiPrefix + "BeanDefinitionParser.java")); + supportingFiles.add(new SupportingFile("namespace_handler.mustache", extensionFolder, + apiPrefix + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("api-model.mustache", resourceFolder, + apiPrefix.toLowerCase() + "-api-model.csv")); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java new file mode 100644 index 0000000000..68d7bf3579 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java @@ -0,0 +1,187 @@ +package org.citrusframework.openapi.generator; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY; +import static java.lang.String.format; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.responses.ApiResponses; +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import javax.wsdl.Binding; +import javax.wsdl.BindingOperation; +import javax.wsdl.Definition; +import javax.wsdl.WSDLException; +import javax.wsdl.factory.WSDLFactory; +import javax.wsdl.xml.WSDLReader; +import javax.xml.namespace.QName; +import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + +/** + * Transforms a wsdl specification into a simple OpenApi specification for usage with the OpenApiGenerator. + *

    + * + * Note that this transformer only transforms bindings from the wsdl into operations in the OpenApi. + */ +public class SimpleWsdlToOpenApiTransformer { + + private static final Logger logger = LoggerFactory.getLogger(SimpleWsdlToOpenApiTransformer.class); + + private static final YAMLMapper yamlMapper = (YAMLMapper) YAMLMapper.builder() + .enable(SORT_PROPERTIES_ALPHABETICALLY) + .build() + .setSerializationInclusion(NON_NULL); + + private final URI wsdlUri; + + public SimpleWsdlToOpenApiTransformer(URI wsdlUri) { + this.wsdlUri = wsdlUri; + } + + /** + * Transforms the wsdl of this transfromer into a OpenApi yaml representation. + * + * @return the OpenApi yaml + * @throws WsdlToOpenApiTransformationException if the parsing fails + */ + public String transformToOpenApi() throws WsdlToOpenApiTransformationException { + try { + Definition wsdlDefinition = readWSDL(); + Map bindings = wsdlDefinition.getBindings(); + OpenAPI openAPI = transformToOpenApi(bindings); + return convertToYaml(openAPI); + } catch (Exception e) { + throw new WsdlToOpenApiTransformationException("Unable to parse wsdl", e); + } + } + + /** + * Performs the actual transformation from bindings into OpenApi operations. + * + * @param bindings + * @return + */ + private OpenAPI transformToOpenApi(Map bindings) { + OpenAPI openAPI = new OpenAPI(); + openAPI.setInfo(createInfo()); + + Paths paths = new Paths(); + openAPI.setPaths(paths); + for (Entry entry : bindings.entrySet()) { + Object key = entry.getKey(); + Object value = entry.getValue(); + + if (key instanceof QName && value instanceof Binding) { + addOperations(openAPI, (QName) key, (Binding) value); + } + } + return openAPI; + } + + private Definition readWSDL() throws WSDLException { + logger.debug("Reading wsdl file from path: {}", wsdlUri); + + WSDLReader reader = WSDLFactory.newInstance().newWSDLReader(); + + // switch off the verbose mode + reader.setFeature("javax.wsdl.verbose", false); + reader.setFeature("javax.wsdl.importDocuments", true); + + if (logger.isDebugEnabled()) { + logger.debug("Reading the WSDL. Base uri is {}", wsdlUri); + } + + return reader.readWSDL(wsdlUri.toString()); + } + + private Info createInfo() { + Info info = new Info(); + info.setTitle("Generated api from wsdl"); + + info.setDescription( + format( + "This api has been generated from the following wsdl '%s'. It's purpose is solely to serve as input for SOAP API generation. Note that only operations are extracted from the WSDL. No schema information whatsoever is generated!", + java.nio.file.Paths.get(wsdlUri).getFileName() + ) + ); + info.setVersion("1.0.0"); + + Contact contact = new Contact(); + contact.setName("org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer"); + info.setContact(contact); + return info; + } + + private void addOperations(OpenAPI openApi, QName qName, Binding binding) { + String localPart = qName.getLocalPart(); + + String bindingApiName; + if (localPart.endsWith("SoapBinding")) { + bindingApiName = localPart.substring(0, localPart.length() - "SoapBinding".length()); + } else { + bindingApiName = localPart; + } + + List bindingOperations = binding.getBindingOperations(); + for (Object operation : bindingOperations) { + if (operation instanceof BindingOperation bindingOperation) { + addOperation( + openApi.getPaths(), + bindingOperation.getName(), + retrieveOperationDescription(bindingOperation), + bindingApiName + ); + } + } + } + + private void addOperation(Paths paths, String name, String description, String tag) { + Operation postOperation = new Operation(); + + logger.debug("Adding operation to spec: {}", name); + + postOperation.setOperationId(name); + postOperation.setDescription(description); + postOperation.tags(Collections.singletonList(tag)); + ApiResponses responses = new ApiResponses(); + postOperation.responses(responses); + + PathItem pi = new PathItem(); + pi.setPost(postOperation); + + paths.addPathItem("/" + name, pi); + } + + /** + * Retrieve the description of the bindingOperation via the documentation of the associated operation. + */ + private String retrieveOperationDescription(BindingOperation bindingOperation) { + String description = ""; + javax.wsdl.Operation soapOperation = bindingOperation.getOperation(); + if (soapOperation != null) { + Element documentationElement = soapOperation.getDocumentationElement(); + if (documentationElement != null) { + description = documentationElement.getTextContent(); + } + } + + return description; + } + + private String convertToYaml(OpenAPI openAPI) throws JsonProcessingException { + return yamlMapper.writeValueAsString(openAPI); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java new file mode 100644 index 0000000000..fd845194bf --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java @@ -0,0 +1,8 @@ +package org.citrusframework.openapi.generator.exception; + +public class WsdlToOpenApiTransformationException extends Exception { + + public WsdlToOpenApiTransformationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig new file mode 100644 index 0000000000..33a85c5059 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -0,0 +1 @@ +org.citrusframework.openapi.generator.JavaCitrusCodegen \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache new file mode 100644 index 0000000000..ae513df561 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache @@ -0,0 +1,2 @@ +OperationId;Path;Method;Parameters{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} +{{operationId}};{{path}};{{httpMethod}};{{#allParams}}{{paramName}}:{{{dataType}}}{{^-last}},{{/-last}}{{/allParams}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache new file mode 100644 index 0000000000..5d90d5f80c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -0,0 +1,265 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{package}}; + +import jakarta.annotation.Generated; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class {{classname}} implements GeneratedApi +{ + + public static final {{classname}} INSTANCE = new {{classname}}(); + + public String getApiTitle() { + return "{{appName}}"; + } + + public String getApiVersion() { + return "{{appVersion}}"; + } + + public String getApiPrefix() { + return "{{prefix}}"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + {{#infoExtensions}} + {{#entrySet}} + infoExtensionMap.put("{{key}}", "{{value}}"); + {{/entrySet}} + {{/infoExtensions}} + return infoExtensionMap; + } + + {{#operations}} + {{#operation}} + /** {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) + {{summary}} + {{description}} + **/ + public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "{{httpPathPrefix}}{{{path}}}"; + private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); + + {{#queryParams}} + private String {{paramName}}; + + {{/queryParams}} + {{#pathParams}} + private String {{paramName}}; + + {{/pathParams}} + {{#isMultipart}} + {{#formParams}} + private String {{paramName}}; + + {{/formParams}} + {{/isMultipart}} + {{#authMethods}}{{#isBasic}} + @Value("${" + "{{apiEndpoint}}.basic.username:#{null}}") + private String basicUsername; + @Value("${" + "{{apiEndpoint}}.basic.password:#{null}}") + private String basicPassword; + + {{/isBasic}} + {{/authMethods}} + + public {{operationIdCamelCase}}Request() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); + } + + public String getOperationName() { + return "{{operationId}}"; + } + + public String getMethod() { + return "{{httpMethod}}"; + } + + public String getPath() { + return "{{path}}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + {{#isMultipart}} + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + {{#formParams}} + {{#required}} + if(StringUtils.isBlank({{paramName}})) { + throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "{{paramName}}")); + } + {{/required}} + {{#isBinary}} + if (StringUtils.isNotBlank({{paramName}})) { + multiValues.add("{{paramName}}", new ClassPathResource({{paramName}})); + bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + {{/isBinary}} + {{^isBinary}} + if (StringUtils.isNotBlank({{paramName}})) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource({{paramName}}); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("{{paramName}}", resource); + } else { + multiValues.add("{{paramName}}", {{paramName}}); + } + bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + {{/isBinary}} + {{/formParams}} + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + {{/isMultipart}} + {{^isMultipart}} + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + {{/isMultipart}} + + Map queryParams = new HashMap<>(); + {{#allParams}}{{#isQueryParam}} + + if (StringUtils.isNotBlank(this.{{paramName}})) { + queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); + httpClientRequestActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); + } + {{/isQueryParam}}{{/allParams}} + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + {{#authMethods}}{{#isBasic}} + + if(basicUsername != null && basicPassword != null){ + messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); + } + {{/isBasic}}{{/authMethods}} + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + {{#queryParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/queryParams}} + {{#pathParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/pathParams}} + {{#isMultipart}} + {{#formParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/formParams}} + {{/isMultipart}} + {{#authMethods}}{{#isBasic}} + + public void setBasicUsername(String basicUsername) { + this.basicUsername = basicUsername; + } + + public void setBasicPassword(String basicPassword) { + this.basicPassword = basicPassword; + } + {{/isBasic}}{{/authMethods}} + private String replacePathParams(String endpoint) { + {{#pathParams}}endpoint = endpoint.replace("{" + "{{baseName}}" + "}", {{paramName}});{{/pathParams}} + return endpoint; + } + } + {{/operation}} + {{/operations}} +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_doc.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_doc.mustache new file mode 100644 index 0000000000..f8737ed4d9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_doc.mustache @@ -0,0 +1 @@ +# not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache new file mode 100644 index 0000000000..d39d1aff12 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -0,0 +1,165 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{package}}; + +import jakarta.annotation.Generated; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.FileUtils; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction.Builder.SendSoapMessageBuilderSupport; +import org.citrusframework.ws.actions.SoapActionBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class {{classname}} implements GeneratedApi +{ + public static final {{classname}} INSTANCE = new {{classname}}(); + + public String getApiTitle() { + return "{{appName}}"; + } + + public String getApiVersion() { + return "{{appVersion}}"; + } + + public String getApiPrefix() { + return "{{prefix}}"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + {{#infoExtensions}} + {{#entrySet}} + infoExtensionMap.put("{{key}}", "{{value}}"); + {{/entrySet}} + {{/infoExtensions}} + return infoExtensionMap; + } + + {{#operations}} + {{#operation}} + /** + {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) + {{summary}} + {{description}} + **/ + public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { + + private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); + + // Query params + {{#allParams}}{{#isQueryParam}}private String {{paramName}}; + {{/isQueryParam}}{{/allParams}} + + public {{operationIdCamelCase}}Request(){ + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); + } + + public String getOperationName() { + return "{{operationId}}"; + } + + public String getMethod() { + return "{{httpMethod}}"; + } + + public String getPath() { + return "{{path}}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + + SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); + SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport.soapAction("{{operationId}}"); + + String payload = null; + String payloadType = null; + + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + if (!CollectionUtils.isEmpty(soapHeaders)) { + for (Entry entry : soapHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), + entry.getValue()); + } + } + + if (!CollectionUtils.isEmpty(mimeHeaders)) { + for (Entry entry : mimeHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), + entry.getValue()); + } + } + + Map queryParams = new HashMap<>(); + {{#allParams}}{{#isQueryParam}} + if (StringUtils.isNotBlank(this.{{paramName}})) { + queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); + sendSoapMessageActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); + } + {{/isQueryParam}}{{/allParams}} + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); + + soapSendMessageActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); + } + + {{#allParams}}{{#isQueryParam}} + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/isQueryParam}}{{/allParams}} + } + {{/operation}} + {{/operations}} +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_test.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_test.mustache new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_test.mustache @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache new file mode 100644 index 0000000000..d4b8dd2e01 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -0,0 +1,38 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{invokerPackage}}.spring; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +{{#apiInfo}} +{{#apis}} +import {{package}}.{{classname}}; +{{/apis}} +{{/apiInfo}} +import javax.annotation.processing.Generated; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class {{prefix}}BeanConfiguration { +{{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + + @Bean + @Scope(SCOPE_PROTOTYPE) + public {{classname}}.{{operationIdCamelCase}}Request {{operationId}}Request() { + return new {{classname}}.{{operationIdCamelCase}}Request(); + } + {{/operation}} + {{/operations}} + {{/apis}} +{{/apiInfo}} +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache new file mode 100644 index 0000000000..4e0957f1af --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache @@ -0,0 +1,215 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{invokerPackage}}.citrus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.processing.Generated; + +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.Conventions; +import org.springframework.util.Assert; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class {{prefix}}BeanDefinitionParser implements BeanDefinitionParser { + + private static final String COOKIE = "cookie"; + private static final String HEADER = "header"; + private static final String SOAP_HEADER = "soapHeader"; + private static final String MIME_HEADER = "mimeHeader"; + private static final String NAME = "name"; + private static final String REQUEST_BODY = "body"; + private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; + private static final String MULTIPART_BODY = "multipartBody"; + private static final String RESPONSE = "response"; + private static final String RESPONSE_JSONPATH = "json-path"; + private static final String RESPONSE_XPATH = "xpath"; + private static final String EXPRESSION = "expression"; + private static final String VALUE = "value"; + private static final String RESPONSE_RESOURCE = "resource"; + private static final String FILE = "file"; + private static final String RESPONSE_VARIABLE = "responseVariable"; + private static final String RESPONSE_VALUE = "responseValue"; + private static final String SCRIPT = "script"; + private static final String TYPE = "type"; + private static final String SQL = "sql"; + private static final String COLUMN = "column"; + private static final String VARIABLE = "variable"; + // new + private static final String SCHEMA = "schema"; + // new + private static final String SCHEMA_VALIDATION = "schemaValidation"; + + private final Class beanClass; + + public {{prefix}}BeanDefinitionParser(Class beanClass) { + this.beanClass = beanClass; + } + + public BeanDefinition parse(Element element) { + return parse(element, null); + } + + /** + * Note: The {@link {{prefix}}BeanDefinitionParser#parse(Element element)} allows access direct + * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. + */ + @Override + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); + retrieveRootNodeAttributes(element, builder); + retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); + retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); + retrieveOptionalNodeAttributes(element, RESPONSE, builder); + retrieveParamNodeData(element, builder, COOKIE); + retrieveParamNodeData(element, builder, HEADER); + retrieveParamNodeData(element, builder, SOAP_HEADER); + retrieveParamNodeData(element, builder, MIME_HEADER); + retrieveOptionalNodeAttributes(element, SCHEMA, builder); + retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); + retrieveOptionalMultipartElements(element, builder); + retrieveResponseNodeData(element, builder); + builder.addPropertyValue("name", element.getTagName()); + return builder.getBeanDefinition(); + } + + private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { + var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); + if (multipartBodyElement != null) { + var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); + for(int i = 0; i < multipartBodyChildElements.size(); i++){ + var multipartBodyChildElement = multipartBodyChildElements.get(i); + String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); + builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); + } + } + } + + private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { + NamedNodeMap attributes = element.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + builder.addPropertyValue(propertyName, attribute.getValue()); + } + } + + private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + } + } + + private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el1.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); + String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + builder.addPropertyValue(elementName, el.getTextContent()); + } + } + + private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { + if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { + Map params = new HashMap<>(); + List elements = DomUtils.getChildElementsByTagName(element, paramType); + elements.forEach(e -> { + String name = e.getAttribute(NAME); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + params.put(name, value); + }); + builder.addPropertyValue(paramType, params); + } + } + + private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { + + if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { + Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); + List elements = DomUtils.getChildElements(response); + + Map responseVariable = new HashMap<>(); + Map responseValue = new HashMap<>(); + + for (int i = 0; i < elements.size(); i++) { + Element e = elements.get(i); + + if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { + String expression = e.getAttribute(EXPRESSION); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + // variable to save @variable('ebid')@ else value to validate + if (value.matches("\\@variable\\('.*'\\)\\@")) { + Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); + if (match.find()) { + responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); + } + } else { + responseValue.put(expression, value); + } + } else if (e.getTagName().contains(SCRIPT)) { + String script = e.getTextContent(); + Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); + builder.addPropertyValue(SCRIPT, script); + + if (!e.getAttribute(TYPE).isEmpty()) { + String type = e.getAttribute(TYPE); + Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); + builder.addPropertyValue(TYPE, type); + } + } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { + String filePath = e.getAttribute(FILE); + Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); + builder.addPropertyValue(RESPONSE_RESOURCE, filePath); + } + + } + + builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); + builder.addPropertyValue(RESPONSE_VALUE, responseValue); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache new file mode 100644 index 0000000000..f8737ed4d9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache @@ -0,0 +1 @@ +# not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache new file mode 100644 index 0000000000..ad260e35ba --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -0,0 +1,36 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{invokerPackage}}.citrus.extension; + +{{#apiInfo}} +{{#apis}} +import {{package}}.{{classname}}; +{{/apis}} +{{/apiInfo}} +import {{invokerPackage}}.citrus.{{prefix}}BeanDefinitionParser; + +import javax.annotation.processing.Generated; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class {{prefix}}NamespaceHandler extends NamespaceHandlerSupport { + + @Override + public void init() { + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + registerBeanDefinitionParser("{{operationId}}Request", new {{prefix}}BeanDefinitionParser({{classname}}.{{operationIdCamelCase}}Request.class)); + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache new file mode 100644 index 0000000000..faf2807dd1 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + + {{#isMultipart}} + + + {{#formParams}} + + + + {{^required}}Optional {{/required}}{{#required}}Required{{/required}} - must either be set as attribute or element: {{#description}} +

    {{description}}

    {{/description}} + + + + {{/formParams}} + + + {{/isMultipart}} + + + + + {{operationId}} +

    {{httpMethod}} {{httpPathPrefix}}{{{path}}}

    +
      + {{#queryParams}} +
    • {{paramName}} {{description}}
    • + {{/queryParams}} + {{#pathParams}} +
    • {{baseName}} {{description}}
    • + {{/pathParams}} + {{#bodyParams}} +
    • Body: {{description}}
    • + {{/bodyParams}} + {{#authMethods}}{{#isBasic}} +
    • basicUsername http basic authentication username
    • +
    • basicPassword http basic authentication password
    • + {{/isBasic}}{{/authMethods}} + {{#isMultipart}} + {{#formParams}} +
    • {{paramName}} {{description}}
    • + {{/formParams}} + {{/isMultipart}} +
    +
    +
    + + + + {{#isMultipart}} + + {{/isMultipart}} + {{^isMultipart}} + {{#bodyParams}} + + + + {{^required}}Optional {{/required}}Body - {{summary}}{{#description}} +

    {{description}}

    {{/description}} +
    +
    +
    + {{/bodyParams}} + {{/isMultipart}} + +
    + {{#queryParams}} + + + {{description}} + + + {{/queryParams}} + {{#pathParams}} + + + {{description}} + + + {{/pathParams}} + {{#isMultipart}} + {{#formParams}} + + + + The filename of the {{paramName}} to upload + + + {{/formParams}} + {{/isMultipart}} + {{#authMethods}}{{#isBasic}} + + + http basic authentication username + + + + + http basic authentication password + + + {{/isBasic}}{{/authMethods}} +
    +
    +
    + {{/operation}} + {{/operations}} + {{/apis}} + {{#apis}} + {{#operations}} + {{#operation}} + + + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache new file mode 100644 index 0000000000..877bdc1884 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + + + + {{operationId}} +

    {{{path}}}

    +
    • + Body: {{description}}
    • +
    +
    +
    + + + + + + + {{^required}}SOAP {{/required}}Body{{summary}}{{#description}} +

    {{description}}

    {{/description}} +
    +
    +
    + +
    +
    +
    +
    + + {{/operation}} + {{/operations}} + {{/apis}} + {{#apis}} + {{#operations}} + {{#operation}} + + + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} +
    diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache new file mode 100644 index 0000000000..f3566c6716 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache @@ -0,0 +1,245 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{invokerPackage}}.citrus; + + +import static org.springframework.util.CollectionUtils.isEmpty; + +import jakarta.annotation.Generated; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.Message; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.spi.Resources; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.json.JsonMessageValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); + + @Autowired + @Qualifier("{{apiEndpoint}}") + protected HttpClient httpClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected boolean schemaValidation; + protected String schema; + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + protected String responseAcceptType = "*/*"; + protected String responseType = "json"; + protected int responseStatus = 200; + protected String responseReasonPhrase = "OK"; + protected String responseVersion = "HTTP/1.1"; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value + protected Map cookies; + protected Map headers; + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + recieveResponse(context); + } + + /** + * This method receives the HTTP-Response. + * + * @deprecated use {@link {{prefix}}AbstractTestRequest#receiveResponse(TestContext)} instead. + */ + public ReceiveMessageAction recieveResponse(TestContext context) { + + HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); + HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport + .statusCode(responseStatus) + .reasonPhrase(responseReasonPhrase) + .version(responseVersion) + .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + messageBuilderSupport.type(responseType); + httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); + var responseAction = httpClientResponseActionBuilder.build(); + + responseAction.execute(context); + + return responseAction; + } + + public @Nullable Message receiveResponse(TestContext context) { + var responseAction = recieveResponse(context); + + var messageStore = context.getMessageStore(); + return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); + } + + public abstract void sendRequest(TestContext context); + + public void setSchemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setResponseAcceptType(String responseAcceptType) { + this.responseAcceptType = responseAcceptType; + } + + public void setCookie(Map cookies) { + this.cookies = cookies; + } + + public void setHeader(Map headers) { + this.headers = headers; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + public void setResponseStatus(int responseStatus) { + this.responseStatus = responseStatus; + } + + public void setResponseReasonPhrase(String responseReasonPhrase) { + this.responseReasonPhrase = responseReasonPhrase; + } + + public void setResponseVersion(String responseVersion) { + this.responseVersion = responseVersion; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, + TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + + httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, + httpClientRequestActionBuilder); + + httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); + + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); + } + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeByBeans( + GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, httpClientRequestActionBuilder); + } + } + return httpClientRequestActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache new file mode 100644 index 0000000000..051485041e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache @@ -0,0 +1,187 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package {{invokerPackage}}.citrus; + +import jakarta.annotation.Generated; +import java.util.List; +import java.util.ServiceLoader; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.spi.Resources; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction.SoapMessageBuilderSupport; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SoapActionBuilder; +import org.citrusframework.ws.client.WebServiceClient; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.util.CollectionUtils; + +import javax.sql.DataSource; +import java.util.Map; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); + + @Autowired + @Qualifier("{{apiEndpoint}}") + protected WebServiceClient wsClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'XPATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'XPATH' as key and the 'VALUE TO BE VALIDATED' as value + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + protected Map soapHeaders; + protected Map mimeHeaders; + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + receiveResponse(context); + } + + /** + * This method receives the HTTP-Response + */ + public void receiveResponse(TestContext context) { + + ReceiveSoapMessageAction.Builder soapReceiveMessageActionBuilder = new SoapActionBuilder().client(wsClient).receive(); + SoapMessageBuilderSupport messageBuilderSupport = soapReceiveMessageActionBuilder.getMessageBuilderSupport(); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!CollectionUtils.isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!CollectionUtils.isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + soapReceiveMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapReceiveMessageActionBuilder.build().execute(context); + } + + public abstract void sendRequest(TestContext context); + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + public void setSoapHeader(Map soapHeaders) { + this.soapHeaders = soapHeaders; + } + + public void setMimeHeader(Map mimeHeaders) { + this.mimeHeaders = mimeHeaders; + } + + protected SendSoapMessageAction.Builder customizeBuilder(GeneratedApi generatedApi, + TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + sendSoapMessageActionBuilder = customizeByBeans(generatedApi, context, sendSoapMessageActionBuilder); + + sendSoapMessageActionBuilder = customizeBySpi(generatedApi, context, sendSoapMessageActionBuilder); + + return sendSoapMessageActionBuilder; + } + + private SendSoapMessageAction.Builder customizeBySpi(GeneratedApi generatedApi, TestContext context, + SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + sendSoapMessageActionBuilder = service.build(generatedApi, this, context, sendSoapMessageActionBuilder); + } + + return sendSoapMessageActionBuilder; + } + + private SendSoapMessageAction.Builder customizeByBeans( + GeneratedApi generatedApi, TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + sendSoapMessageActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, sendSoapMessageActionBuilder); + } + } + + return sendSoapMessageActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java new file mode 100644 index 0000000000..0240db1100 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java @@ -0,0 +1,626 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.message.MessagePayloadUtils.normalizeWhitespace; +import static org.citrusframework.util.FileUtils.readToString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.networknt.schema.JsonSchema; +import com.networknt.schema.ValidationMessage; +import jakarta.servlet.http.Cookie; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Stream; +import org.assertj.core.api.InstanceOfAssertFactories; +import org.citrusframework.Citrus; +import org.citrusframework.CitrusInstanceManager; +import org.citrusframework.TestAction; +import org.citrusframework.TestCase; +import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; +import org.citrusframework.common.SpringXmlTestLoader; +import org.citrusframework.common.TestLoader; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.context.TestContext; +import org.citrusframework.endpoint.EndpointConfiguration; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.json.schema.SimpleJsonSchema; +import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; +import org.citrusframework.message.DefaultMessage; +import org.citrusframework.message.Message; +import org.citrusframework.messaging.Producer; +import org.citrusframework.messaging.SelectiveConsumer; +import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi.PostFileRequest; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.AddPetRequest; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; +import org.citrusframework.spi.Resources; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.parallel.Isolated; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatcher; +import org.mockito.ArgumentMatchers; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.core.io.Resource; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.TestPropertySource; +import org.springframework.util.MultiValueMap; + +/** + * This test tests the generated API + */ +@Isolated +@DirtiesContext +@ExtendWith({CitrusSpringExtension.class}) +@SpringBootTest(classes = {CitrusSpringConfig.class, GeneratedApiIT.Config.class}) +@TestPropertySource( + properties = {"applicationServiceClient.basic.username=Max Mustermann", + "applicationServiceClient.basic.password=Top secret"} +) +class GeneratedApiIT { + + @Autowired + private ApplicationContext applicationContext; + + @Autowired + private HttpClient httpClientMock; + + @Mock + private Producer producerMock; + + @Mock + private SelectiveConsumer consumerMock; + + private TestContext testContext; + + @BeforeEach + void beforeEach() { + testContext = applicationContext.getBean(TestContext.class); + } + + @Test + void testValidationFailure() { + mockProducerAndConsumer(createReceiveMessage("{\"some\": \"payload\"}")); + assertThatThrownBy( + () -> executeTest("getPetByIdRequestTest", testContext)).hasCauseExactlyInstanceOf( + ValidationException.class); + } + + @Nested + class WithValidationMatcher { + + @BeforeEach + void beforeEach() { + mockProducerAndConsumer(createReceiveMessage("")); + } + + @Test + void testSendWithBody() { + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + try { + assertThat(httpMessage.getPayload()) + .isEqualTo( + readToString(Resources.create( + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json"), + StandardCharsets.UTF_8) + ); + } catch (IOException e) { + throw new CitrusRuntimeException("Unable to parse file!", e); + } + return true; + }; + + sendAndValidateMessage("sendWithBodyTest", messageMatcher); + } + + @Test + void testSendWithBodyLiteralWithVariable() { + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(((String) httpMessage.getPayload()).trim()).isEqualTo("{\"id\": 15}"); + return true; + }; + sendAndValidateMessage("sendWithBodyLiteralWithVariableTest", messageMatcher); + } + + @Test + void testXCitrusApiHeaders() { + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(httpMessage.getHeader("x-citrus-api-name")).isEqualTo("petstore"); + assertThat(httpMessage.getHeader("x-citrus-app")).isEqualTo("PETS"); + assertThat(httpMessage.getHeader("x-citrus-api-version")).isEqualTo("1.0.0"); + return true; + }; + + sendAndValidateMessage("sendWithBodyLiteralTest", messageMatcher); + } + + @Test + void testSendWithExtraHeaders() { + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(httpMessage.getHeader("h1")).isEqualTo("v1"); + assertThat(httpMessage.getHeader("h2")).isEqualTo("v2"); + return true; + }; + + sendAndValidateMessage("sendWithExtraHeaderTest", messageMatcher); + } + + @Test + void testSendWithBodyLiteral() { + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(((String) httpMessage.getPayload()).trim()).isEqualTo("{\"id\": 13}"); + return true; + }; + + sendAndValidateMessage("sendWithBodyLiteralTest", messageMatcher); + } + + private void sendAndValidateMessage(String testName, + ArgumentMatcher messageMatcher) { + GeneratedApiIT.this.sendAndValidateMessage(testName, messageMatcher, + AddPetRequest.class); + } + + } + + @Nested + class WithMultipartMessage { + + @Test + void testSendMultipartFile() { + mockProducerAndConsumer(createReceiveMessage("")); + + ArgumentMatcher messageMatcher = message -> { + assertThat(message.getPayload()).isInstanceOf(MultiValueMap.class); + MultiValueMap multiValueMap = (MultiValueMap) message.getPayload(); + List multipartFile = multiValueMap.get("multipartFile"); + try { + assertThat(((Resource) multipartFile.get(0)).getURL().toString()) + .endsWith( + "test-classes/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"); + } catch (IOException e) { + throw new CitrusRuntimeException("Unable to parse file!", e); + } + + return true; + }; + + sendAndValidateMessage("postFileTest", messageMatcher, PostFileRequest.class); + } + + @Test + void testSendMultipartWithFileAttribute() { + Message payload = createReceiveMessage("{\"id\": 1}"); + mockProducerAndConsumer(payload); + + executeTest("multipartWithFileAttributesTest", testContext); + ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); + verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); + Object producedMessagePayload = messageArgumentCaptor.getValue().getPayload(); + assertThat(producedMessagePayload).isInstanceOf(MultiValueMap.class); + + Object templateValue = ((MultiValueMap) producedMessagePayload).get("template"); + assertThat(templateValue) + .asInstanceOf(InstanceOfAssertFactories.LIST) + .element(0) + .hasFieldOrPropertyWithValue("path", + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml"); + + Object additionalDataValue = ((MultiValueMap) producedMessagePayload).get( + "additionalData"); + assertThat(additionalDataValue) + .asInstanceOf(InstanceOfAssertFactories.LIST) + .element(0) + .hasFieldOrPropertyWithValue("path", + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json"); + + Object schemaValue = ((MultiValueMap) producedMessagePayload).get("_schema"); + assertThat(schemaValue) + .asInstanceOf(InstanceOfAssertFactories.LIST) + .element(0) + .hasFieldOrPropertyWithValue("path", + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json"); + } + + @Test + void testSendMultipartWithPlainText() { + mockProducerAndConsumer(createReceiveMessage("{\"id\": 1}")); + executeTest("multipartWithPlainTextTest", testContext); + ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); + verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); + String producedMessagePayload = normalizeWhitespace( + messageArgumentCaptor.getValue().getPayload().toString(), + true, + true + ); + + String expectedPayload = + "{template=[ ], additionalData=[ {\"data1\":\"value1\"} ], _schema=[ {\"schema\":\"mySchema\"} ]}"; + assertThat(producedMessagePayload).isEqualTo(expectedPayload); + } + + @Test + void testSendMultipartWithMultipleDatatypes() { + Message receiveMessage = createReceiveMessage("{\"id\": 1}"); + mockProducerAndConsumer(receiveMessage); + + executeTest("multipartWithMultipleDatatypesTest", testContext); + ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); + verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); + String producedMessagePayload = normalizeWhitespace( + messageArgumentCaptor.getValue().getPayload().toString(), + true, + true + ); + + String expectedPayload = "{stringData=[Test], booleanData=[true], integerData=[1]}"; + assertThat(producedMessagePayload).isEqualTo(expectedPayload); + } + } + + @Nested + class WithDefaultReceiveMessage { + + private Message defaultRecieveMessage; + + @BeforeEach + void beforeEach() throws IOException { + defaultRecieveMessage = createReceiveMessage( + readToString(Resources.create( + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), + StandardCharsets.UTF_8) + ); + mockProducerAndConsumer(defaultRecieveMessage); + } + + @Test + void testJsonPathExtraction() { + TestCase testCase = executeTest("jsonPathExtractionTest", testContext); + TestAction testAction = testCase.getActions().get(0); + assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); + + assertThat(testContext.getVariable("name")).isEqualTo("Snoopy"); + assertThat(testContext.getVariable("id")).isEqualTo("12"); + } + + @Test + void testCustomizer() { + TestCase testCase = executeTest("getPetByIdRequestTest", testContext); + + TestAction testAction = testCase.getActions().get(0); + assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); + + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(httpMessage.getHeader("x-citrus-api-version")).isEqualTo( + "1.0.0"); + + return true; + }; + verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); + verify(consumerMock).receive(testContext, 5000L); + } + + @Test + void testBasicAuthorization() { + TestCase testCase = executeTest("getPetByIdRequestTest", testContext); + + TestAction testAction = testCase.getActions().get(0); + assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); + + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(httpMessage.getHeader("Authorization")).isEqualTo( + "Basic YWRtaW46dG9wLXNlY3JldA=="); + return true; + }; + verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); + verify(consumerMock).receive(testContext, 5000L); + } + + @Test + void testRequestPath() { + TestCase testCase = executeTest("getPetByIdRequestTest", testContext); + TestAction testAction = testCase.getActions().get(0); + assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); + + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + assertThat(httpMessage.getHeader("citrus_request_path")).isEqualTo("/pet/1234"); + return true; + }; + verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); + verify(consumerMock).receive(testContext, 5000L); + } + + @Test + void testCookies() { + TestCase testCase = executeTest("getPetByIdRequestTest", testContext); + TestAction testAction = testCase.getActions().get(0); + assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); + + ArgumentMatcher messageMatcher = message -> { + HttpMessage httpMessage = (HttpMessage) message; + Cookie cookie1 = httpMessage.getCookies().get(0); + Cookie cookie2 = httpMessage.getCookies().get(1); + assertThat(cookie1.getName()).isEqualTo("c1"); + assertThat(cookie1.getValue()).isEqualTo("v1"); + assertThat(cookie2.getName()).isEqualTo("c2"); + assertThat(cookie2.getValue()).isEqualTo("v2"); + return true; + }; + verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); + verify(consumerMock).receive(testContext, 5000L); + } + + @Test + void testJsonPathValidation() { + TestCase testCase = executeTest("jsonPathValidationTest", testContext); + assertTestActionType(testCase, GetPetByIdRequest.class); + } + + @Test + void scriptValidationFailureTest() { + TestCase testCase = executeTest("scriptValidationTest", testContext); + assertTestActionType(testCase, GetPetByIdRequest.class); + } + + @Test + void jsonSchemaValidationFailureTest() { + assertThatThrownBy(() -> executeTest("jsonSchemaValidationFailureTest", testContext)) + .hasCauseExactlyInstanceOf(ValidationException.class); + + SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( + "failingTestSchema"); + + // Assert that schema validation was called + verify(testSchema).getSchema(); + JsonSchema schema = testSchema.getSchema(); + verify(schema).validate(any()); + } + + @Test + void jsonDeactivatedSchemaValidationTest() { + SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( + "testSchema"); + Mockito.clearInvocations(testSchema, testSchema.getSchema()); + + TestCase testCase = executeTest("jsonDeactivatedSchemaValidationTest", testContext); + + assertTestActionType(testCase, GetPetByIdRequest.class); + + // Assert that schema validation was called + Mockito.verifyNoInteractions(testSchema); + } + + @Test + void defaultOas3SchemaValidationTest() { + SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean("oas3"); + Mockito.clearInvocations(testSchema, testSchema.getSchema()); + + TestCase testCase = executeTest("defaultOas3SchemaValidationTest", testContext); + + assertTestActionType(testCase, GetPetByIdRequest.class); + + // Assert that schema validation was called + verify(testSchema).getSchema(); + JsonSchema schema = testSchema.getSchema(); + verify(schema).validate(any()); + } + + @Test + void jsonSchemaValidationTest() { + SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( + "testSchema"); + Mockito.clearInvocations(testSchema, testSchema.getSchema()); + + TestCase testCase = executeTest("jsonSchemaValidationTest", testContext); + + assertTestActionType(testCase, GetPetByIdRequest.class); + + // Assert that schema validation was called + verify(testSchema).getSchema(); + JsonSchema schema = testSchema.getSchema(); + verify(schema).validate(any()); + } + + @Test + void testJsonPathValidationFailure() { + mockProducerAndConsumer(defaultRecieveMessage); + + assertThatThrownBy(() -> executeTest("jsonPathValidationFailureTest", testContext)) + .hasCauseExactlyInstanceOf(ValidationException.class); + } + + private static Stream testValidationFailures() { + return Stream.of( + Arguments.of("failOnStatusTest", + "Values not equal for header element 'citrus_http_status_code', expected '201' but was '200'"), + Arguments.of( + "failOnReasonPhraseTest", + "Values not equal for header element 'citrus_http_reason_phrase', expected 'Almost OK' but was 'OK'" + ), + Arguments.of( + "failOnVersionTest", + "Values not equal for header element 'citrus_http_version', expected 'HTTP/1.0' but was 'HTTP/1.1'" + ) + ); + } + + @ParameterizedTest + @MethodSource + void testValidationFailures(String testName, String expectedErrorMessage) { + assertThatThrownBy(() -> executeTest(testName, testContext)) + .hasCauseExactlyInstanceOf(ValidationException.class) + .message() + .startsWith(expectedErrorMessage); + } + } + +// @Test +// void testCoverageLogger() throws IOException { +// List logMessages = new ArrayList<>(); +// Logger logger = LoggerFactory.getLogger(GetPetByIdRequest.class); +// org.qos.logback.classic.Logger l = (org.qos.logback.classic.Logger) logger; +// l.setLevel(Level.TRACE); +// l.addAppender( +// new AppenderBase<>() { +// @Override +// protected void append(ILoggingEvent eventObject) {} +// +// @Override +// public synchronized void doAppend(ILoggingEvent eventObject) { +// logMessages.add(eventObject.getMessage()); +// super.doAppend(eventObject); +// } +// } +// ); +// +// +// +// mockProducer(httpClient); +// +// Message receiveMessage = createReceiveMessage( +// FileUtils.readToString(Resources.create("org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), StandardCharsets.UTF_8) +// ); +// +// mockConsumer(httpClient, testContext, receiveMessage); +// +// executeTest("getPetByIdRequestTest", testContext); +// +// assertThat(logMessages.get(0)).isEqualTo("getPetById;GET;\"{}\";\"\";\"\""); +// } + + /** + * Test the send message using the given matcher + */ + private void sendAndValidateMessage(String testName, ArgumentMatcher messageMatcher, + Class apiClass) { + + TestCase testCase = executeTest(testName, testContext); + assertTestActionType(testCase, apiClass); + + verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); + } + + /** + * Assert that an action of type 'apiClass' is contained in the list of test actions + */ + private void assertTestActionType(TestCase testCase, Class apiClass) { + TestAction testAction = testCase + .getActions() + .stream() + .filter(action -> apiClass.isAssignableFrom(action.getClass())) + .findAny() + .orElse(null); + assertThat(testAction).isNotNull(); + } + + private void mockProducerAndConsumer(Message receiveMessage) { + when(httpClientMock.createProducer()).thenReturn(producerMock); + when(httpClientMock.createConsumer()).thenReturn(consumerMock); + when(consumerMock.receive(testContext, 5000L)).thenReturn(receiveMessage); + } + + private TestCase executeTest(String testName, TestContext testContext) { + assertThat(CitrusInstanceManager.get()).isPresent(); + + Citrus citrus = CitrusInstanceManager.get().get(); + TestLoader loader = new SpringXmlTestLoader().citrusContext(citrus.getCitrusContext()) + .citrus(citrus) + .context(testContext); + loader.setTestName(testName); + loader.setPackageName("org.citrusframework.openapi.generator.GeneratedApiTest"); + loader.load(); + return loader.getTestCase(); + } + + private Message createReceiveMessage(String payload) { + Message receiveMessage = new DefaultMessage(); + receiveMessage.setPayload(payload); + receiveMessage.getHeaders().put("citrus_http_reason_phrase", "OK"); + receiveMessage.getHeaders().put("citrus_http_version", "HTTP/1.1"); + receiveMessage.getHeaders().put("citrus_http_status_code", 200); + return receiveMessage; + } + + public static class Config { + + @Bean(name = {"applicationServiceClient", "multipartTestEndpoint", + "soapSampleStoreEndpoint", "petStoreEndpoint"}) + public HttpClient applicationServiceClient() { + HttpClient clientMock = mock(); + EndpointConfiguration endpointConfigurationMock = mock(); + when(clientMock.getEndpointConfiguration()).thenReturn(new HttpEndpointConfiguration()); + when(endpointConfigurationMock.getTimeout()).thenReturn(5000L); + return clientMock; + } + + @Bean + public ApiActionBuilderCustomizerService customizer() { + return new ApiActionBuilderCustomizerService() { + @Override + public > T build( + GeneratedApi generatedApi, TestAction action, TestContext context, T builder) { + builder.getMessageBuilderSupport() + .header("x-citrus-api-version", generatedApi.getApiVersion()); + return builder; + } + }; + } + + @Bean({"oas3", "testSchema"}) + public SimpleJsonSchema testSchema() { + JsonSchema schemaMock = mock(); + SimpleJsonSchema jsonSchemaMock = mock(); + + when(jsonSchemaMock.getSchema()).thenReturn(schemaMock); + + Set okReport = new HashSet<>(); + when(schemaMock.validate(any())).thenReturn(okReport); + return jsonSchemaMock; + } + + @Bean + public SimpleJsonSchema failingTestSchema() { + JsonSchema schemaMock = mock(); + SimpleJsonSchema jsonSchemaMock = mock(); + + when(jsonSchemaMock.getSchema()).thenReturn(schemaMock); + + Set nokReport = new HashSet<>(); + nokReport.add(new ValidationMessage.Builder().customMessage( + "This is a simulated validation error message").build()); + when(schemaMock.validate(any())).thenReturn(nokReport); + return jsonSchemaMock; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java new file mode 100644 index 0000000000..6421cee946 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java @@ -0,0 +1,254 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.container.Assert.Builder.assertException; +import static org.citrusframework.util.FileUtils.readToString; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; +import org.citrusframework.TestCaseRunner; +import org.citrusframework.annotations.CitrusResource; +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.context.TestContext; +import org.citrusframework.endpoint.EndpointConfiguration; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; +import org.citrusframework.message.DefaultMessage; +import org.citrusframework.message.Message; +import org.citrusframework.messaging.Producer; +import org.citrusframework.messaging.SelectiveConsumer; +import org.citrusframework.openapi.generator.GetPetByIdTest.Config; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; +import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; +import org.citrusframework.spi.Resources; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; + +@ExtendWith(CitrusSpringExtension.class) +@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class, Config.class}) +class GetPetByIdTest { + + @Autowired + private GetPetByIdRequest getPetByIdRequest; + + @Autowired + @Qualifier("petStoreEndpoint") + private HttpClient httpClient; + + private String defaultResponse; + + @BeforeEach + public void beforeTest() throws IOException { + defaultResponse = readToString(Resources.create( + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), + StandardCharsets.UTF_8) ; + + mockProducer(); + mockConsumer(); + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void testByJsonPath(@CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + + // Assert body by json path + getPetByIdRequest.setResponseValue(Map.of("$.name", "Snoopy")); + + // When + runner.$(getPetByIdRequest); + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void testValidationFailureByJsonPath(@CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + + // Assert body by json path + getPetByIdRequest.setResponseValue(Map.of("$.name", "Garfield")); + + // When + runner.$(assertException() + .exception(org.citrusframework.exceptions.CitrusRuntimeException.class) + .message("Values not equal for element '$.name', expected 'Garfield' but was 'Snoopy'") + .when( + getPetByIdRequest + ) + ); + // When + + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void testByResource(@CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + // Assert body by resource + getPetByIdRequest.setResource( + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"); + + // When + runner.$(getPetByIdRequest); + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void testValidationFailureByResource(@CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + // Assert body by resource + getPetByIdRequest.setResource( + "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json"); + + // When + runner.$(assertException() + .exception(org.citrusframework.exceptions.CitrusRuntimeException.class) + .message("Values not equal for entry: '$['name']', expected 'Garfield' but was 'Snoopy'") + .when( + getPetByIdRequest + ) + ); + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void validateByVariable(@CitrusResource TestContext testContext, + @CitrusResource TestCaseRunner runner) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // Then + getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); + getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + + // Assert load data into variables + getPetByIdRequest.setResponseVariable(Map.of("$", "RESPONSE", "$.id", "ID")); + + // When + runner.$(getPetByIdRequest); + + // Then + assertThat(testContext) + .satisfies( + c -> assertThat(c.getVariable("RESPONSE")) + .isNotNull(), + c -> assertThat(c.getVariable("ID")) + .isNotNull() + .isEqualTo("12") + ); + } + + /** + * TODO #1161 - Improve with builder pattern + */ + @Test + @CitrusTest + void validateReceivedResponse(@CitrusResource TestContext testContext) { + + // Given + getPetByIdRequest.setPetId("1234"); + + // When + getPetByIdRequest.sendRequest(testContext); + + // Then + Message receiveResponse = getPetByIdRequest.receiveResponse(testContext); + assertThat(receiveResponse) + .isNotNull() + .extracting(Message::getPayload) + .asString() + .isEqualToIgnoringWhitespace(defaultResponse); + assertThat(receiveResponse.getHeaders()) + .containsEntry("citrus_http_status_code", 200) + .containsEntry("citrus_http_reason_phrase", "OK"); + } + + private void mockProducer() { + Producer producerMock = mock(); + when(httpClient.createProducer()).thenReturn(producerMock); + } + + private void mockConsumer() { + Message receiveMessage = createReceiveMessage(); + + SelectiveConsumer consumer = mock(SelectiveConsumer.class); + when(httpClient.createConsumer()).thenReturn(consumer); + when(consumer.receive(any(), eq(5000L))).thenReturn(receiveMessage); + } + + private Message createReceiveMessage() { + Message receiveMessage = new DefaultMessage(); + receiveMessage.setPayload(defaultResponse); + receiveMessage.getHeaders().put("citrus_http_reason_phrase", "OK"); + receiveMessage.getHeaders().put("citrus_http_version", "HTTP/1.1"); + receiveMessage.getHeaders().put("Content-Type", 200); + receiveMessage.getHeaders().put("citrus_http_status_code", 200); + return receiveMessage; + } + + @TestConfiguration + public static class Config { + + @Bean(name = {"applicationServiceClient", "petStoreEndpoint"}) + public HttpClient applicationServiceClient() { + HttpClient client = mock(HttpClient.class); + EndpointConfiguration endpointConfiguration = mock(EndpointConfiguration.class); + when(client.getEndpointConfiguration()).thenReturn(new HttpEndpointConfiguration()); + when(endpointConfiguration.getTimeout()).thenReturn(5000L); + return client; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java new file mode 100644 index 0000000000..dd4f52ece7 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java @@ -0,0 +1,93 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.stream.Stream; +import org.apache.commons.lang3.stream.Streams; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +/** + * This test case is designed to validate the consistency of the code generation process and detect + * any discrepancies between the generated API files and the reference files stored in + * '/JavaCitrusCodegenIntegrationTest/expectedgen/'. It compares the results of API generation + * against the reference files, and a failure indicates potential changes in mustache templates or + * code generation logic. + *

    + * If this test fails, it is essential to review the code generation process and underlying + * templates carefully. If the changes are intentional and verified, update the reference files by + * copying the generated API sources to the '/JavaCitrusCodegenIntegrationTest/expectedgen/' + * directory. To ensure accurate copying, without unwanted code formatting, use a simple File + * Explorer instead of relying on IDE-based operations. + */ +class JavaCitrusCodegenIT { + + static Stream getResourcesForRest() throws IOException { + return geClassResourcesIgnoringInnerClasses("org/citrusframework/openapi/generator/rest"); + } + + @ParameterizedTest + @MethodSource("getResourcesForRest") + void testGeneratedFiles(Resource resource) throws IOException { + File classFile = resource.getFile(); + String absolutePath = classFile.getAbsolutePath(); + String javaFilePath = absolutePath.replace("test-classes", "generated-test-sources") + .replace(".class", ".java"); + + assertFileContent(new File(javaFilePath), "rest"); + } + + static Stream getResourcesForSoap() throws IOException { + return geClassResourcesIgnoringInnerClasses( + "org/citrusframework/openapi/generator/soap/bookservice"); + } + + @ParameterizedTest + @MethodSource("getResourcesForSoap") + void testGeneratedSoapFiles(Resource resource) throws IOException { + File classFile = resource.getFile(); + String absolutePath = classFile.getAbsolutePath(); + + String javaFilePath = absolutePath.replace("test-classes", "generated-test-sources") + .replace(".class", ".java"); + + assertFileContent(new File(javaFilePath), "soap"); + } + + private static Stream geClassResourcesIgnoringInnerClasses(String path) + throws IOException { + return Streams.of(new PathMatchingResourcePatternResolver().getResources( + path + "/**/*.class")).filter(resource -> { + try { + return !resource.getURI().toString().contains("$"); + } catch (Exception e) { + throw new CitrusRuntimeException("Unable to retrieve URL from resource!"); + } + }).map(Arguments::arguments); + } + + private void assertFileContent(File file, String apiDir) throws IOException { + assertThat(file).exists(); + String expectedFilePath = + "org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/" + + file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(apiDir)); + + ClassPathResource classPathResource = new ClassPathResource(expectedFilePath); + + /* + * NOTE: when changes have been performed to mustache templates, the expected files need to be updated. + * Be aware that file content may change according to IDE formatting rules if the files are copied via IDE. + * Files should therefore be copied using a file explorer which ensures that content of files does not change. + */ + assertThat(file).hasSameTextualContentAs(classPathResource.getFile()); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java new file mode 100644 index 0000000000..57f49cd861 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java @@ -0,0 +1,166 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.junit.jupiter.api.Test; +import org.openapitools.codegen.ClientOptInput; +import org.openapitools.codegen.CodegenConfigLoader; +import org.openapitools.codegen.DefaultGenerator; +import org.openapitools.codegen.config.CodegenConfigurator; + +/** + * This test validates the code generation process. + *

    + * It may also serve as an entry point for debugging the code generation process. When executed in debug mode, it allows you to + * step through the generation process and inspect the resulting output in the specified output directory. + *

    + * To debug the code generator: + *

      + *
    1. Set a breakpoint in the {@code postProcessOperationsWithModels()} method of {@code JavaCitrusCodegen.java}.
    2. + *
    3. In your IDE, launch this test by right-clicking and selecting Debug As > JUnit Test.
    4. + *
    + */ + +class JavaCitrusCodegenTest { + + @Test + void retrieveGeneratorBsSpi() { + JavaCitrusCodegen codegen = (JavaCitrusCodegen) CodegenConfigLoader.forName("java-citrus"); + assertThat(codegen).isNotNull(); + } + + @Test + void arePredefinedValuesNotEmptyTest() { + JavaCitrusCodegen codegen = new JavaCitrusCodegen(); + + assertThat(codegen.getName()).isEqualTo(CODEGEN_NAME); + assertThat(codegen.getHelp()).isNotEmpty(); + assertThat(codegen.getHttpClient()).isNotEmpty(); + assertThat(codegen.getOpenapiSchema()).isNotEmpty(); + assertThat(codegen.getApiPrefix()).isNotEmpty(); + assertThat(codegen.getHttpPathPrefix()).isNotEmpty(); + assertThat(codegen.getTargetXmlnsNamespace()).isNull(); + assertThat(codegen.getGeneratedSchemaFolder()).isNotEmpty(); + } + + @Test + void areAdditionalPropertiesProcessedTest() { + final String httpClient = "myTestEndpoint"; + final String openapiSchema = "testSchema"; + final String prefix = "testPrefix"; + final String httpPathPrefix = "test/path"; + final String targetXmlnsNamespace = "http://www.citrusframework.org/schema/test/extension"; + final String generatedSchemaFolder = "generatedResourceFolder"; + + Map properties = new HashMap<>(); + properties.put(JavaCitrusCodegen.API_ENDPOINT, httpClient); + properties.put(JavaCitrusCodegen.GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); + properties.put(JavaCitrusCodegen.HTTP_PATH_PREFIX, httpPathPrefix); + properties.put(JavaCitrusCodegen.OPENAPI_SCHEMA, openapiSchema); + properties.put(JavaCitrusCodegen.PREFIX, prefix); + properties.put(JavaCitrusCodegen.TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); + + JavaCitrusCodegen codegen = new JavaCitrusCodegen(); + codegen.additionalProperties().putAll(properties); + codegen.processOpts(); + + assertThat(codegen.getApiPrefix()).isEqualTo(prefix); + assertThat(codegen.getGeneratedSchemaFolder()).isEqualTo(generatedSchemaFolder); + assertThat(codegen.getHttpClient()).isEqualTo(httpClient); + assertThat(codegen.getHttpPathPrefix()).isEqualTo(httpPathPrefix); + assertThat(codegen.getOpenapiSchema()).isEqualTo(openapiSchema); + assertThat(codegen.getTargetXmlnsNamespace()).isEqualTo(targetXmlnsNamespace); + } + + @Test + void areReservedWordsEscapedTest() throws IOException { + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(CODEGEN_NAME) + .setInputSpec("src/test/resources/apis/petstore_reservedWords.yaml") + .setOutputDir("target/JavaCitrusCodegenTest/petstore_escapedWords"); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + List outputFiles = generator.opts(clientOptInput).generate(); + + Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + .findFirst(); + + assertThat(file).isPresent(); + + List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); + + // "name" is a reserved word, so it should be escaped with an underline for the second parameter + assertThat(lines.stream().filter(x -> x.contains("\"name\", this._name")).count()).isEqualTo(1L); + } + + @Test + void arePathParamsFieldsPresent() throws IOException { + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(CODEGEN_NAME) + .setInputSpec("src/test/resources/apis/petstore.yaml") + .setOutputDir("target/JavaCitrusCodegenTest/petstore"); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + List outputFiles = generator.opts(clientOptInput).generate(); + + Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + .findFirst(); + + assertThat(file).isPresent(); + + List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); + + // "name" is a reserved word, so it should be escaped with an underline for the second parameter + assertThat(lines.stream().filter(x -> x.contains("private String petId;")).count()).isEqualTo(4L); + assertThat(lines.stream().filter( + x -> x.contains("endpoint = endpoint.replace(\"{\" + \"petId\" + \"}\", petId);")) + .count()).isEqualTo(4L); + } + + @Test + void areBasicAuthFieldsPresent() throws IOException { + final CodegenConfigurator configurator = new CodegenConfigurator() + .setGeneratorName(CODEGEN_NAME) + .setInputSpec("src/test/resources/apis/petstore.yaml") + .setOutputDir("target/JavaCitrusCodegenTest/petstore"); + + final ClientOptInput clientOptInput = configurator.toClientOptInput(); + DefaultGenerator generator = new DefaultGenerator(); + List outputFiles = generator.opts(clientOptInput).generate(); + + Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + .findFirst(); + + assertThat(file).isPresent(); + + List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); + + // "name" is a reserved word, so it should be escaped with an underline for the second parameter + assertThat(lines.stream() + .filter(x -> x.contains("@Value(\"${\" + \"apiEndpoint.basic.username:#{null}}\")")) + .count()).isEqualTo(1L); + assertThat( + lines.stream().filter(x -> x.contains("private String basicUsername;")).count()).isEqualTo(1L); + assertThat( + lines + .stream() + .filter(x -> + x.contains( + "messageBuilderSupport.header(\"Authorization\", \"Basic \" + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+\":\"+context.replaceDynamicContentInString(basicPassword)).getBytes()));" + ) + ) + .count() + ).isEqualTo(1L); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java new file mode 100644 index 0000000000..6b17f01f13 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java @@ -0,0 +1,24 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.ServiceLoader; +import java.util.ServiceLoader.Provider; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.openapi.generator.util.TestApiActionBuilderCustomizer; +import org.junit.jupiter.api.Test; + +class ServiceLoaderTest { + + @Test + void test() { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + List> list = serviceLoader.stream().toList(); + assertThat(list).hasSize(1); + ApiActionBuilderCustomizerService apiActionBuilderCustomizerService = list.iterator().next() + .get(); + assertThat(apiActionBuilderCustomizerService).isInstanceOf(TestApiActionBuilderCustomizer.class); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java new file mode 100644 index 0000000000..1ae66986fd --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java @@ -0,0 +1,29 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.util.FileUtils.readToString; + +import java.io.IOException; +import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources.ClasspathResource; +import org.junit.jupiter.api.Test; +import org.springframework.core.io.ClassPathResource; + +class SimpleWsdlToOpenApiTransformerTest { + + @Test + void testTransform() throws WsdlToOpenApiTransformationException, IOException { + ClassPathResource wsdlResource = new ClassPathResource( + "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl"); + + SimpleWsdlToOpenApiTransformer simpleWsdlToOpenApiTransformer = new SimpleWsdlToOpenApiTransformer(wsdlResource.getURI()); + String generatedYaml = simpleWsdlToOpenApiTransformer.transformToOpenApi(); + + Resource expectedYamlResource = new ClasspathResource( + "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml"); + + String expectedYaml = readToString(expectedYamlResource); + assertThat(generatedYaml).isEqualToIgnoringWhitespace(expectedYaml); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java new file mode 100644 index 0000000000..2f5dbf7179 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java @@ -0,0 +1,55 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.citrusframework.annotations.CitrusResource; +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.junit.jupiter.spring.CitrusSpringSupport; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.AddPetRequest; +import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; +import org.junit.jupiter.api.Test; +import org.citrusframework.openapi.generator.SpringBeanConfigurationIT.ClientConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; + +@CitrusSpringSupport +@ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, PetStoreBeanConfiguration.class}) +class SpringBeanConfigurationIT { + + @Autowired + private ApplicationContext applicationContext; + + @Test + @CitrusTest + void fromReferenceResolverIsPrototypeScoped(@CitrusResource TestContext testContext) { + var addPetRequest = testContext.getReferenceResolver().resolve(AddPetRequest.class); + assertThat(addPetRequest) + .isNotNull() + .isNotEqualTo(testContext.getReferenceResolver().resolve(AddPetRequest.class)); + } + + @Test + void fromSpringApplicationContextIsPrototypeScoped() { + assertThat(applicationContext.getBean(AddPetRequest.class)) + .isNotNull() + .isNotEqualTo(applicationContext.getBean(AddPetRequest.class)); + } + + @TestConfiguration + public static class ClientConfiguration { + + @Bean(name= {"applicationServiceClient", "petStoreEndpoint"}) + public HttpClient applicationServiceClient() { + var config = new HttpEndpointConfiguration(); + config.setRequestUrl("http://localhost:9000"); + return new HttpClient(config); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java new file mode 100644 index 0000000000..0aaa9761ab --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java @@ -0,0 +1,22 @@ +package org.citrusframework.openapi.generator.util; + +import org.citrusframework.TestAction; +import org.citrusframework.TestActionBuilder; +import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; +import org.citrusframework.context.TestContext; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; + +public class TestApiActionBuilderCustomizer implements ApiActionBuilderCustomizerService { + + @Override + public > T build(GeneratedApi generatedApi, TestAction action, + TestContext context, T builder) { + + generatedApi.getApiInfoExtensions().forEach((key, value) -> { + builder.getMessageBuilderSupport().header(key, value); + }); + + return builder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService new file mode 100644 index 0000000000..ba96f521f6 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService @@ -0,0 +1 @@ +org.citrusframework.openapi.generator.util.TestApiActionBuilderCustomizer \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers new file mode 100644 index 0000000000..1f0c4bdb95 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers @@ -0,0 +1,3 @@ +http\://www.citrusframework.org/citrus-test-schema/multiparttest-api=org.citrusframework.openapi.generator.rest.multiparttest.citrus.extension.MultipartTestNamespaceHandler +http\://www.citrusframework.org/citrus-test-schema/openapifromwsdl-api=org.citrusframework.openapi.generator.soap.bookservice.citrus.extension.OpenApiFromWsdlNamespaceHandler +http\://www.citrusframework.org/citrus-test-schema/petstore-api=org.citrusframework.openapi.generator.rest.petstore.citrus.extension.PetStoreNamespaceHandler diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas new file mode 100644 index 0000000000..0050010472 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas @@ -0,0 +1,3 @@ +http\://www.citrusframework.org/citrus-test-schema/multiparttest-api/multiparttest-api.xsd=schema/xsd/multiparttest-api.xsd +http\://www.citrusframework.org/citrus-test-schema/openapifromwsdl-api/openapifromwsdl-api.xsd=schema/xsd/openapifromwsdl-api.xsd +http\://www.citrusframework.org/citrus-test-schema/petstore-api/petstore-api.xsd=schema/xsd/petstore-api.xsd diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml new file mode 100644 index 0000000000..b77b55c4d2 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml @@ -0,0 +1,249 @@ +openapi: 3.0.3 +info: + title: multiparttest API + version: 2.0.0 + description: | + The service to test mutlipart + x-citrus-app: MPT + x-citrus-api-name: multiparttest-rest-resource + contact: + name: IT-Services-CI TAuBE + email: IT-Serv-CI-ETAdl@post.ch + url: https://confluence.pnet.ch/pages/viewpage.action?pageId=314828825 +tags: + - name: multiparttest-controller +paths: + /api/v2/multitest-file/{bucket}/{filename}/random: + post: + tags: + - multiparttest-controller + operationId: postRandom + summary: Uploads random file. + parameters: + - name: bucket + description: The name of an existing s3 bucket. + in: path + required: true + schema: + type: string + - name: filename + description: The name under which to store the random file. + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PutObjectResult' + 500: + description: Internal Server Error + /api/v2/multitest-file/{bucket}/{filename}: + post: + tags: + - multiparttest-controller + operationId: postFile + summary: Uploads file. + parameters: + - name: bucket + description: The name of an existing s3 bucket. + in: path + required: true + schema: + type: string + - name: filename + description: The name of the file which should be uploaded. It may override any existing file with the same name. + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + multipartFile: + type: string + format: binary + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PutObjectResult' + 500: + description: Internal Server Error + delete: + tags: + - multiparttest-controller + operationId: deleteObject + summary: Delete file. + parameters: + - name: bucket + in: path + required: true + schema: + type: string + description: The name of an existing s3 bucket. + - name: filename + in: path + required: true + schema: + type: string + description: The name of the file which should be deleted. + responses: + 200: + description: OK + content: + application/json: + schema: + type: boolean + 500: + description: Internal Server Error + /api/v2/multitest-reportgeneration: + post: + tags: + - multiparttest-controller + operationId: generateReport + summary: summary + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: ['template'] + properties: + template: + description: | + Content of the template. + type: string + additionalData: + $ref: '#/components/schemas/AdditionalData' + schema: + description: | + An optional JSON schema to validate the created report against. + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PutObjectResult' + 500: + description: Internal Server Error + /api/v2/multitest-multipledatatypes: + post: + tags: + - multiparttest-controller + operationId: multipleDatatypes + summary: summary + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + stringData: + type: string + booleanData: + type: boolean + integerData: + type: integer + + responses: + 200: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/PutObjectResult' + 500: + description: Internal Server Error + /api/v2/multitest-file/{bucket}/{filename}/exists: + get: + tags: + - multiparttest-controller + operationId: fileExists + summary: Checks if file exist. + parameters: + - name: bucket + description: The name of an existing s3 bucket. + in: path + required: true + schema: + type: string + - name: filename + description: The name of the file on which the status should be checked. + in: path + required: true + schema: + type: string + responses: + 200: + description: OK + content: + application/json: + schema: + type: boolean + 500: + description: Internal Server Error +components: + schemas: + Metadata: + type: object + properties: + userMetadata: + type: object + additionalProperties: + type: string + rawMetadata: + type: object + additionalProperties: + type: string + httpExpiresDate: + type: string + format: date-time + expirationTime: + type: string + format: date-time + expirationTimeRuleId: + type: string + ongoingRestore: + type: boolean + restoreExpirationTime: + type: string + format: date-time + bucketKeyEnabled: + type: boolean + PutObjectResult: + type: object + properties: + versionId: + type: string + eTag: + type: string + expirationTime: + type: string + format: date-time + expirationTimeRuleId: + type: string + contentMd5: + type: string + metadata: + $ref: '#/components/schemas/Metadata' + isRequesterCharged: + type: boolean + AdditionalData: + description: | + Additional data provided to the report. For each dataset requested, provide a json + object with the name of the dataset. + type: string diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml new file mode 100644 index 0000000000..79249f26ed --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml @@ -0,0 +1,700 @@ +swagger: '2.0' +info: + description: 'This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.' + version: 1.0.0 + x-citrus-app: PETS + x-citrus-api-name: petstore + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +host: petstore.swagger.io +basePath: /v2 +tags: + - name: pet + description: Everything about your Pets + - name: store + description: Access to Petstore orders + - name: user + description: Operations about user +schemes: + - http +paths: + /pet: + post: + tags: + - pet + summary: Add a new pet to the store + description: '' + operationId: addPet + consumes: + - application/json + - application/xml + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Pet object that needs to be added to the store + required: true + schema: + $ref: '#/definitions/Pet' + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + put: + tags: + - pet + summary: Update an existing pet + description: '' + operationId: updatePet + consumes: + - application/json + - application/xml + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Pet object that needs to be added to the store + required: true + schema: + $ref: '#/definitions/Pet' + responses: + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + produces: + - application/xml + - application/json + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: true + type: array + items: + type: string + enum: + - available + - pending + - sold + default: available + collectionFormat: csv + responses: + '200': + description: successful operation + schema: + type: array + items: + $ref: '#/definitions/Pet' + '400': + description: Invalid status value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.' + operationId: findPetsByTags + produces: + - application/xml + - application/json + parameters: + - name: tags + in: query + description: Tags to filter by + required: true + type: array + items: + type: string + collectionFormat: csv + responses: + '200': + description: successful operation + schema: + type: array + items: + $ref: '#/definitions/Pet' + '400': + description: Invalid tag value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + deprecated: true + '/pet/{petId}': + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + type: integer + format: int64 + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + security: + - api_key: [] + - basicAuth: [] + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: '' + operationId: updatePetWithForm + consumes: + - application/x-www-form-urlencoded + produces: + - application/xml + - application/json + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + type: integer + format: int64 + - name: name + in: formData + description: Updated name of the pet + required: false + type: string + - name: status + in: formData + description: Updated status of the pet + required: false + type: string + responses: + '405': + description: Invalid input + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + delete: + tags: + - pet + summary: Deletes a pet + description: '' + operationId: deletePet + produces: + - application/xml + - application/json + parameters: + - name: api_key + in: header + required: false + type: string + - name: petId + in: path + description: Pet id to delete + required: true + type: integer + format: int64 + responses: + '400': + description: Invalid pet value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + '/pet/{petId}/uploadImage': + post: + tags: + - pet + summary: uploads an image + description: '' + operationId: uploadFile + consumes: + - multipart/form-data + produces: + - application/json + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + type: integer + format: int64 + - name: additionalMetadata + in: formData + description: Additional data to pass to server + required: false + type: string + - name: file + in: formData + description: file to upload + required: false + type: file + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/ApiResponse' + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + produces: + - application/json + parameters: [] + responses: + '200': + description: successful operation + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: '' + operationId: placeOrder + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: order placed for purchasing the pet + required: true + schema: + $ref: '#/definitions/Order' + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Order' + '400': + description: Invalid Order + '/store/order/{order_id}': + get: + tags: + - store + summary: Find purchase order by ID + description: 'For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions' + operationId: getOrderById + produces: + - application/xml + - application/json + parameters: + - name: order_id + in: path + description: ID of pet that needs to be fetched + required: true + type: integer + maximum: 5 + minimum: 1 + format: int64 + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Order' + '400': + description: Invalid ID supplied + '404': + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors + operationId: deleteOrder + produces: + - application/xml + - application/json + parameters: + - name: order_id + in: path + description: ID of the order that needs to be deleted + required: true + type: string + responses: + '400': + description: Invalid ID supplied + '404': + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: Created user object + required: true + schema: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithArray: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithArrayInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: '' + operationId: createUsersWithListInput + produces: + - application/xml + - application/json + parameters: + - in: body + name: body + description: List of user object + required: true + schema: + type: array + items: + $ref: '#/definitions/User' + responses: + default: + description: successful operation + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: '' + operationId: loginUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: query + description: The user name for login + required: true + type: string + - name: password + in: query + description: The password for login in clear text + required: true + type: string + responses: + '200': + description: successful operation + schema: + type: string + headers: + X-Rate-Limit: + type: integer + format: int32 + description: calls per hour allowed by the user + X-Expires-After: + type: string + format: date-time + description: date in UTC when toekn expires + '400': + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: '' + operationId: logoutUser + produces: + - application/xml + - application/json + parameters: [] + responses: + default: + description: successful operation + '/user/{username}': + get: + tags: + - user + summary: Get user by user name + description: '' + operationId: getUserByName + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: 'The name that needs to be fetched. Use user1 for testing.' + required: true + type: string + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/User' + '400': + description: Invalid username supplied + '404': + description: User not found + put: + tags: + - user + summary: Updated user + description: This can only be done by the logged in user. + operationId: updateUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: name that need to be deleted + required: true + type: string + - in: body + name: body + description: Updated user object + required: true + schema: + $ref: '#/definitions/User' + responses: + '400': + description: Invalid user supplied + '404': + description: User not found + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + produces: + - application/xml + - application/json + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + type: string + responses: + '400': + description: Invalid username supplied + '404': + description: User not found +securityDefinitions: + petstore_auth: + type: oauth2 + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + flow: implicit + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header + basicAuth: + type: basic +definitions: + Order: + title: Pet Order + description: An order for a pets from the pet store + type: object + properties: + id: + type: integer + format: int64 + petId: + type: integer + format: int64 + quantity: + type: integer + format: int32 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + enum: + - placed + - approved + - delivered + complete: + type: boolean + default: false + xml: + name: Order + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Category + User: + title: a User + description: A User who is purchasing from the pet store + type: object + properties: + id: + type: integer + format: int64 + username: + type: string + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + phone: + type: string + userStatus: + type: integer + format: int32 + description: User Status + xml: + name: User + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/definitions/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/definitions/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet + ApiResponse: + title: An uploaded response + description: Describes the result of uploading an image resource + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml new file mode 100644 index 0000000000..7175b75f0e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml @@ -0,0 +1,120 @@ +swagger: '2.0' +info: + description: 'This is a modified Petstore server, that uses the reserved word "name" as parameter name. This should be renamed to "_name" in the generated code.' + version: 1.0.0 + title: OpenAPI Petstore + license: + name: Apache-2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0.html' +host: petstore.swagger.io +basePath: /v2 +tags: + - name: pet + description: Everything about your Pets +schemes: + - http +paths: + /pet/findByName: + get: + tags: + - pet + summary: Finds Pet by name + description: Name can be any text + operationId: findPetByName + produces: + - application/xml + - application/json + parameters: + # name is a reserved word and should be masked with an '_' in the generated api + - name: name + in: query + description: Name of the pet + required: true + type: string + responses: + '200': + description: successful operation + schema: + $ref: '#/definitions/Pet' + '400': + description: Invalid name value + security: + - petstore_auth: + - 'write:pets' + - 'read:pets' +securityDefinitions: + petstore_auth: + type: oauth2 + authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' + flow: implicit + scopes: + 'write:pets': modify pets in your account + 'read:pets': read your pets + api_key: + type: apiKey + name: api_key + in: header +definitions: + Category: + title: Pet category + description: A category for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Category + Tag: + title: Pet Tag + description: A tag for a pet + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: Tag + Pet: + title: a Pet + description: A pet for sale in the pet store + type: object + required: + - name + - photoUrls + properties: + id: + type: integer + format: int64 + category: + $ref: '#/definitions/Category' + name: + type: string + example: doggie + photoUrls: + type: array + xml: + name: photoUrl + wrapped: true + items: + type: string + tags: + type: array + xml: + name: tag + wrapped: true + items: + $ref: '#/definitions/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: Pet diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/citrus-context.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/citrus-context.xml new file mode 100644 index 0000000000..3f2a783fca --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/citrus-context.xml @@ -0,0 +1,7 @@ + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml new file mode 100644 index 0000000000..1784d89782 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml new file mode 100644 index 0000000000..60f8dc25d0 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml new file mode 100644 index 0000000000..ca47b78103 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml new file mode 100644 index 0000000000..5047fc38a0 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml new file mode 100644 index 0000000000..c6f1afc8b5 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml new file mode 100644 index 0000000000..7f4b46ed43 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml new file mode 100644 index 0000000000..efb6b3e5a8 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml new file mode 100644 index 0000000000..2ead5c459b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml new file mode 100644 index 0000000000..4d4bff102f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml new file mode 100644 index 0000000000..320e32fcd9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml new file mode 100644 index 0000000000..3aeb456f25 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml new file mode 100644 index 0000000000..50f146bc18 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml new file mode 100644 index 0000000000..4e24ad3e06 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml new file mode 100644 index 0000000000..a727b3bd06 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml @@ -0,0 +1,24 @@ + + + + + + Test + true + 1 + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml new file mode 100644 index 0000000000..a3082ee857 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml @@ -0,0 +1,32 @@ + + + + + + + + ]]> + + + {"data1":"value1"} + + + {"schema":"mySchema"} + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json new file mode 100644 index 0000000000..a921a4b0c2 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json @@ -0,0 +1,6 @@ +{ + "Konto": { + "iban": "DE43100500000920018963", + "amount": 1234 + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml new file mode 100644 index 0000000000..a3dd52a043 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml @@ -0,0 +1,4 @@ + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json @@ -0,0 +1 @@ +{} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json new file mode 100644 index 0000000000..b68ed32a5e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json @@ -0,0 +1,6 @@ +{ + "id": 12, + "name": "Snoopy", + "tags": ["comic dog"], + "photoUrls": ["url1", "url2"] +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json new file mode 100644 index 0000000000..b68ed32a5e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json @@ -0,0 +1,6 @@ +{ + "id": 12, + "name": "Snoopy", + "tags": ["comic dog"], + "photoUrls": ["url1", "url2"] +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json new file mode 100644 index 0000000000..267e7887a0 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json @@ -0,0 +1,6 @@ +{ + "id": 12, + "name": "Garfield", + "tags": ["comic cat"], + "photoUrls": ["url1", "url2"] +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml new file mode 100644 index 0000000000..a04b808966 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml new file mode 100644 index 0000000000..39efdef351 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml @@ -0,0 +1,25 @@ + + + + + + + assert json.id == 12 + assert json.name == 'Snoopy' + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml new file mode 100644 index 0000000000..3daad673c3 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml @@ -0,0 +1,20 @@ + + + + + {"id": 13} + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml new file mode 100644 index 0000000000..11aacdf5a0 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml @@ -0,0 +1,23 @@ + + + + + + + + {"id": ${id}} + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml new file mode 100644 index 0000000000..8cb689bf3f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml new file mode 100644 index 0000000000..b2b002aa24 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java new file mode 100644 index 0000000000..d35d8934bf --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java @@ -0,0 +1,245 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.multiparttest.citrus; + + +import static org.springframework.util.CollectionUtils.isEmpty; + +import jakarta.annotation.Generated; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.Message; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.spi.Resources; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.json.JsonMessageValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public abstract class MultipartTestAbstractTestRequest extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("MULTIPARTTEST-API-COVERAGE"); + + @Autowired + @Qualifier("multipartTestEndpoint") + protected HttpClient httpClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected boolean schemaValidation; + protected String schema; + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + protected String responseAcceptType = "*/*"; + protected String responseType = "json"; + protected int responseStatus = 200; + protected String responseReasonPhrase = "OK"; + protected String responseVersion = "HTTP/1.1"; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value + protected Map cookies; + protected Map headers; + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + recieveResponse(context); + } + + /** + * This method receives the HTTP-Response. + * + * @deprecated use {@link MultipartTestAbstractTestRequest#receiveResponse(TestContext)} instead. + */ + public ReceiveMessageAction recieveResponse(TestContext context) { + + HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); + HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport + .statusCode(responseStatus) + .reasonPhrase(responseReasonPhrase) + .version(responseVersion) + .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + messageBuilderSupport.type(responseType); + httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); + var responseAction = httpClientResponseActionBuilder.build(); + + responseAction.execute(context); + + return responseAction; + } + + public @Nullable Message receiveResponse(TestContext context) { + var responseAction = recieveResponse(context); + + var messageStore = context.getMessageStore(); + return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); + } + + public abstract void sendRequest(TestContext context); + + public void setSchemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setResponseAcceptType(String responseAcceptType) { + this.responseAcceptType = responseAcceptType; + } + + public void setCookie(Map cookies) { + this.cookies = cookies; + } + + public void setHeader(Map headers) { + this.headers = headers; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + public void setResponseStatus(int responseStatus) { + this.responseStatus = responseStatus; + } + + public void setResponseReasonPhrase(String responseReasonPhrase) { + this.responseReasonPhrase = responseReasonPhrase; + } + + public void setResponseVersion(String responseVersion) { + this.responseVersion = responseVersion; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, + TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + + httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, + httpClientRequestActionBuilder); + + httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); + + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); + } + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeByBeans( + GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, httpClientRequestActionBuilder); + } + } + return httpClientRequestActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java new file mode 100644 index 0000000000..d9730d0d42 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java @@ -0,0 +1,215 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.multiparttest.citrus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.processing.Generated; + +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.Conventions; +import org.springframework.util.Assert; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class MultipartTestBeanDefinitionParser implements BeanDefinitionParser { + + private static final String COOKIE = "cookie"; + private static final String HEADER = "header"; + private static final String SOAP_HEADER = "soapHeader"; + private static final String MIME_HEADER = "mimeHeader"; + private static final String NAME = "name"; + private static final String REQUEST_BODY = "body"; + private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; + private static final String MULTIPART_BODY = "multipartBody"; + private static final String RESPONSE = "response"; + private static final String RESPONSE_JSONPATH = "json-path"; + private static final String RESPONSE_XPATH = "xpath"; + private static final String EXPRESSION = "expression"; + private static final String VALUE = "value"; + private static final String RESPONSE_RESOURCE = "resource"; + private static final String FILE = "file"; + private static final String RESPONSE_VARIABLE = "responseVariable"; + private static final String RESPONSE_VALUE = "responseValue"; + private static final String SCRIPT = "script"; + private static final String TYPE = "type"; + private static final String SQL = "sql"; + private static final String COLUMN = "column"; + private static final String VARIABLE = "variable"; + // new + private static final String SCHEMA = "schema"; + // new + private static final String SCHEMA_VALIDATION = "schemaValidation"; + + private final Class beanClass; + + public MultipartTestBeanDefinitionParser(Class beanClass) { + this.beanClass = beanClass; + } + + public BeanDefinition parse(Element element) { + return parse(element, null); + } + + /** + * Note: The {@link MultipartTestBeanDefinitionParser#parse(Element element)} allows access direct + * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. + */ + @Override + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); + retrieveRootNodeAttributes(element, builder); + retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); + retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); + retrieveOptionalNodeAttributes(element, RESPONSE, builder); + retrieveParamNodeData(element, builder, COOKIE); + retrieveParamNodeData(element, builder, HEADER); + retrieveParamNodeData(element, builder, SOAP_HEADER); + retrieveParamNodeData(element, builder, MIME_HEADER); + retrieveOptionalNodeAttributes(element, SCHEMA, builder); + retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); + retrieveOptionalMultipartElements(element, builder); + retrieveResponseNodeData(element, builder); + builder.addPropertyValue("name", element.getTagName()); + return builder.getBeanDefinition(); + } + + private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { + var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); + if (multipartBodyElement != null) { + var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); + for(int i = 0; i < multipartBodyChildElements.size(); i++){ + var multipartBodyChildElement = multipartBodyChildElements.get(i); + String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); + builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); + } + } + } + + private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { + NamedNodeMap attributes = element.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + builder.addPropertyValue(propertyName, attribute.getValue()); + } + } + + private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + } + } + + private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el1.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); + String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + builder.addPropertyValue(elementName, el.getTextContent()); + } + } + + private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { + if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { + Map params = new HashMap<>(); + List elements = DomUtils.getChildElementsByTagName(element, paramType); + elements.forEach(e -> { + String name = e.getAttribute(NAME); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + params.put(name, value); + }); + builder.addPropertyValue(paramType, params); + } + } + + private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { + + if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { + Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); + List elements = DomUtils.getChildElements(response); + + Map responseVariable = new HashMap<>(); + Map responseValue = new HashMap<>(); + + for (int i = 0; i < elements.size(); i++) { + Element e = elements.get(i); + + if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { + String expression = e.getAttribute(EXPRESSION); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + // variable to save @variable('ebid')@ else value to validate + if (value.matches("\\@variable\\('.*'\\)\\@")) { + Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); + if (match.find()) { + responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); + } + } else { + responseValue.put(expression, value); + } + } else if (e.getTagName().contains(SCRIPT)) { + String script = e.getTextContent(); + Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); + builder.addPropertyValue(SCRIPT, script); + + if (!e.getAttribute(TYPE).isEmpty()) { + String type = e.getAttribute(TYPE); + Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); + builder.addPropertyValue(TYPE, type); + } + } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { + String filePath = e.getAttribute(FILE); + Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); + builder.addPropertyValue(RESPONSE_RESOURCE, filePath); + } + + } + + builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); + builder.addPropertyValue(RESPONSE_VALUE, responseValue); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java new file mode 100644 index 0000000000..0d81b2d521 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java @@ -0,0 +1,29 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.multiparttest.citrus.extension; + +import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; +import org.citrusframework.openapi.generator.rest.multiparttest.citrus.MultipartTestBeanDefinitionParser; + +import javax.annotation.processing.Generated; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class MultipartTestNamespaceHandler extends NamespaceHandlerSupport { + + @Override + public void init() { + registerBeanDefinitionParser("deleteObjectRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.DeleteObjectRequest.class)); + registerBeanDefinitionParser("fileExistsRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.FileExistsRequest.class)); + registerBeanDefinitionParser("generateReportRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.GenerateReportRequest.class)); + registerBeanDefinitionParser("multipleDatatypesRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.MultipleDatatypesRequest.class)); + registerBeanDefinitionParser("postFileRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.PostFileRequest.class)); + registerBeanDefinitionParser("postRandomRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.PostRandomRequest.class)); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java new file mode 100644 index 0000000000..36d2bca5f4 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java @@ -0,0 +1,750 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.multiparttest.request; + +import jakarta.annotation.Generated; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.citrusframework.openapi.generator.rest.multiparttest.citrus.MultipartTestAbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class MultiparttestControllerApi implements GeneratedApi +{ + + public static final MultiparttestControllerApi INSTANCE = new MultiparttestControllerApi(); + + public String getApiTitle() { + return "multiparttest API"; + } + + public String getApiVersion() { + return "2.0.0"; + } + + public String getApiPrefix() { + return "MultipartTest"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + infoExtensionMap.put("x-citrus-api-name", "multiparttest-rest-resource"); + infoExtensionMap.put("x-citrus-app", "MPT"); + return infoExtensionMap; + } + + /** deleteObject (DELETE /api/v2/multitest-file/{bucket}/{filename}) + Delete file. + + **/ + public static class DeleteObjectRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}"; + private final Logger coverageLogger = LoggerFactory.getLogger(DeleteObjectRequest.class); + + private String bucket; + + private String filename; + + + public DeleteObjectRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":deleteObjectRequestType"); + } + + public String getOperationName() { + return "deleteObject"; + } + + public String getMethod() { + return "DELETE"; + } + + public String getPath() { + return "/api/v2/multitest-file/{bucket}/{filename}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .delete(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "deleteObject;DELETE;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); + return endpoint; + } + } + /** fileExists (GET /api/v2/multitest-file/{bucket}/{filename}/exists) + Checks if file exist. + + **/ + public static class FileExistsRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}/exists"; + private final Logger coverageLogger = LoggerFactory.getLogger(FileExistsRequest.class); + + private String bucket; + + private String filename; + + + public FileExistsRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":fileExistsRequestType"); + } + + public String getOperationName() { + return "fileExists"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/api/v2/multitest-file/{bucket}/{filename}/exists"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "fileExists;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); + return endpoint; + } + } + /** generateReport (POST /api/v2/multitest-reportgeneration) + summary + + **/ + public static class GenerateReportRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-reportgeneration"; + private final Logger coverageLogger = LoggerFactory.getLogger(GenerateReportRequest.class); + + private String template; + + private String additionalData; + + private String _schema; + + + public GenerateReportRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":generateReportRequestType"); + } + + public String getOperationName() { + return "generateReport"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/api/v2/multitest-reportgeneration"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + if(StringUtils.isBlank(template)) { + throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "template")); + } + if (StringUtils.isNotBlank(template)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(template); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("template", resource); + } else { + multiValues.add("template", template); + } + bodyLog += template.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + if (StringUtils.isNotBlank(additionalData)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(additionalData); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("additionalData", resource); + } else { + multiValues.add("additionalData", additionalData); + } + bodyLog += additionalData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + if (StringUtils.isNotBlank(_schema)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(_schema); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("_schema", resource); + } else { + multiValues.add("_schema", _schema); + } + bodyLog += _schema.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "generateReport;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setTemplate(String template) { + this.template = template; + } + + public void setAdditionalData(String additionalData) { + this.additionalData = additionalData; + } + + public void set_schema(String _schema) { + this._schema = _schema; + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** multipleDatatypes (POST /api/v2/multitest-multipledatatypes) + summary + + **/ + public static class MultipleDatatypesRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-multipledatatypes"; + private final Logger coverageLogger = LoggerFactory.getLogger(MultipleDatatypesRequest.class); + + private String stringData; + + private String booleanData; + + private String integerData; + + + public MultipleDatatypesRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":multipleDatatypesRequestType"); + } + + public String getOperationName() { + return "multipleDatatypes"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/api/v2/multitest-multipledatatypes"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + if (StringUtils.isNotBlank(stringData)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(stringData); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("stringData", resource); + } else { + multiValues.add("stringData", stringData); + } + bodyLog += stringData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + if (StringUtils.isNotBlank(booleanData)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(booleanData); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("booleanData", resource); + } else { + multiValues.add("booleanData", booleanData); + } + bodyLog += booleanData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + if (StringUtils.isNotBlank(integerData)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(integerData); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("integerData", resource); + } else { + multiValues.add("integerData", integerData); + } + bodyLog += integerData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "multipleDatatypes;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setStringData(String stringData) { + this.stringData = stringData; + } + + public void setBooleanData(String booleanData) { + this.booleanData = booleanData; + } + + public void setIntegerData(String integerData) { + this.integerData = integerData; + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** postFile (POST /api/v2/multitest-file/{bucket}/{filename}) + Uploads file. + + **/ + public static class PostFileRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}"; + private final Logger coverageLogger = LoggerFactory.getLogger(PostFileRequest.class); + + private String bucket; + + private String filename; + + private String multipartFile; + + + public PostFileRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":postFileRequestType"); + } + + public String getOperationName() { + return "postFile"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/api/v2/multitest-file/{bucket}/{filename}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + if (StringUtils.isNotBlank(multipartFile)) { + multiValues.add("multipartFile", new ClassPathResource(multipartFile)); + bodyLog += multipartFile.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "postFile;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public void setMultipartFile(String multipartFile) { + this.multipartFile = multipartFile; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); + return endpoint; + } + } + /** postRandom (POST /api/v2/multitest-file/{bucket}/{filename}/random) + Uploads random file. + + **/ + public static class PostRandomRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}/random"; + private final Logger coverageLogger = LoggerFactory.getLogger(PostRandomRequest.class); + + private String bucket; + + private String filename; + + + public PostRandomRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("MultipartTest".toLowerCase() + ":postRandomRequestType"); + } + + public String getOperationName() { + return "postRandom"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/api/v2/multitest-file/{bucket}/{filename}/random"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "postRandom;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); + return endpoint; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java new file mode 100644 index 0000000000..090a9bfb7e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java @@ -0,0 +1,56 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.multiparttest.spring; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; +import javax.annotation.processing.Generated; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class MultipartTestBeanConfiguration { + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.DeleteObjectRequest deleteObjectRequest() { + return new MultiparttestControllerApi.DeleteObjectRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.FileExistsRequest fileExistsRequest() { + return new MultiparttestControllerApi.FileExistsRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.GenerateReportRequest generateReportRequest() { + return new MultiparttestControllerApi.GenerateReportRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.MultipleDatatypesRequest multipleDatatypesRequest() { + return new MultiparttestControllerApi.MultipleDatatypesRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.PostFileRequest postFileRequest() { + return new MultiparttestControllerApi.PostFileRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public MultiparttestControllerApi.PostRandomRequest postRandomRequest() { + return new MultiparttestControllerApi.PostRandomRequest(); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java new file mode 100644 index 0000000000..9ff2150d21 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java @@ -0,0 +1,245 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.citrus; + + +import static org.springframework.util.CollectionUtils.isEmpty; + +import jakarta.annotation.Generated; +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.Message; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.spi.Resources; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.json.JsonMessageValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public abstract class PetStoreAbstractTestRequest extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); + + @Autowired + @Qualifier("petStoreEndpoint") + protected HttpClient httpClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected boolean schemaValidation; + protected String schema; + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + protected String responseAcceptType = "*/*"; + protected String responseType = "json"; + protected int responseStatus = 200; + protected String responseReasonPhrase = "OK"; + protected String responseVersion = "HTTP/1.1"; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value + protected Map cookies; + protected Map headers; + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + recieveResponse(context); + } + + /** + * This method receives the HTTP-Response. + * + * @deprecated use {@link PetStoreAbstractTestRequest#receiveResponse(TestContext)} instead. + */ + public ReceiveMessageAction recieveResponse(TestContext context) { + + HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); + HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport + .statusCode(responseStatus) + .reasonPhrase(responseReasonPhrase) + .version(responseVersion) + .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + messageBuilderSupport.type(responseType); + httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); + var responseAction = httpClientResponseActionBuilder.build(); + + responseAction.execute(context); + + return responseAction; + } + + public @Nullable Message receiveResponse(TestContext context) { + var responseAction = recieveResponse(context); + + var messageStore = context.getMessageStore(); + return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); + } + + public abstract void sendRequest(TestContext context); + + public void setSchemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setResponseAcceptType(String responseAcceptType) { + this.responseAcceptType = responseAcceptType; + } + + public void setCookie(Map cookies) { + this.cookies = cookies; + } + + public void setHeader(Map headers) { + this.headers = headers; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + public void setResponseStatus(int responseStatus) { + this.responseStatus = responseStatus; + } + + public void setResponseReasonPhrase(String responseReasonPhrase) { + this.responseReasonPhrase = responseReasonPhrase; + } + + public void setResponseVersion(String responseVersion) { + this.responseVersion = responseVersion; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, + TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + + httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, + httpClientRequestActionBuilder); + + httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); + + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); + } + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeByBeans( + GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, httpClientRequestActionBuilder); + } + } + return httpClientRequestActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java new file mode 100644 index 0000000000..32920fb8ef --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java @@ -0,0 +1,215 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.citrus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.processing.Generated; + +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.Conventions; +import org.springframework.util.Assert; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class PetStoreBeanDefinitionParser implements BeanDefinitionParser { + + private static final String COOKIE = "cookie"; + private static final String HEADER = "header"; + private static final String SOAP_HEADER = "soapHeader"; + private static final String MIME_HEADER = "mimeHeader"; + private static final String NAME = "name"; + private static final String REQUEST_BODY = "body"; + private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; + private static final String MULTIPART_BODY = "multipartBody"; + private static final String RESPONSE = "response"; + private static final String RESPONSE_JSONPATH = "json-path"; + private static final String RESPONSE_XPATH = "xpath"; + private static final String EXPRESSION = "expression"; + private static final String VALUE = "value"; + private static final String RESPONSE_RESOURCE = "resource"; + private static final String FILE = "file"; + private static final String RESPONSE_VARIABLE = "responseVariable"; + private static final String RESPONSE_VALUE = "responseValue"; + private static final String SCRIPT = "script"; + private static final String TYPE = "type"; + private static final String SQL = "sql"; + private static final String COLUMN = "column"; + private static final String VARIABLE = "variable"; + // new + private static final String SCHEMA = "schema"; + // new + private static final String SCHEMA_VALIDATION = "schemaValidation"; + + private final Class beanClass; + + public PetStoreBeanDefinitionParser(Class beanClass) { + this.beanClass = beanClass; + } + + public BeanDefinition parse(Element element) { + return parse(element, null); + } + + /** + * Note: The {@link PetStoreBeanDefinitionParser#parse(Element element)} allows access direct + * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. + */ + @Override + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); + retrieveRootNodeAttributes(element, builder); + retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); + retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); + retrieveOptionalNodeAttributes(element, RESPONSE, builder); + retrieveParamNodeData(element, builder, COOKIE); + retrieveParamNodeData(element, builder, HEADER); + retrieveParamNodeData(element, builder, SOAP_HEADER); + retrieveParamNodeData(element, builder, MIME_HEADER); + retrieveOptionalNodeAttributes(element, SCHEMA, builder); + retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); + retrieveOptionalMultipartElements(element, builder); + retrieveResponseNodeData(element, builder); + builder.addPropertyValue("name", element.getTagName()); + return builder.getBeanDefinition(); + } + + private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { + var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); + if (multipartBodyElement != null) { + var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); + for(int i = 0; i < multipartBodyChildElements.size(); i++){ + var multipartBodyChildElement = multipartBodyChildElements.get(i); + String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); + builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); + } + } + } + + private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { + NamedNodeMap attributes = element.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + builder.addPropertyValue(propertyName, attribute.getValue()); + } + } + + private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + } + } + + private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el1.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); + String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + builder.addPropertyValue(elementName, el.getTextContent()); + } + } + + private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { + if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { + Map params = new HashMap<>(); + List elements = DomUtils.getChildElementsByTagName(element, paramType); + elements.forEach(e -> { + String name = e.getAttribute(NAME); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + params.put(name, value); + }); + builder.addPropertyValue(paramType, params); + } + } + + private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { + + if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { + Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); + List elements = DomUtils.getChildElements(response); + + Map responseVariable = new HashMap<>(); + Map responseValue = new HashMap<>(); + + for (int i = 0; i < elements.size(); i++) { + Element e = elements.get(i); + + if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { + String expression = e.getAttribute(EXPRESSION); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + // variable to save @variable('ebid')@ else value to validate + if (value.matches("\\@variable\\('.*'\\)\\@")) { + Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); + if (match.find()) { + responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); + } + } else { + responseValue.put(expression, value); + } + } else if (e.getTagName().contains(SCRIPT)) { + String script = e.getTextContent(); + Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); + builder.addPropertyValue(SCRIPT, script); + + if (!e.getAttribute(TYPE).isEmpty()) { + String type = e.getAttribute(TYPE); + Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); + builder.addPropertyValue(TYPE, type); + } + } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { + String filePath = e.getAttribute(FILE); + Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); + builder.addPropertyValue(RESPONSE_RESOURCE, filePath); + } + + } + + builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); + builder.addPropertyValue(RESPONSE_VALUE, responseValue); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java new file mode 100644 index 0000000000..af5b731084 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java @@ -0,0 +1,45 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.citrus.extension; + +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; +import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreBeanDefinitionParser; + +import javax.annotation.processing.Generated; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { + + @Override + public void init() { + registerBeanDefinitionParser("addPetRequest", new PetStoreBeanDefinitionParser(PetApi.AddPetRequest.class)); + registerBeanDefinitionParser("deletePetRequest", new PetStoreBeanDefinitionParser(PetApi.DeletePetRequest.class)); + registerBeanDefinitionParser("findPetsByStatusRequest", new PetStoreBeanDefinitionParser(PetApi.FindPetsByStatusRequest.class)); + registerBeanDefinitionParser("findPetsByTagsRequest", new PetStoreBeanDefinitionParser(PetApi.FindPetsByTagsRequest.class)); + registerBeanDefinitionParser("getPetByIdRequest", new PetStoreBeanDefinitionParser(PetApi.GetPetByIdRequest.class)); + registerBeanDefinitionParser("updatePetRequest", new PetStoreBeanDefinitionParser(PetApi.UpdatePetRequest.class)); + registerBeanDefinitionParser("updatePetWithFormRequest", new PetStoreBeanDefinitionParser(PetApi.UpdatePetWithFormRequest.class)); + registerBeanDefinitionParser("uploadFileRequest", new PetStoreBeanDefinitionParser(PetApi.UploadFileRequest.class)); + registerBeanDefinitionParser("deleteOrderRequest", new PetStoreBeanDefinitionParser(StoreApi.DeleteOrderRequest.class)); + registerBeanDefinitionParser("getInventoryRequest", new PetStoreBeanDefinitionParser(StoreApi.GetInventoryRequest.class)); + registerBeanDefinitionParser("getOrderByIdRequest", new PetStoreBeanDefinitionParser(StoreApi.GetOrderByIdRequest.class)); + registerBeanDefinitionParser("placeOrderRequest", new PetStoreBeanDefinitionParser(StoreApi.PlaceOrderRequest.class)); + registerBeanDefinitionParser("createUserRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUserRequest.class)); + registerBeanDefinitionParser("createUsersWithArrayInputRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUsersWithArrayInputRequest.class)); + registerBeanDefinitionParser("createUsersWithListInputRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUsersWithListInputRequest.class)); + registerBeanDefinitionParser("deleteUserRequest", new PetStoreBeanDefinitionParser(UserApi.DeleteUserRequest.class)); + registerBeanDefinitionParser("getUserByNameRequest", new PetStoreBeanDefinitionParser(UserApi.GetUserByNameRequest.class)); + registerBeanDefinitionParser("loginUserRequest", new PetStoreBeanDefinitionParser(UserApi.LoginUserRequest.class)); + registerBeanDefinitionParser("logoutUserRequest", new PetStoreBeanDefinitionParser(UserApi.LogoutUserRequest.class)); + registerBeanDefinitionParser("updateUserRequest", new PetStoreBeanDefinitionParser(UserApi.UpdateUserRequest.class)); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java new file mode 100644 index 0000000000..d5341fea2c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java @@ -0,0 +1 @@ +// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java new file mode 100644 index 0000000000..a014b1c53f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java @@ -0,0 +1,862 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.request; + +import jakarta.annotation.Generated; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class PetApi implements GeneratedApi +{ + + public static final PetApi INSTANCE = new PetApi(); + + public String getApiTitle() { + return "OpenAPI Petstore"; + } + + public String getApiVersion() { + return "1.0.0"; + } + + public String getApiPrefix() { + return "PetStore"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + infoExtensionMap.put("x-citrus-api-name", "petstore"); + infoExtensionMap.put("x-citrus-app", "PETS"); + return infoExtensionMap; + } + + /** addPet (POST /pet) + Add a new pet to the store + + **/ + public static class AddPetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet"; + private final Logger coverageLogger = LoggerFactory.getLogger(AddPetRequest.class); + + + public AddPetRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":addPetRequestType"); + } + + public String getOperationName() { + return "addPet"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/pet"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "addPet;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** deletePet (DELETE /pet/{petId}) + Deletes a pet + + **/ + public static class DeletePetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/{petId}"; + private final Logger coverageLogger = LoggerFactory.getLogger(DeletePetRequest.class); + + private String petId; + + + public DeletePetRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":deletePetRequestType"); + } + + public String getOperationName() { + return "deletePet"; + } + + public String getMethod() { + return "DELETE"; + } + + public String getPath() { + return "/pet/{petId}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .delete(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "deletePet;DELETE;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setPetId(String petId) { + this.petId = petId; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "petId" + "}", petId); + return endpoint; + } + } + /** findPetsByStatus (GET /pet/findByStatus) + Finds Pets by status + + **/ + public static class FindPetsByStatusRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/findByStatus"; + private final Logger coverageLogger = LoggerFactory.getLogger(FindPetsByStatusRequest.class); + + private String status; + + + public FindPetsByStatusRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":findPetsByStatusRequestType"); + } + + public String getOperationName() { + return "findPetsByStatus"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/pet/findByStatus"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + + if (StringUtils.isNotBlank(this.status)) { + queryParams.put("status", context.replaceDynamicContentInString(this.status)); + httpClientRequestActionBuilder.queryParam("status", this.status); + } + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "findPetsByStatus;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setStatus(String status) { + this.status = status; + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** findPetsByTags (GET /pet/findByTags) + Finds Pets by tags + + **/ + public static class FindPetsByTagsRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/findByTags"; + private final Logger coverageLogger = LoggerFactory.getLogger(FindPetsByTagsRequest.class); + + private String tags; + + + public FindPetsByTagsRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":findPetsByTagsRequestType"); + } + + public String getOperationName() { + return "findPetsByTags"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/pet/findByTags"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + + if (StringUtils.isNotBlank(this.tags)) { + queryParams.put("tags", context.replaceDynamicContentInString(this.tags)); + httpClientRequestActionBuilder.queryParam("tags", this.tags); + } + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "findPetsByTags;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setTags(String tags) { + this.tags = tags; + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** getPetById (GET /pet/{petId}) + Find pet by ID + + **/ + public static class GetPetByIdRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/{petId}"; + private final Logger coverageLogger = LoggerFactory.getLogger(GetPetByIdRequest.class); + + private String petId; + + + @Value("${" + "petStoreEndpoint.basic.username:#{null}}") + private String basicUsername; + @Value("${" + "petStoreEndpoint.basic.password:#{null}}") + private String basicPassword; + + + public GetPetByIdRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":getPetByIdRequestType"); + } + + public String getOperationName() { + return "getPetById"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/pet/{petId}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + + if(basicUsername != null && basicPassword != null){ + messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); + } + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getPetById;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setPetId(String petId) { + this.petId = petId; + } + + + public void setBasicUsername(String basicUsername) { + this.basicUsername = basicUsername; + } + + public void setBasicPassword(String basicPassword) { + this.basicPassword = basicPassword; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "petId" + "}", petId); + return endpoint; + } + } + /** updatePet (PUT /pet) + Update an existing pet + + **/ + public static class UpdatePetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet"; + private final Logger coverageLogger = LoggerFactory.getLogger(UpdatePetRequest.class); + + + public UpdatePetRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":updatePetRequestType"); + } + + public String getOperationName() { + return "updatePet"; + } + + public String getMethod() { + return "PUT"; + } + + public String getPath() { + return "/pet"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .put(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "updatePet;PUT;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** updatePetWithForm (POST /pet/{petId}) + Updates a pet in the store with form data + + **/ + public static class UpdatePetWithFormRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/{petId}"; + private final Logger coverageLogger = LoggerFactory.getLogger(UpdatePetWithFormRequest.class); + + private String petId; + + + public UpdatePetWithFormRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":updatePetWithFormRequestType"); + } + + public String getOperationName() { + return "updatePetWithForm"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/pet/{petId}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "updatePetWithForm;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setPetId(String petId) { + this.petId = petId; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "petId" + "}", petId); + return endpoint; + } + } + /** uploadFile (POST /pet/{petId}/uploadImage) + uploads an image + + **/ + public static class UploadFileRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/pet/{petId}/uploadImage"; + private final Logger coverageLogger = LoggerFactory.getLogger(UploadFileRequest.class); + + private String petId; + + private String additionalMetadata; + + private String _file; + + + public UploadFileRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":uploadFileRequestType"); + } + + public String getOperationName() { + return "uploadFile"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/pet/{petId}/uploadImage"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + if (StringUtils.isNotBlank(additionalMetadata)) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource(additionalMetadata); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("additionalMetadata", resource); + } else { + multiValues.add("additionalMetadata", additionalMetadata); + } + bodyLog += additionalMetadata.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + if (StringUtils.isNotBlank(_file)) { + multiValues.add("_file", new ClassPathResource(_file)); + bodyLog += _file.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "uploadFile;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setPetId(String petId) { + this.petId = petId; + } + + public void setAdditionalMetadata(String additionalMetadata) { + this.additionalMetadata = additionalMetadata; + } + + public void set_file(String _file) { + this._file = _file; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "petId" + "}", petId); + return endpoint; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java new file mode 100644 index 0000000000..406f97f2f9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java @@ -0,0 +1,433 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.request; + +import jakarta.annotation.Generated; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class StoreApi implements GeneratedApi +{ + + public static final StoreApi INSTANCE = new StoreApi(); + + public String getApiTitle() { + return "OpenAPI Petstore"; + } + + public String getApiVersion() { + return "1.0.0"; + } + + public String getApiPrefix() { + return "PetStore"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + infoExtensionMap.put("x-citrus-api-name", "petstore"); + infoExtensionMap.put("x-citrus-app", "PETS"); + return infoExtensionMap; + } + + /** deleteOrder (DELETE /store/order/{order_id}) + Delete purchase order by ID + + **/ + public static class DeleteOrderRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/store/order/{order_id}"; + private final Logger coverageLogger = LoggerFactory.getLogger(DeleteOrderRequest.class); + + private String orderId; + + + public DeleteOrderRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":deleteOrderRequestType"); + } + + public String getOperationName() { + return "deleteOrder"; + } + + public String getMethod() { + return "DELETE"; + } + + public String getPath() { + return "/store/order/{order_id}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .delete(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "deleteOrder;DELETE;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "order_id" + "}", orderId); + return endpoint; + } + } + /** getInventory (GET /store/inventory) + Returns pet inventories by status + + **/ + public static class GetInventoryRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/store/inventory"; + private final Logger coverageLogger = LoggerFactory.getLogger(GetInventoryRequest.class); + + + public GetInventoryRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":getInventoryRequestType"); + } + + public String getOperationName() { + return "getInventory"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/store/inventory"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getInventory;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** getOrderById (GET /store/order/{order_id}) + Find purchase order by ID + + **/ + public static class GetOrderByIdRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/store/order/{order_id}"; + private final Logger coverageLogger = LoggerFactory.getLogger(GetOrderByIdRequest.class); + + private String orderId; + + + public GetOrderByIdRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":getOrderByIdRequestType"); + } + + public String getOperationName() { + return "getOrderById"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/store/order/{order_id}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getOrderById;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "order_id" + "}", orderId); + return endpoint; + } + } + /** placeOrder (POST /store/order) + Place an order for a pet + + **/ + public static class PlaceOrderRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/store/order"; + private final Logger coverageLogger = LoggerFactory.getLogger(PlaceOrderRequest.class); + + + public PlaceOrderRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":placeOrderRequestType"); + } + + public String getOperationName() { + return "placeOrder"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/store/order"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "placeOrder;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java new file mode 100644 index 0000000000..01f4558954 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java @@ -0,0 +1,819 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.request; + +import jakarta.annotation.Generated; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class UserApi implements GeneratedApi +{ + + public static final UserApi INSTANCE = new UserApi(); + + public String getApiTitle() { + return "OpenAPI Petstore"; + } + + public String getApiVersion() { + return "1.0.0"; + } + + public String getApiPrefix() { + return "PetStore"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + infoExtensionMap.put("x-citrus-api-name", "petstore"); + infoExtensionMap.put("x-citrus-app", "PETS"); + return infoExtensionMap; + } + + /** createUser (POST /user) + Create user + + **/ + public static class CreateUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user"; + private final Logger coverageLogger = LoggerFactory.getLogger(CreateUserRequest.class); + + + public CreateUserRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":createUserRequestType"); + } + + public String getOperationName() { + return "createUser"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/user"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "createUser;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** createUsersWithArrayInput (POST /user/createWithArray) + Creates list of users with given input array + + **/ + public static class CreateUsersWithArrayInputRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/createWithArray"; + private final Logger coverageLogger = LoggerFactory.getLogger(CreateUsersWithArrayInputRequest.class); + + + public CreateUsersWithArrayInputRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":createUsersWithArrayInputRequestType"); + } + + public String getOperationName() { + return "createUsersWithArrayInput"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/user/createWithArray"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "createUsersWithArrayInput;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** createUsersWithListInput (POST /user/createWithList) + Creates list of users with given input array + + **/ + public static class CreateUsersWithListInputRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/createWithList"; + private final Logger coverageLogger = LoggerFactory.getLogger(CreateUsersWithListInputRequest.class); + + + public CreateUsersWithListInputRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":createUsersWithListInputRequestType"); + } + + public String getOperationName() { + return "createUsersWithListInput"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/user/createWithList"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .post(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "createUsersWithListInput;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** deleteUser (DELETE /user/{username}) + Delete user + + **/ + public static class DeleteUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/{username}"; + private final Logger coverageLogger = LoggerFactory.getLogger(DeleteUserRequest.class); + + private String username; + + + public DeleteUserRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":deleteUserRequestType"); + } + + public String getOperationName() { + return "deleteUser"; + } + + public String getMethod() { + return "DELETE"; + } + + public String getPath() { + return "/user/{username}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .delete(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "deleteUser;DELETE;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setUsername(String username) { + this.username = username; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "username" + "}", username); + return endpoint; + } + } + /** getUserByName (GET /user/{username}) + Get user by user name + + **/ + public static class GetUserByNameRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/{username}"; + private final Logger coverageLogger = LoggerFactory.getLogger(GetUserByNameRequest.class); + + private String username; + + + public GetUserByNameRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":getUserByNameRequestType"); + } + + public String getOperationName() { + return "getUserByName"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/user/{username}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getUserByName;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setUsername(String username) { + this.username = username; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "username" + "}", username); + return endpoint; + } + } + /** loginUser (GET /user/login) + Logs user into the system + + **/ + public static class LoginUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/login"; + private final Logger coverageLogger = LoggerFactory.getLogger(LoginUserRequest.class); + + private String username; + + private String password; + + + public LoginUserRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":loginUserRequestType"); + } + + public String getOperationName() { + return "loginUser"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/user/login"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + + if (StringUtils.isNotBlank(this.username)) { + queryParams.put("username", context.replaceDynamicContentInString(this.username)); + httpClientRequestActionBuilder.queryParam("username", this.username); + } + + + if (StringUtils.isNotBlank(this.password)) { + queryParams.put("password", context.replaceDynamicContentInString(this.password)); + httpClientRequestActionBuilder.queryParam("password", this.password); + } + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "loginUser;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** logoutUser (GET /user/logout) + Logs out current logged in user session + + **/ + public static class LogoutUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/logout"; + private final Logger coverageLogger = LoggerFactory.getLogger(LogoutUserRequest.class); + + + public LogoutUserRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":logoutUserRequestType"); + } + + public String getOperationName() { + return "logoutUser"; + } + + public String getMethod() { + return "GET"; + } + + public String getPath() { + return "/user/logout"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .get(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "logoutUser;GET;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + private String replacePathParams(String endpoint) { + + return endpoint; + } + } + /** updateUser (PUT /user/{username}) + Updated user + + **/ + public static class UpdateUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "/user/{username}"; + private final Logger coverageLogger = LoggerFactory.getLogger(UpdateUserRequest.class); + + private String username; + + + public UpdateUserRequest() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("PetStore".toLowerCase() + ":updateUserRequestType"); + } + + public String getOperationName() { + return "updateUser"; + } + + public String getMethod() { + return "PUT"; + } + + public String getPath() { + return "/user/{username}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .put(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "updateUser;PUT;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + + public void setUsername(String username) { + this.username = username; + } + + private String replacePathParams(String endpoint) { + endpoint = endpoint.replace("{" + "username" + "}", username); + return endpoint; + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java new file mode 100644 index 0000000000..cb89458c0b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -0,0 +1,142 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.rest.petstore.spring; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; +import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import javax.annotation.processing.Generated; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class PetStoreBeanConfiguration { + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.AddPetRequest addPetRequest() { + return new PetApi.AddPetRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.DeletePetRequest deletePetRequest() { + return new PetApi.DeletePetRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.FindPetsByStatusRequest findPetsByStatusRequest() { + return new PetApi.FindPetsByStatusRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.FindPetsByTagsRequest findPetsByTagsRequest() { + return new PetApi.FindPetsByTagsRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.GetPetByIdRequest getPetByIdRequest() { + return new PetApi.GetPetByIdRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.UpdatePetRequest updatePetRequest() { + return new PetApi.UpdatePetRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.UpdatePetWithFormRequest updatePetWithFormRequest() { + return new PetApi.UpdatePetWithFormRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public PetApi.UploadFileRequest uploadFileRequest() { + return new PetApi.UploadFileRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public StoreApi.DeleteOrderRequest deleteOrderRequest() { + return new StoreApi.DeleteOrderRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public StoreApi.GetInventoryRequest getInventoryRequest() { + return new StoreApi.GetInventoryRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public StoreApi.GetOrderByIdRequest getOrderByIdRequest() { + return new StoreApi.GetOrderByIdRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public StoreApi.PlaceOrderRequest placeOrderRequest() { + return new StoreApi.PlaceOrderRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.CreateUserRequest createUserRequest() { + return new UserApi.CreateUserRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.CreateUsersWithArrayInputRequest createUsersWithArrayInputRequest() { + return new UserApi.CreateUsersWithArrayInputRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.CreateUsersWithListInputRequest createUsersWithListInputRequest() { + return new UserApi.CreateUsersWithListInputRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.DeleteUserRequest deleteUserRequest() { + return new UserApi.DeleteUserRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.GetUserByNameRequest getUserByNameRequest() { + return new UserApi.GetUserByNameRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.LoginUserRequest loginUserRequest() { + return new UserApi.LoginUserRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.LogoutUserRequest logoutUserRequest() { + return new UserApi.LogoutUserRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public UserApi.UpdateUserRequest updateUserRequest() { + return new UserApi.UpdateUserRequest(); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java new file mode 100644 index 0000000000..8acda64ca3 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java @@ -0,0 +1,187 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.soap.bookservice.citrus; + +import jakarta.annotation.Generated; +import java.util.List; +import java.util.ServiceLoader; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.spi.Resources; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction.SoapMessageBuilderSupport; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SoapActionBuilder; +import org.citrusframework.ws.client.WebServiceClient; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.util.CollectionUtils; + +import javax.sql.DataSource; +import java.util.Map; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public abstract class OpenApiFromWsdlAbstractTestRequest extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("OPENAPIFROMWSDL-API-COVERAGE"); + + @Autowired + @Qualifier("soapSampleEndpoint") + protected WebServiceClient wsClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'XPATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'XPATH' as key and the 'VALUE TO BE VALIDATED' as value + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + protected Map soapHeaders; + protected Map mimeHeaders; + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + receiveResponse(context); + } + + /** + * This method receives the HTTP-Response + */ + public void receiveResponse(TestContext context) { + + ReceiveSoapMessageAction.Builder soapReceiveMessageActionBuilder = new SoapActionBuilder().client(wsClient).receive(); + SoapMessageBuilderSupport messageBuilderSupport = soapReceiveMessageActionBuilder.getMessageBuilderSupport(); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!CollectionUtils.isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!CollectionUtils.isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + soapReceiveMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapReceiveMessageActionBuilder.build().execute(context); + } + + public abstract void sendRequest(TestContext context); + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + public void setSoapHeader(Map soapHeaders) { + this.soapHeaders = soapHeaders; + } + + public void setMimeHeader(Map mimeHeaders) { + this.mimeHeaders = mimeHeaders; + } + + protected SendSoapMessageAction.Builder customizeBuilder(GeneratedApi generatedApi, + TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + sendSoapMessageActionBuilder = customizeByBeans(generatedApi, context, sendSoapMessageActionBuilder); + + sendSoapMessageActionBuilder = customizeBySpi(generatedApi, context, sendSoapMessageActionBuilder); + + return sendSoapMessageActionBuilder; + } + + private SendSoapMessageAction.Builder customizeBySpi(GeneratedApi generatedApi, TestContext context, + SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + sendSoapMessageActionBuilder = service.build(generatedApi, this, context, sendSoapMessageActionBuilder); + } + + return sendSoapMessageActionBuilder; + } + + private SendSoapMessageAction.Builder customizeByBeans( + GeneratedApi generatedApi, TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { + + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + sendSoapMessageActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, sendSoapMessageActionBuilder); + } + } + + return sendSoapMessageActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java new file mode 100644 index 0000000000..1c72d58016 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java @@ -0,0 +1,215 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.soap.bookservice.citrus; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.processing.Generated; + +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.core.Conventions; +import org.springframework.util.Assert; +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class OpenApiFromWsdlBeanDefinitionParser implements BeanDefinitionParser { + + private static final String COOKIE = "cookie"; + private static final String HEADER = "header"; + private static final String SOAP_HEADER = "soapHeader"; + private static final String MIME_HEADER = "mimeHeader"; + private static final String NAME = "name"; + private static final String REQUEST_BODY = "body"; + private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; + private static final String MULTIPART_BODY = "multipartBody"; + private static final String RESPONSE = "response"; + private static final String RESPONSE_JSONPATH = "json-path"; + private static final String RESPONSE_XPATH = "xpath"; + private static final String EXPRESSION = "expression"; + private static final String VALUE = "value"; + private static final String RESPONSE_RESOURCE = "resource"; + private static final String FILE = "file"; + private static final String RESPONSE_VARIABLE = "responseVariable"; + private static final String RESPONSE_VALUE = "responseValue"; + private static final String SCRIPT = "script"; + private static final String TYPE = "type"; + private static final String SQL = "sql"; + private static final String COLUMN = "column"; + private static final String VARIABLE = "variable"; + // new + private static final String SCHEMA = "schema"; + // new + private static final String SCHEMA_VALIDATION = "schemaValidation"; + + private final Class beanClass; + + public OpenApiFromWsdlBeanDefinitionParser(Class beanClass) { + this.beanClass = beanClass; + } + + public BeanDefinition parse(Element element) { + return parse(element, null); + } + + /** + * Note: The {@link OpenApiFromWsdlBeanDefinitionParser#parse(Element element)} allows access direct + * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. + */ + @Override + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); + retrieveRootNodeAttributes(element, builder); + retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); + retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); + retrieveOptionalNodeAttributes(element, RESPONSE, builder); + retrieveParamNodeData(element, builder, COOKIE); + retrieveParamNodeData(element, builder, HEADER); + retrieveParamNodeData(element, builder, SOAP_HEADER); + retrieveParamNodeData(element, builder, MIME_HEADER); + retrieveOptionalNodeAttributes(element, SCHEMA, builder); + retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); + retrieveOptionalMultipartElements(element, builder); + retrieveResponseNodeData(element, builder); + builder.addPropertyValue("name", element.getTagName()); + return builder.getBeanDefinition(); + } + + private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { + var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); + if (multipartBodyElement != null) { + var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); + for(int i = 0; i < multipartBodyChildElements.size(); i++){ + var multipartBodyChildElement = multipartBodyChildElements.get(i); + String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); + builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); + } + } + } + + private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { + NamedNodeMap attributes = element.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + builder.addPropertyValue(propertyName, attribute.getValue()); + } + } + + private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); + String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + } + } + + private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { + if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { + Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); + NamedNodeMap attributes = el1.getAttributes(); + for (int x = 0; x < attributes.getLength(); x++) { + Attr attribute = (Attr) attributes.item(x); + String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); + Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); + String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); + builder.addPropertyValue(variableName, attribute.getValue()); + } + Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); + builder.addPropertyValue(elementName, el.getTextContent()); + } + } + + private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { + if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { + Map params = new HashMap<>(); + List elements = DomUtils.getChildElementsByTagName(element, paramType); + elements.forEach(e -> { + String name = e.getAttribute(NAME); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + params.put(name, value); + }); + builder.addPropertyValue(paramType, params); + } + } + + private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { + + if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { + Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); + List elements = DomUtils.getChildElements(response); + + Map responseVariable = new HashMap<>(); + Map responseValue = new HashMap<>(); + + for (int i = 0; i < elements.size(); i++) { + Element e = elements.get(i); + + if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { + String expression = e.getAttribute(EXPRESSION); + String value = e.getAttribute(VALUE); + + Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); + Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); + + // variable to save @variable('ebid')@ else value to validate + if (value.matches("\\@variable\\('.*'\\)\\@")) { + Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); + if (match.find()) { + responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); + } + } else { + responseValue.put(expression, value); + } + } else if (e.getTagName().contains(SCRIPT)) { + String script = e.getTextContent(); + Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); + builder.addPropertyValue(SCRIPT, script); + + if (!e.getAttribute(TYPE).isEmpty()) { + String type = e.getAttribute(TYPE); + Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); + builder.addPropertyValue(TYPE, type); + } + } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { + String filePath = e.getAttribute(FILE); + Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); + builder.addPropertyValue(RESPONSE_RESOURCE, filePath); + } + + } + + builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); + builder.addPropertyValue(RESPONSE_VALUE, responseValue); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java new file mode 100644 index 0000000000..04773ddb99 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java @@ -0,0 +1,26 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.soap.bookservice.citrus.extension; + +import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; +import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlBeanDefinitionParser; + +import javax.annotation.processing.Generated; + +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class OpenApiFromWsdlNamespaceHandler extends NamespaceHandlerSupport { + + @Override + public void init() { + registerBeanDefinitionParser("addBookRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.AddBookRequest.class)); + registerBeanDefinitionParser("getAllBooksRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.GetAllBooksRequest.class)); + registerBeanDefinitionParser("getBookRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.GetBookRequest.class)); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java new file mode 100644 index 0000000000..dd84878034 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -0,0 +1,330 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.soap.bookservice.request; + +import jakarta.annotation.Generated; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.FileUtils; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction.Builder.SendSoapMessageBuilderSupport; +import org.citrusframework.ws.actions.SoapActionBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.CollectionUtils; + +import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; + +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class BookServiceSoapApi implements GeneratedApi +{ + public static final BookServiceSoapApi INSTANCE = new BookServiceSoapApi(); + + public String getApiTitle() { + return "Generated api from wsdl"; + } + + public String getApiVersion() { + return "1.0.0"; + } + + public String getApiPrefix() { + return "OpenApiFromWsdl"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + return infoExtensionMap; + } + + /** + addBook (POST /AddBook) + + + **/ + public static class AddBookRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { + + private final Logger coverageLogger = LoggerFactory.getLogger(AddBookRequest.class); + + // Query params + + + public AddBookRequest(){ + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("OpenApiFromWsdl".toLowerCase() + ":addBookRequestType"); + } + + public String getOperationName() { + return "addBook"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/AddBook"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + + SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); + SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport.soapAction("addBook"); + + String payload = null; + String payloadType = null; + + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + if (!CollectionUtils.isEmpty(soapHeaders)) { + for (Entry entry : soapHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), + entry.getValue()); + } + } + + if (!CollectionUtils.isEmpty(mimeHeaders)) { + for (Entry entry : mimeHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), + entry.getValue()); + } + } + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); + + soapSendMessageActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "addBook;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); + } + + + } + /** + getAllBooks (POST /GetAllBooks) + + + **/ + public static class GetAllBooksRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { + + private final Logger coverageLogger = LoggerFactory.getLogger(GetAllBooksRequest.class); + + // Query params + + + public GetAllBooksRequest(){ + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("OpenApiFromWsdl".toLowerCase() + ":getAllBooksRequestType"); + } + + public String getOperationName() { + return "getAllBooks"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/GetAllBooks"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + + SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); + SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport.soapAction("getAllBooks"); + + String payload = null; + String payloadType = null; + + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + if (!CollectionUtils.isEmpty(soapHeaders)) { + for (Entry entry : soapHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), + entry.getValue()); + } + } + + if (!CollectionUtils.isEmpty(mimeHeaders)) { + for (Entry entry : mimeHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), + entry.getValue()); + } + } + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); + + soapSendMessageActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getAllBooks;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); + } + + + } + /** + getBook (POST /GetBook) + + + **/ + public static class GetBookRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { + + private final Logger coverageLogger = LoggerFactory.getLogger(GetBookRequest.class); + + // Query params + + + public GetBookRequest(){ + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("OpenApiFromWsdl".toLowerCase() + ":getBookRequestType"); + } + + public String getOperationName() { + return "getBook"; + } + + public String getMethod() { + return "POST"; + } + + public String getPath() { + return "/GetBook"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + + SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); + SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport.soapAction("getBook"); + + String payload = null; + String payloadType = null; + + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + if (!CollectionUtils.isEmpty(soapHeaders)) { + for (Entry entry : soapHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), + entry.getValue()); + } + } + + if (!CollectionUtils.isEmpty(mimeHeaders)) { + for (Entry entry : mimeHeaders.entrySet()) { + messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), + entry.getValue()); + } + } + + Map queryParams = new HashMap<>(); + + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + + soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); + soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); + + soapSendMessageActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "getBook;POST;\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); + } + + + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java new file mode 100644 index 0000000000..e462cae9f8 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java @@ -0,0 +1,38 @@ +/** + * ================================================== + * GENERATED CLASS, ALL CHANGES WILL BE LOST + * ================================================== + */ + +package org.citrusframework.openapi.generator.soap.bookservice.spring; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; +import javax.annotation.processing.Generated; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +public class OpenApiFromWsdlBeanConfiguration { + + @Bean + @Scope(SCOPE_PROTOTYPE) + public BookServiceSoapApi.AddBookRequest addBookRequest() { + return new BookServiceSoapApi.AddBookRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public BookServiceSoapApi.GetAllBooksRequest getAllBooksRequest() { + return new BookServiceSoapApi.GetAllBooksRequest(); + } + + @Bean + @Scope(SCOPE_PROTOTYPE) + public BookServiceSoapApi.GetBookRequest getBookRequest() { + return new BookServiceSoapApi.GetBookRequest(); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd new file mode 100644 index 0000000000..c093acef11 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml new file mode 100644 index 0000000000..480e462dfe --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml @@ -0,0 +1,33 @@ +--- +info: + contact: + name: "org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer" + description: "This api has been generated from the following wsdl 'BookService.wsdl'.\ + \ It's purpose is solely to serve as input for SOAP API generation. Note that\ + \ only operations are extracted from the WSDL. No schema information whatsoever\ + \ is generated!" + title: "Generated api from wsdl" + version: "1.0.0" +openapi: "3.0.1" +paths: + /GetBook: + post: + description: "" + operationId: "GetBook" + responses: {} + tags: + - "BookServiceSOAP" + /AddBook: + post: + description: "" + operationId: "AddBook" + responses: {} + tags: + - "BookServiceSOAP" + /GetAllBooks: + post: + description: "" + operationId: "GetAllBooks" + responses: {} + tags: + - "BookServiceSOAP" \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl new file mode 100644 index 0000000000..5243c102d5 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl @@ -0,0 +1,110 @@ + + + Definition for a web service called BookService, + which can be used to add or retrieve books from a collection. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml new file mode 100644 index 0000000000..e92fd84d94 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -0,0 +1,111 @@ + + 4.0.0 + + + citrus-test-api-generator + org.citrusframework + 4.3.0-SNAPSHOT + ../pom.xml + + + citrus-test-api-generator-maven-plugin + maven-plugin + + Citrus :: Test API Generator :: Maven Plugin + Maven Plugin for generation of Citrus Test API + + + 2.2.21 + + + + + + org.apache.maven.plugins + maven-plugin-plugin + ${maven.plugin.plugin.version} + + true + + + + + + + + + org.citrusframework + citrus-test-api-generator-core + ${project.version} + + + + commons-io + commons-io + ${commons.io.version} + + + io.swagger.core.v3 + swagger-core + ${swagger.version} + + + io.swagger.core.v3 + swagger-models-jakarta + ${swagger.version} + + + org.apache.maven + maven-artifact + ${maven.version} + provided + + + org.apache.maven + maven-core + ${maven.version} + provided + + + org.apache.maven + maven-plugin-api + ${maven.version} + provided + + + org.apache.maven.plugin-tools + maven-plugin-annotations + ${maven.plugin.annotations.version} + provided + + + + + org.apache.maven + maven-compat + ${maven.version} + test + + + org.apache.maven.plugin-testing + maven-plugin-testing-harness + ${maven.plugin.testing.harness.version} + test + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.junit.jupiter + junit-jupiter-params + test + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java new file mode 100644 index 0000000000..ea92db1efb --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -0,0 +1,86 @@ +package org.citrusframework.maven.plugin; + +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; +import static java.lang.String.format; + +import org.citrusframework.openapi.generator.JavaCitrusCodegen; +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.project.MavenProject; +import org.openapitools.codegen.plugin.CodeGenMojo; + +/** + * Wrapper class that uses reflection to expose several properties of the {@link CodeGenMojo} for explicit assignment. + * + * @author Thorsten Schlathoelter + */ +public class CodeGenMojoWrapper extends CodeGenMojo { + + private final Map configOptionsProperties = new HashMap<>(); + + public CodeGenMojoWrapper() throws MojoExecutionException { + setFixedConfigOptions(); + setPrivateField("configOptions", configOptionsProperties); + } + + private void setFixedConfigOptions() throws MojoExecutionException { + setPrivateField("generateSupportingFiles", true); + setPrivateField( "generatorName", CODEGEN_NAME); + } + + public CodeGenMojoWrapper project(MavenProject mavenProject) throws MojoExecutionException { + setPrivateField("project", mavenProject); + return this; + } + + public CodeGenMojoWrapper output(File output) throws MojoExecutionException { + setPrivateField("output", output); + return this; + } + + public CodeGenMojoWrapper inputSpec(String inputSpec) throws MojoExecutionException { + setPrivateField("inputSpec", inputSpec); + return this; + } + + public CodeGenMojoWrapper mojoExecution(MojoExecution mojoExecution) throws MojoExecutionException { + setPrivateField("mojo", mojoExecution); + return this; + } + + public CodeGenMojoWrapper configOptions(Map configOptionsProperties) { + this.configOptionsProperties.putAll(configOptionsProperties); + return this; + } + + public CodeGenMojoWrapper schemaFolder(String schemaFolder) { + configOptionsProperties.put(JavaCitrusCodegen.GENERATED_SCHEMA_FOLDER, schemaFolder); + return this; + } + + public CodeGenMojoWrapper resourceFolder(String resourceFolder) { + configOptionsProperties.put(JavaCitrusCodegen.RESOURCE_FOLDER, resourceFolder); + return this; + } + + public CodeGenMojoWrapper sourceFolder(String sourceFolder) { + configOptionsProperties.put(JavaCitrusCodegen.SOURCE_FOLDER, sourceFolder); + return this; + } + + @SuppressWarnings("java:S3011") // Accessibility bypass + private void setPrivateField(String fieldName, Object fieldValue) throws MojoExecutionException { + try { + var field = CodeGenMojo.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(this, fieldValue); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new MojoExecutionException( + format("Could not reflectively set field value '%s' for field '%s'", fieldValue, fieldName)); + } + } + +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java new file mode 100644 index 0000000000..23ae7b161f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -0,0 +1,156 @@ +package org.citrusframework.maven.plugin; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; + +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.function.BiConsumer; +import org.apache.maven.plugin.MojoExecutionException; +import org.citrusframework.exceptions.CitrusRuntimeException; + +/** + * Utility class responsible for generating the Spring meta files 'spring.handlers' and 'spring.schemas', used + * in Spring integration testing. These meta files define mappings between XML namespace URIs and corresponding + * handler classes. The class provides methods to generate these meta files based on the configuration provided. + *

    + * The generated meta files can be created either in the generated folder or in the main resources folder. See + * {@link TestApiGeneratorMojo#RESOURCE_FOLDER_PROPERTY} for details. The implemented algorithm carefully updates these + * files and tries to keep non generated information unchanged. Therefore, a special segment in the namespace uri is used, namely + * {@link TestApiGeneratorMojo#CITRUS_TEST_SCHEMA}. + *

    + * + * @author Thorsten Schlathoelter + * + */ +public class SpringMetaFileGenerator { + + private final TestApiGeneratorMojo testApiGeneratorMojo; + + public SpringMetaFileGenerator(TestApiGeneratorMojo testApiGeneratorMojo) { + this.testApiGeneratorMojo = testApiGeneratorMojo; + } + + public void generateSpringIntegrationMetaFiles() throws MojoExecutionException { + + String springMetafileDirectory = format("%s/%s", testApiGeneratorMojo.getMavenProject().getBasedir(), + testApiGeneratorMojo.metaInfFolder()); + File metaFolder = new File(springMetafileDirectory); + if (!metaFolder.exists() && !metaFolder.mkdirs()) { + throw new CitrusRuntimeException( + format("Unable to create spring meta file directory: '%s'", springMetafileDirectory)); + } + + try { + writeSpringSchemaMetaFile(metaFolder); + writeSpringHandlerMetaFile(metaFolder); + } catch (MetaFileWriteException e) { + throw new MojoExecutionException(e); + } + } + + private void writeSpringSchemaMetaFile(File springMetafileDirectory) throws MojoExecutionException { + + String filename = "spring.schemas"; + writeSpringMetaFile(springMetafileDirectory, filename, (fileWriter, apiConfig) -> { + String targetXmlnsNamespace = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), + apiConfig.getVersion()); + String schemaFolderPath = TestApiGeneratorMojo.replaceDynamicVars(testApiGeneratorMojo.schemaFolder(apiConfig), apiConfig.getPrefix(), + apiConfig.getVersion()); + String schemaPath = String.format("%s/%s-api.xsd", schemaFolderPath, apiConfig.getPrefix().toLowerCase()); + appendLine(fileWriter, format("%s.xsd=%s%n", targetXmlnsNamespace.replace("http://", "http\\://"), schemaPath), filename); + }); + } + + private void writeSpringHandlerMetaFile(File springMetafileDirectory) throws MojoExecutionException { + String filename = "spring.handlers"; + writeSpringMetaFile(springMetafileDirectory, filename, (fileWriter, apiConfig) -> { + String targetXmlnsNamespace = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), + apiConfig.getVersion()); + String invokerPackage = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion()); + String namespaceHandlerClass = invokerPackage + ".citrus.extension." + apiConfig.getPrefix() + "NamespaceHandler"; + appendLine(fileWriter, format("%s=%s%n", targetXmlnsNamespace.replace("http://", "http\\://"), namespaceHandlerClass), + filename); + }); + } + + private void writeSpringMetaFile(File springMetafileDirectory, String filename, BiConsumer contentFormatter) + throws MojoExecutionException { + + File handlerFile = new File(format("%s/%s", springMetafileDirectory.getPath(), filename)); + List filteredLines = readAndFilterLines(handlerFile); + + try (FileWriter fileWriter = new FileWriter(handlerFile)) { + + for (String line : filteredLines) { + fileWriter.write(format("%s%n", line)); + } + + for (ApiConfig apiConfig : testApiGeneratorMojo.getApiConfigs()) { + contentFormatter.accept(fileWriter, apiConfig); + } + + } catch (IOException e) { + throw new MojoExecutionException("Unable to write spring meta file!", e); + } + } + + /** + * Reads the lines from the specified file and filters out lines indicating a generated test API, + * while maintaining all non-generated test API lines. This method is used to process files + * containing both generated and non-generated test APIs, allowing seamless integration and + * modification of both types of APIs in the same source files. + * + *

    + * Generated test API lines are identified by the presence of the {@code CITRUS_TEST_SCHEMA} + * string and excluded from the output of this method, while all other lines are preserved. + * This enables the algorithm to operate on files that are not purely generated, for example, + * when mixing generated with non-generated APIs in 'src/main/META-INF'. + *

    + * + * @param file the file to read and filter + * @return a list of filtered lines, excluding lines indicating a generated test API + * @throws CitrusRuntimeException if an error occurs while reading the file + */ + private static List readAndFilterLines(File file) { + + if (!file.exists()) { + return emptyList(); + } + + List filteredLines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.contains(TestApiGeneratorMojo.CITRUS_TEST_SCHEMA)) { + filteredLines.add(line); + } + } + } catch (IOException e) { + throw new CitrusRuntimeException(format("Unable to read file file: '%s'", file.getPath()), e); + } + + return filteredLines; + } + + private void appendLine(FileWriter fileWriter, String format, String filename) { + try { + fileWriter.append(format); + } catch (IOException e) { + throw new MetaFileWriteException(format("Unable to write spring meta file '%s'!", filename), e); + } + } + + private static final class MetaFileWriteException extends RuntimeException { + + public MetaFileWriteException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java new file mode 100644 index 0000000000..d5b2b1cd53 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -0,0 +1,412 @@ +package org.citrusframework.maven.plugin; + +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_ENDPOINT; +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_TYPE; +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.PREFIX; +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.TARGET_XMLNS_NAMESPACE; +import static java.lang.String.format; +import static org.apache.commons.lang3.StringUtils.isBlank; + +import com.google.common.annotations.VisibleForTesting; +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.plugins.annotations.ResolutionScope; +import org.apache.maven.project.MavenProject; +import org.openapitools.codegen.plugin.CodeGenMojo; +import org.sonatype.plexus.build.incremental.BuildContext; +import org.sonatype.plexus.build.incremental.DefaultBuildContext; + +/** + * The Citrus OpenAPI Generator Maven Plugin is designed to facilitate the integration of multiple OpenAPI specifications + * into the Citrus testing framework by automatically generating necessary test classes and XSDs. This plugin wraps the + * {@code CodeGenMojo} and extends its functionality to support multiple API configurations. + *

    + * Features: + * - Multiple API Configurations: Easily configure multiple OpenAPI specifications to generate test APIs with specific prefixes. + * - Citrus Integration: Generates classes and XSDs tailored for use within the Citrus framework, streamlining the process + * of creating robust integration tests. + *

    + * + * @author Thorsten Schlathoelter + * + */ +@Mojo( + name = "create-test-api", + defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, + requiresDependencyCollection = ResolutionScope.TEST, + requiresDependencyResolution = ResolutionScope.TEST, + threadSafe = true +) +public class TestApiGeneratorMojo extends AbstractMojo { + + public static final String DEFAULT_SOURCE_FOLDER = "generated-test-sources"; + public static final String DEFAULT_RESOURCE_FOLDER = "generated-test-resources"; + public static final String DEFAULT_BASE_PACKAGE = "org.citrusframework.automation.%PREFIX%.%VERSION%"; + public static final String DEFAULT_INVOKER_PACKAGE = DEFAULT_BASE_PACKAGE; + public static final String DEFAULT_API_PACKAGE = DEFAULT_BASE_PACKAGE+".api"; + public static final String DEFAULT_MODEL_PACKAGE = DEFAULT_BASE_PACKAGE+".model"; + public static final String DEFAULT_SCHEMA_FOLDER_TEMPLATE = "schema/xsd/%VERSION%"; + public static final ApiType DEFAULT_API_TYPE = ApiType.REST; + + /** + * Marker fragment in the schema name of a generated schema. Used to distinguish generated from non generated values, when manipulating + * spring meta-data files. + */ + public static final String CITRUS_TEST_SCHEMA = "citrus-test-schema"; + + /** + * Specifies the default target namespace template. When changing the default value, it's important to maintain the 'citrus-test-schema' + * part, as this name serves to differentiate between generated and non-generated schemas. This differentiation aids in the creation of + * supporting Spring files such as 'spring.handlers' and 'spring.schemas'. + */ + public static final String DEFAULT_TARGET_NAMESPACE_TEMPLATE = + "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; + + /** + * The default META-INF folder. Note that it points into the main resources, not generated resources, to allow for non generated + * schemas/handlers. See also {@link TestApiGeneratorMojo}#DEFAULT_TARGET_NAMESPACE_TEMPLATE. + */ + public static final String DEFAULT_META_INF_FOLDER = "target/generated-test-resources/META-INF"; + + @Component + private final BuildContext buildContext = new DefaultBuildContext(); + + @Parameter(defaultValue = "${project}", readonly = true) + private MavenProject mavenProject; + + @Parameter(defaultValue = "${mojoExecution}", readonly = true) + private MojoExecution mojoExecution; + + /** + * sourceFolder: specifies the location to which the sources are generated. Defaults to 'generated-test-sources'. + */ + public static final String SOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.source.folder"; + @Parameter(property = SOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_SOURCE_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String sourceFolder = DEFAULT_SOURCE_FOLDER; + + /** + * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-test-resources'. + */ + public static final String RESOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.resource.folder"; + @Parameter(property = RESOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_RESOURCE_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String resourceFolder = DEFAULT_RESOURCE_FOLDER; + + /** + * schemaFolder: specifies the location for the generated xsd schemas. Defaults to 'schema/xsd/%VERSION%' + */ + public static final String API_SCHEMA_FOLDER = "citrus.test.api.generator.schema.folder"; + @Parameter(property = API_SCHEMA_FOLDER, defaultValue = DEFAULT_SCHEMA_FOLDER_TEMPLATE) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String schemaFolder = DEFAULT_SCHEMA_FOLDER_TEMPLATE; + + /** + * metaInfFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. + */ + public static final String META_INF_FOLDER = "citrus.test.api.generator.meta.inf.folder"; + @Parameter(property = META_INF_FOLDER, defaultValue = DEFAULT_META_INF_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String metaInfFolder = DEFAULT_META_INF_FOLDER; + + /** + * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. + */ + public static final String GENERATE_SPRING_INTEGRATION_FILES = "citrus.test.api.generator.generate.spring.integration.files"; + @Parameter(property = GENERATE_SPRING_INTEGRATION_FILES, defaultValue = "true") + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private boolean generateSpringIntegrationFiles = true; + + @Parameter + private List apis; + + protected MavenProject getMavenProject() { + return mavenProject; + } + + protected void setMavenProject(MavenProject mavenProject) { + this.mavenProject = mavenProject; + } + + public List getApiConfigs() { + return apis; + } + + public String metaInfFolder() { + return metaInfFolder; + } + + @VisibleForTesting + void setMojoExecution(MojoExecution mojoExecution) { + this.mojoExecution = mojoExecution; + } + + /** + * Returns the fully qualified schema folder + */ + public String schemaFolder(ApiConfig apiConfig) { + return replaceDynamicVars(schemaFolder, apiConfig.getPrefix(), apiConfig.getVersion()); + } + + @Override + public void execute() throws MojoExecutionException { + + for (int index = 0; index < apis.size(); index++) { + ApiConfig apiConfig = apis.get(index); + validateApiConfig(index, apiConfig); + CodeGenMojo codeGenMojo = configureCodeGenMojo(apiConfig); + codeGenMojo.execute(); + } + + if (generateSpringIntegrationFiles) { + new SpringMetaFileGenerator(this).generateSpringIntegrationMetaFiles(); + } + } + + CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionException { + CodeGenMojo codeGenMojo = new CodeGenMojoWrapper() + .resourceFolder(resourceFolder) + .sourceFolder(sourceFolder) + .schemaFolder(schemaFolder(apiConfig)) + .output(new File(mavenProject.getBuild().getDirectory())) + .mojoExecution(mojoExecution) + .project(mavenProject) + .inputSpec(apiConfig.getSource()) + .configOptions(apiConfig.toConfigOptionsProperties()); + + codeGenMojo.setPluginContext(getPluginContext()); + codeGenMojo.setBuildContext(buildContext); + return codeGenMojo; + } + + private void validateApiConfig(int apiIndex, ApiConfig apiConfig) throws MojoExecutionException { + requireNonBlankParameter("prefix", apiIndex, apiConfig.getPrefix()); + requireNonBlankParameter("source", apiIndex, apiConfig.getSource()); + } + + private void requireNonBlankParameter(String name, int index, String parameterValue) throws MojoExecutionException { + if (isBlank(parameterValue)) { + throw new MojoExecutionException(format("Required parameter '%s' not set for api at index '%d'!", name, index)); + } + } + + /** + * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text. + */ + static String replaceDynamicVars(String text, String prefix, String version) { + + if (text == null) { + return null; + } + + return text.replace("%PREFIX%", prefix) + .replace(".%VERSION%", version != null ? "." + version : "") + .replace("/%VERSION%", version != null ? "/" + version : "") + .replace("-%VERSION%", version != null ? "-" + version : "") + .replace("%VERSION%", version != null ? version : ""); + } + + /** + * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text, performing a toLowerCase on the prefix. + */ + static String replaceDynamicVarsToLowerCase(String text, String prefix, String version) { + return replaceDynamicVars(text, prefix.toLowerCase(), version); + } + + public enum ApiType { + REST, SOAP + } + + /** + * Note that the default values are not properly set by maven processor. Therefore, the default values have been assigned additionally + * on field level. + */ + public static class ApiConfig { + + public static final String DEFAULT_ENDPOINT = "PREFIX_ENDPOINT"; + + /** + * prefix: specifies the prefixed used for the test api. Typically, an acronym for the application which is being tested. + */ + public static final String API_PREFIX_PROPERTY = "citrus.test.api.generator.prefix"; + @Parameter(required = true, property = API_PREFIX_PROPERTY) + private String prefix; + + /** + * source: specifies the source of the test api. + */ + public static final String API_SOURCE_PROPERTY = "citrus.test.api.generator.source"; + @Parameter(required = true, property = API_SOURCE_PROPERTY) + private String source; + + /** + * version: specifies the version of the api. May be null. + */ + public static final String API_VERSION_PROPERTY = "citrus.test.api.generator.version"; + @Parameter(property = API_VERSION_PROPERTY) + private String version; + + /** + * endpoint: specifies the endpoint of the test api. Defaults to 'prefixEndpoint'. + */ + public static final String API_ENDPOINT_PROPERTY = "citrus.test.api.generator.endpoint"; + @Parameter(property = API_ENDPOINT_PROPERTY, defaultValue = DEFAULT_ENDPOINT) + private String endpoint = DEFAULT_ENDPOINT; + + /** + * type: specifies the type of the test api. Defaults to 'REST' + */ + public static final String API_TYPE_PROPERTY = "citrus.test.api.generator.type"; + @Parameter(property = API_TYPE_PROPERTY, defaultValue = "REST") + private ApiType type = DEFAULT_API_TYPE; + + /** + * useTags: specifies whether tags should be used by the generator. Defaults to 'true'. If useTags is set to true, the generator + * will organize the generated code based on the tags defined in your API specification. + */ + public static final String API_USE_TAGS_PROPERTY = "citrus.test.api.generator.use.tags"; + @Parameter(property = API_USE_TAGS_PROPERTY, defaultValue = "true") + private boolean useTags = true; + + /** + * invokerPackage: specifies the package for the test api classes. Defaults to + * 'org.citrusframework.automation.%PREFIX%.%VERSION%'. + */ + public static final String API_INVOKER_PACKAGE_PROPERTY = "citrus.test.api.generator.invoker.package"; + @Parameter(property = API_INVOKER_PACKAGE_PROPERTY, defaultValue = DEFAULT_INVOKER_PACKAGE) + private String invokerPackage = DEFAULT_INVOKER_PACKAGE; + + /** + * apiPackage: specifies the package for the test api classes. Defaults to + * 'org.citrusframework.automation.%PREFIX%.%VERSION%.api'. + */ + public static final String API_API_PACKAGE_PROPERTY = "citrus.test.api.generator.api.package"; + @Parameter(property = API_API_PACKAGE_PROPERTY, defaultValue = DEFAULT_API_PACKAGE) + private String apiPackage = DEFAULT_API_PACKAGE; + + /** + * modelPackage: specifies the package for the test api classes. Defaults to + * 'org.citrusframework.automation.%PREFIX%.%VERSION%.model'. + */ + public static final String API_MODEL_PACKAGE_PROPERTY = "citrus.test.api.generator.model.package"; + @Parameter(property = API_MODEL_PACKAGE_PROPERTY, defaultValue = DEFAULT_MODEL_PACKAGE) + private String modelPackage = DEFAULT_MODEL_PACKAGE; + + /** + * targetXmlNamespace: specifies the xml namespace to be used by the api. Defaults to + * 'http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api' + */ + @SuppressWarnings("JavadocLinkAsPlainText") + public static final String API_NAMESPACE_PROPERTY = "citrus.test.api.generator.namespace"; + @Parameter(property = API_NAMESPACE_PROPERTY, defaultValue = DEFAULT_TARGET_NAMESPACE_TEMPLATE) + private String targetXmlnsNamespace = DEFAULT_TARGET_NAMESPACE_TEMPLATE; + + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String qualifiedEndpoint() { + return DEFAULT_ENDPOINT.equals(endpoint) ? getPrefix().toLowerCase() + "Endpoint" : endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public ApiType getType() { + return type; + } + + public void setType(ApiType type) { + this.type = type; + } + + public void setUseTags(boolean useTags) { + this.useTags = useTags; + } + + public String getInvokerPackage() { + return invokerPackage; + } + + public void setInvokerPackage(String invokerPackage) { + this.invokerPackage = invokerPackage; + } + + public String getApiPackage() { + return apiPackage; + } + + public void setApiPackage(String apiPackage) { + this.apiPackage = apiPackage; + } + + public String getModelPackage() { + return modelPackage; + } + + public void setModelPackage(String modelPackage) { + this.modelPackage = modelPackage; + } + + public String getTargetXmlnsNamespace() { + return targetXmlnsNamespace; + } + + public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { + this.targetXmlnsNamespace = targetXmlnsNamespace; + } + + Map toConfigOptionsProperties() { + + Map configOptionsProperties = new HashMap<>(); + configOptionsProperties.put(PREFIX, prefix); + configOptionsProperties.put(API_ENDPOINT, qualifiedEndpoint()); + configOptionsProperties.put(API_TYPE, type.toString()); + configOptionsProperties.put(TARGET_XMLNS_NAMESPACE, + replaceDynamicVarsToLowerCase(targetXmlnsNamespace, prefix, version)); + configOptionsProperties.put("invokerPackage", + replaceDynamicVarsToLowerCase(invokerPackage, prefix, version)); + configOptionsProperties.put("apiPackage", + replaceDynamicVarsToLowerCase(apiPackage, prefix, version)); + configOptionsProperties.put("modelPackage", + replaceDynamicVarsToLowerCase(modelPackage, prefix, version)); + configOptionsProperties.put("useTags", useTags); + + return configOptionsProperties; + } + + } + + +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java new file mode 100644 index 0000000000..d4bcc740b9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -0,0 +1,314 @@ +package org.citrusframework.maven.plugin; + +import static com.google.common.collect.Streams.concat; +import static java.lang.Boolean.TRUE; +import static java.util.Arrays.stream; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.springframework.test.util.ReflectionTestUtils.getField; + +import jakarta.validation.constraints.NotNull; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.apache.maven.project.MavenProject; +import org.assertj.core.api.Assertions; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.exceptions.TestCaseFailedException; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiType; +import org.citrusframework.maven.plugin.stubs.CitrusOpenApiGeneratorMavenProjectStub; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +/** + * @author Thorsten Schlathoelter + */ +class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { + + public static final String OTHER_META_FILE_CONTENT = "somenamespace=somevalue"; + + public static final String OTHER_CITRUS_META_FILE_CONTENT = String.format("somenamespace/%s/aa=somevalue", CITRUS_TEST_SCHEMA); + + /** + * Array containing path templates for each generated file, specified with tokens. Tokens can be replaced with values of the respective + * testing scenario. + */ + private static final String[] STANDARD_FILE_PATH_TEMPLATES = new String[]{ + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/extension/%CAMEL_PREFIX%NamespaceHandler.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/%CAMEL_PREFIX%AbstractTestRequest.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/%CAMEL_PREFIX%BeanDefinitionParser.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%BeanConfiguration.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingReqType.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingRespType.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PingApi.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PungApi.java", + "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%SCHEMA_FOLDER%/%LOWER_PREFIX%-api.xsd", + "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%LOWER_PREFIX%-api-model.csv" + }; + + /** + * Array containing path templates for each generated spring meta file, specified with tokens. Tokens can be replaced with values of the respective + * testing scenario. + */ + private static final String[] SPRING_META_FILE_TEMPLATES = new String[]{ + "%BASE_FOLDER%/%META_INF_FOLDER%/spring.handlers", + "%BASE_FOLDER%/%META_INF_FOLDER%/spring.schemas" + }; + + private TestApiGeneratorMojo fixture; + + @BeforeEach + @SuppressWarnings("JUnitMixedFramework") + void beforeEachSetup() throws Exception { + setUp(); + } + + static Stream executeMojoWithConfigurations() { + return Stream.of( + arguments("pom-missing-prefix", + new MojoExecutionException("Required parameter 'prefix' not set for api at index '0'!")), + arguments("pom-missing-source", + new MojoExecutionException("Required parameter 'source' not set for api at index '0'!")), + arguments("pom-minimal-config", null), + arguments("pom-minimal-with-version-config", null), + arguments("pom-multi-config", null), + arguments("pom-full-config", null), + arguments("pom-full-with-version-config", null), + arguments("pom-soap-config", null) + ); + } + + @ParameterizedTest + @MethodSource + void executeMojoWithConfigurations(String configName, Exception expectedException) + throws Exception { + + try { + fixture = fixtureFromPom(configName); + } catch (MojoExecutionException | MojoFailureException e) { + Assertions.fail("Test setup failed!", e); + } + + @SuppressWarnings("unchecked") + List apiConfigs = (List) getField(fixture, "apis"); + + assertThat(apiConfigs).isNotNull(); + + if (expectedException == null) { + // Given + writeSomeValuesToSpringMetaFiles(apiConfigs); + + // When + assertThatCode(() -> fixture.execute()).doesNotThrowAnyException(); + + // Then + for (ApiConfig apiConfig : apiConfigs) { + assertFilesGenerated(apiConfig); + assertSpecificFileContent(apiConfig); + } + } else { + // When/Then + assertThatThrownBy(() -> fixture.execute()).isInstanceOf(expectedException.getClass()) + .hasMessage(expectedException.getMessage()); + } + } + + /** + * Writes values to spring meta files, to make sure existing non generated and existing generated values are treated properly. + */ + private void writeSomeValuesToSpringMetaFiles(List apiConfigs) { + for (ApiConfig apiConfig : apiConfigs) { + for (String filePathTemplate : SPRING_META_FILE_TEMPLATES) { + + String filePath = resolveFilePath(apiConfig, filePathTemplate); + File file = new File(filePath); + if (!file.getParentFile().exists() && !new File(filePath).getParentFile().mkdirs()) { + Assertions.fail("Unable to prepare test data."); + } + + try (FileWriter fileWriter = new FileWriter(filePath)) { + fileWriter.append(String.format("%s%n", OTHER_META_FILE_CONTENT)); + fileWriter.append(String.format("%s%n", OTHER_CITRUS_META_FILE_CONTENT)); + } catch (IOException e) { + throw new CitrusRuntimeException("Unable to write spring meta files", e); + } + } + } + } + + private void assertFilesGenerated(ApiConfig apiConfig) { + + for (String filePathTemplate : STANDARD_FILE_PATH_TEMPLATES) { + String filePath = resolveFilePath(apiConfig, filePathTemplate); + assertThat(new File(filePath)).isFile().exists(); + } + + if (TRUE.equals(getField(fixture, "generateSpringIntegrationFiles"))) { + for (String filePathTemplate : SPRING_META_FILE_TEMPLATES) { + String filePath = resolveFilePath(apiConfig, filePathTemplate); + assertThat(new File(filePath)).isFile().exists(); + } + } + } + + private void assertSpecificFileContent(ApiConfig apiConfig) { + try { + assertEndpointName(apiConfig); + assertTargetNamespace(apiConfig); + assertApiType(apiConfig); + assertSchemasInSpringSchemas(apiConfig); + assertHandlersInSpringHandlers(apiConfig); + } catch (IOException e) { + throw new TestCaseFailedException(e); + } + } + + private void assertHandlersInSpringHandlers(ApiConfig apiConfig) throws IOException { + String targetNamespace = replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()); + targetNamespace = targetNamespace.replace(":", "\\:"); + String invokerPackage = replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion()); + + String text = String.format("%s=%s.citrus.extension.%sNamespaceHandler", targetNamespace, invokerPackage, apiConfig.getPrefix()); + + assertThat(getContentOfFile(apiConfig, "spring.handlers")).contains(text); + + // Other specific meta info should be retained + assertThat(getContentOfFile(apiConfig, "spring.handlers")).contains(OTHER_META_FILE_CONTENT); + // Other citrus generated meta info should be deleted + assertThat(getContentOfFile(apiConfig, "spring.handlers")).doesNotContain(OTHER_CITRUS_META_FILE_CONTENT); + } + + private void assertSchemasInSpringSchemas(ApiConfig apiConfig) throws IOException { + + String targetNamespace = replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()); + targetNamespace = targetNamespace.replace(":", "\\:"); + String schemaPath = replaceDynamicVarsToLowerCase((String)getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion()); + + String text = String.format("%s.xsd=%s/%s-api.xsd", targetNamespace, schemaPath, apiConfig.getPrefix().toLowerCase()); + + // Other specific meta info should be retained assertThat(getContentOfFile(apiConfig, "spring.schemas")).contains(OTHER_META_FILE_CONTENT); + assertThat(getContentOfFile(apiConfig, "spring.schemas")).contains(String.format("%s", text)); + // Other citrus generated meta info should be deleted + assertThat(getContentOfFile(apiConfig, "spring.schemas")).doesNotContain(OTHER_CITRUS_META_FILE_CONTENT); + } + + private void assertApiType(ApiConfig apiConfig) throws IOException { + String text; + switch (apiConfig.getType()) { + case REST -> text = "HttpClient httpClient"; + case SOAP -> text = "WebServiceClient wsClient"; + default -> throw new IllegalArgumentException(String.format("No apiTye set in ApiConfig. Expected one of %s", + stream(ApiType.values()).map(ApiType::toString).collect( + Collectors.joining()))); + } + assertThat(getContentOfFile(apiConfig, "AbstractTestRequest.java")).contains(text); + } + + private void assertTargetNamespace(ApiConfig apiConfig) throws IOException { + assertThat(getContentOfFile(apiConfig, "-api.xsd")).contains( + String.format("targetNamespace=\"%s\"", + replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()))); + } + + private void assertEndpointName(ApiConfig apiConfig) throws IOException { + assertThat(getContentOfFile(apiConfig, "AbstractTestRequest")).contains( + String.format("@Qualifier(\"%s\")", apiConfig.qualifiedEndpoint())); + } + + private String getContentOfFile(ApiConfig apiConfig, String fileIdentifier) throws IOException { + String filePathTemplate = getTemplateContaining(fileIdentifier); + String filePath = resolveFilePath(apiConfig, filePathTemplate); + + File file = new File(filePath); + + assertThat(file).exists(); + Path path = Paths.get(filePath); + byte[] bytes = Files.readAllBytes(path); + return new String(bytes, StandardCharsets.UTF_8); + } + + private String getTemplateContaining(String text) { + return concat(stream(STANDARD_FILE_PATH_TEMPLATES), stream(SPRING_META_FILE_TEMPLATES)) + .filter(path -> path.contains(text)).findFirst() + .orElseThrow(() -> new AssertionError(String.format("Can't find file template with content: '%s'", text))); + } + + @NotNull + private String resolveFilePath(ApiConfig apiConfig, String filePathTemplate) { + + String lowerCasePrefix = apiConfig.getPrefix().toLowerCase(); + char[] prefixCharArray = apiConfig.getPrefix().toCharArray(); + prefixCharArray[0] = Character.toUpperCase(prefixCharArray[0]); + String camelCasePrefix = new String(prefixCharArray); + + String invokerFolder = toFolder( + replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + String modelFolder = toFolder( + replaceDynamicVarsToLowerCase(apiConfig.getModelPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + String requestFolder = toFolder( + replaceDynamicVarsToLowerCase(apiConfig.getApiPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + String schemaFolder = toFolder( + replaceDynamicVars((String)getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + String generatedSourcesFolder = toFolder( + replaceDynamicVars((String)getField(fixture, "sourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + String generatedResourcesFolder = toFolder( + replaceDynamicVars((String)getField(fixture, "resourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + + return filePathTemplate + .replace("%BASE_FOLDER%", fixture.getMavenProject().getBasedir().getPath()) + .replace("%TARGET_FOLDER%", fixture.getMavenProject().getBuild().getDirectory()) + .replace("%SOURCE_FOLDER%", fixture.getMavenProject().getBuild().getSourceDirectory()) + .replace("%GENERATED_SOURCES_FOLDER%", generatedSourcesFolder) + .replace("%GENERATED_RESOURCES_FOLDER%", generatedResourcesFolder) + .replace("%INVOKER_FOLDER%", invokerFolder) + .replace("%MODEL_FOLDER%", modelFolder) + .replace("%REQUEST_FOLDER%", requestFolder) + .replace("%SCHEMA_FOLDER%", schemaFolder) + .replace("%LOWER_PREFIX%", lowerCasePrefix) + .replace("%CAMEL_PREFIX%", camelCasePrefix) + .replace("%META_INF_FOLDER%", toFolder((String) getField(fixture, "metaInfFolder"))); + } + + private String toFolder(String text) { + + if (text == null) { + return ""; + } + + return text.replace(".", "/"); + } + + private TestApiGeneratorMojo fixtureFromPom(String configName) throws Exception { + String goal = "create-test-api"; + + File pomFile = new File(getBasedir(), String.format("src/test/resources/%s/%s", getClass().getSimpleName(), configName + ".xml")); + assertThat(pomFile).exists(); + + MavenProject mavenProject = new CitrusOpenApiGeneratorMavenProjectStub(configName); + + TestApiGeneratorMojo testApiGeneratorMojo = (TestApiGeneratorMojo) lookupMojo(goal, pomFile); + testApiGeneratorMojo.setMavenProject(mavenProject); + testApiGeneratorMojo.setMojoExecution(newMojoExecution(goal)); + + return testApiGeneratorMojo; + } + +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java new file mode 100644 index 0000000000..c63753525f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -0,0 +1,286 @@ +package org.citrusframework.maven.plugin; + +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_TYPE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_INVOKER_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_META_INF_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_MODEL_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_RESOURCE_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SCHEMA_FOLDER_TEMPLATE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SOURCE_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_TARGET_NAMESPACE_TEMPLATE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; +import static java.lang.Boolean.TRUE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.doReturn; +import static org.springframework.test.util.ReflectionTestUtils.getField; + +import jakarta.validation.constraints.NotNull; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiType; +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; +import org.apache.maven.model.Build; +import org.apache.maven.plugin.MojoExecution; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.testing.AbstractMojoTestCase; +import org.apache.maven.project.MavenProject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.openapitools.codegen.plugin.CodeGenMojo; + + +/** + * @author Thorsten Schlathoelter + */ +@ExtendWith(MockitoExtension.class) +@SuppressWarnings({"JUnitMalformedDeclaration", "JUnitMixedFramework"}) +class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase { + + private TestApiGeneratorMojo fixture; + + @Mock + private Build buildMock; + + @Mock + private MavenProject mavenProjectMock; + + @Mock + private MojoExecution mojoExecutionMock; + + @BeforeEach + void beforeEach() { + fixture = new TestApiGeneratorMojo(); + } + + static Stream replaceDynamicVarsInPattern() { + return Stream.of( + arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", "1", false, "MyPrefix-aa-1"), + arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", null, false, "MyPrefix-aa"), + arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", "1", false, "MyPrefix/aa/1"), + arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", null, false, "MyPrefix/aa"), + arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", "1", true, "myprefix.aa.1"), + arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", null, true, "myprefix.aa") + ); + } + + @ParameterizedTest + @MethodSource + void replaceDynamicVarsInPattern(String pattern, String prefix, String version, boolean toLowerCasePrefix, String expectedResult) { + + if (toLowerCasePrefix) { + assertThat( + replaceDynamicVarsToLowerCase(pattern, prefix, version)).isEqualTo(expectedResult); + } else { + assertThat( + replaceDynamicVars(pattern, prefix, version)).isEqualTo(expectedResult); + } + } + + static Stream configureMojo() { + return Stream.of( + arguments("DefaultConfigWithoutVersion", createMinimalApiConfig(null), + createMinimalCodeGenMojoParams( + "schema/xsd", + "org.citrusframework.automation.mydefaultprefix", + "org.citrusframework.automation.mydefaultprefix.model", + "org.citrusframework.automation.mydefaultprefix.api", + "http://www.citrusframework.org/citrus-test-schema/mydefaultprefix-api" + )), + arguments("DefaultConfigWithVersion", createMinimalApiConfig("v1"), + createMinimalCodeGenMojoParams( + "schema/xsd/v1", + "org.citrusframework.automation.mydefaultprefix.v1", + "org.citrusframework.automation.mydefaultprefix.v1.model", + "org.citrusframework.automation.mydefaultprefix.v1.api", + "http://www.citrusframework.org/citrus-test-schema/v1/mydefaultprefix-api" + )), + arguments("CustomConfigWithoutVersion", createFullApiConfig(null), + createCustomCodeGenMojoParams( + "schema/xsd", + "my.mycustomprefix.invoker.package", + "my.mycustomprefix.model.package", + "my.mycustomprefix.api.package", + "myNamespace/citrus-test-schema/mycustomprefix" + )), + arguments("CustomConfigWithVersion", createFullApiConfig("v1"), + createCustomCodeGenMojoParams( + "schema/xsd/v1", + "my.mycustomprefix.v1.invoker.package", + "my.mycustomprefix.v1.model.package", + "my.mycustomprefix.v1.api.package", + "myNamespace/citrus-test-schema/mycustomprefix/v1" + )) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource + void configureMojo(String name, ApiConfig apiConfig, CodeGenMojoParams controlParams) throws MojoExecutionException { + doReturn("target").when(buildMock).getDirectory(); + doReturn(buildMock).when(mavenProjectMock).getBuild(); + fixture.setMavenProject(mavenProjectMock); + fixture.setMojoExecution(mojoExecutionMock); + + CodeGenMojo codeGenMojo = fixture.configureCodeGenMojo(apiConfig); + assertThat(getField(codeGenMojo, "project")).isEqualTo(mavenProjectMock); + assertThat(getField(codeGenMojo, "mojo")).isEqualTo(mojoExecutionMock); + assertThat(((File) getField(codeGenMojo, "output"))).hasName(controlParams.output); + assertThat(getField(codeGenMojo, "inputSpec")).isEqualTo(controlParams.source); + assertThat(getField(codeGenMojo, "generateSupportingFiles")).isEqualTo(TRUE); + assertThat(getField(codeGenMojo, "generatorName")).isEqualTo("java-citrus"); + + //noinspection unchecked + assertThat((Map)getField(codeGenMojo, "configOptions")) + .containsExactlyInAnyOrderEntriesOf(controlParams.configOptions); + } + + /** + * Create an {@link ApiConfig} with the minimal configuration, that is required. All other values will be chosen as defaults. + */ + @NotNull + private static ApiConfig createMinimalApiConfig(String version) { + ApiConfig apiConfig = new ApiConfig(); + apiConfig.setPrefix("MyDefaultPrefix"); + apiConfig.setSource("myDefaultSource"); + apiConfig.setVersion(version); + + return apiConfig; + } + + /** + * Create an {@link ApiConfig} with all possible configurations, no defaults. + */ + @NotNull + private static ApiConfig createFullApiConfig(String version) { + ApiConfig apiConfig = new ApiConfig(); + apiConfig.setPrefix("MyCustomPrefix"); + apiConfig.setSource("myCustomSource"); + apiConfig.setApiPackage("my.%PREFIX%.%VERSION%.api.package"); + apiConfig.setInvokerPackage("my.%PREFIX%.%VERSION%.invoker.package"); + apiConfig.setModelPackage("my.%PREFIX%.%VERSION%.model.package"); + apiConfig.setEndpoint("myEndpoint"); + apiConfig.setTargetXmlnsNamespace("myNamespace/citrus-test-schema/%PREFIX%/%VERSION%"); + apiConfig.setUseTags(false); + apiConfig.setType(ApiType.SOAP); + apiConfig.setVersion(version); + + return apiConfig; + } + + @NotNull + private static CodeGenMojoParams createMinimalCodeGenMojoParams(String schemaFolder, String invokerPackage, String modelPackage, String apiPackage, String targetXmlnsNamespace) { + + Map configOptionsControlMap = new HashMap<>(); + configOptionsControlMap.put("prefix", "MyDefaultPrefix"); + configOptionsControlMap.put("generatedSchemaFolder", schemaFolder); + configOptionsControlMap.put("invokerPackage", invokerPackage); + configOptionsControlMap.put("apiPackage", apiPackage); + configOptionsControlMap.put("modelPackage", modelPackage); + configOptionsControlMap.put("resourceFolder", "generated-test-resources"); + configOptionsControlMap.put("sourceFolder", "generated-test-sources"); + configOptionsControlMap.put("apiEndpoint", "mydefaultprefixEndpoint"); + configOptionsControlMap.put("targetXmlnsNamespace", targetXmlnsNamespace); + configOptionsControlMap.put("apiType", "REST"); + configOptionsControlMap.put("useTags", true); + + return new CodeGenMojoParams("target", "myDefaultSource", configOptionsControlMap); + } + + @NotNull + private static CodeGenMojoParams createCustomCodeGenMojoParams(String schemaFolder, String invokerPackage, String modelPackage, String apiPackage, String targetXmlnsNamespace) { + + Map configOptionsControlMap = new HashMap<>(); + configOptionsControlMap.put("prefix", "MyCustomPrefix"); + configOptionsControlMap.put("generatedSchemaFolder", schemaFolder); + configOptionsControlMap.put("invokerPackage", invokerPackage); + configOptionsControlMap.put("modelPackage", modelPackage); + configOptionsControlMap.put("apiPackage", apiPackage); + configOptionsControlMap.put("resourceFolder", "generated-test-resources"); + configOptionsControlMap.put("sourceFolder", "generated-test-sources"); + configOptionsControlMap.put("apiEndpoint", "myEndpoint"); + configOptionsControlMap.put("targetXmlnsNamespace", targetXmlnsNamespace); + configOptionsControlMap.put("apiType", "SOAP"); + configOptionsControlMap.put("useTags", false); + + return new CodeGenMojoParams("target", "myCustomSource", configOptionsControlMap); + } + + @Nested + class ApiConfigTest { + + private ApiConfig configFixture; + + @BeforeEach + void beforeEach() { + configFixture = new ApiConfig(); + } + + @Test + void apiPackagePathDefault() { + assertThat(configFixture.getApiPackage()).isEqualTo(DEFAULT_API_PACKAGE); + } + + @Test + void invokerPackagePathDefault() { + assertThat(configFixture.getInvokerPackage()).isEqualTo(DEFAULT_INVOKER_PACKAGE); + } + + @Test + void modelPackagePathDefault() { + assertThat(configFixture.getModelPackage()).isEqualTo(DEFAULT_MODEL_PACKAGE); + } + + @Test + void targetXmlnsNamespaceDefault() { + assertThat(configFixture.getTargetXmlnsNamespace()).isEqualTo(DEFAULT_TARGET_NAMESPACE_TEMPLATE); + } + + @Test + void endpointDefault() { + configFixture.setPrefix("MyPrefix"); + assertThat(configFixture.qualifiedEndpoint()).isEqualTo("myprefixEndpoint"); + } + + @Test + void apiTypeDefault() { + assertThat(configFixture.getType()).isEqualTo(DEFAULT_API_TYPE); + } + + @Test + void schemaFolderDefault() { + assertThat((String)getField(fixture, "schemaFolder")).isEqualTo(DEFAULT_SCHEMA_FOLDER_TEMPLATE); + } + + @Test + void sourceFolderDefault() { + assertThat((String) getField(fixture, "sourceFolder")).isEqualTo(DEFAULT_SOURCE_FOLDER); + } + + @Test + void resourceFolderDefault() { + assertThat((String) getField(fixture, "resourceFolder")).isEqualTo(DEFAULT_RESOURCE_FOLDER); + } + + @Test + void metaInfFolderDefault() { + assertThat((String) getField(fixture, "metaInfFolder")).isEqualTo(DEFAULT_META_INF_FOLDER); + } + } + + private record CodeGenMojoParams(String output, String source, Map configOptions) { + + } +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java new file mode 100644 index 0000000000..94345c88ad --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java @@ -0,0 +1,42 @@ +package org.citrusframework.maven.plugin.stubs; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import org.apache.maven.model.Build; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.plugin.testing.stubs.MavenProjectStub; +import org.codehaus.plexus.PlexusTestCase; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +public class CitrusOpenApiGeneratorMavenProjectStub extends MavenProjectStub { + + private final String config; + + public CitrusOpenApiGeneratorMavenProjectStub(String config) { + this.config = config; + initModel(); + initBuild(); + } + + private void initBuild() { + Build build = new Build(); + build.setDirectory(getBasedir() + "/target"); + build.setSourceDirectory(getBasedir() + "/src"); + setBuild(build); + } + + private void initModel() { + MavenXpp3Reader reader = new MavenXpp3Reader(); + try { + setModel(reader.read(new FileReader("pom.xml"))); + } catch (IOException | XmlPullParserException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public File getBasedir() { + return new File(PlexusTestCase.getBasedir() + "/target/" + config); + } +} diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml new file mode 100644 index 0000000000..97fcd85dd4 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml @@ -0,0 +1,42 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + + org.mypackage.%PREFIX%.api + myEndpoint + org.mypackage.%PREFIX%.invoker + org.mypackage.%PREFIX%.model + Full + api/test-api.yml + "http://myNamespace" + + + generated-sources-mod + generated-resources-mod + myschema/xsd + main-mod/resources-mod/META-INF-MOD + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml new file mode 100644 index 0000000000..401ea5fa50 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml @@ -0,0 +1,42 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + + org.mypackage.%PREFIX%.api + myEndpoint + org.mypackage.%PREFIX%.invoker + org.mypackage.%PREFIX%.model + FullWithVersion + api/test-api.yml + "http://myNamespace" + v1 + + + generated-sources-mod + generated-resources-mod + myschema/xsd + main-mod/resources-mod/META-INF-MOD + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-config.xml new file mode 100644 index 0000000000..ffb294db1d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-config.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + minimal-config + + + + + citrus-test-api-generator-maven-plugin + + + + Minimal + api/test-api.yml + + + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-with-version-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-with-version-config.xml new file mode 100644 index 0000000000..90ee2d6e4d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-minimal-with-version-config.xml @@ -0,0 +1,33 @@ + + 4.0.0 + + minimal-config + + + + + citrus-test-api-generator-maven-plugin + + + + MinimalWithVersion + api/test-api.yml + v2 + + + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-prefix.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-prefix.xml new file mode 100644 index 0000000000..fbdd07bd0d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-prefix.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + missing-prefix + + + + + citrus-test-api-generator-maven-plugin + + + + mySource + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-source.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-source.xml new file mode 100644 index 0000000000..03f9f49074 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-missing-source.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + missing-source + + + + + citrus-test-api-generator-maven-plugin + + + + MissingSource + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-multi-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-multi-config.xml new file mode 100644 index 0000000000..f71d499ba4 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-multi-config.xml @@ -0,0 +1,40 @@ + + 4.0.0 + + multi-config + + + + + citrus-test-api-generator-maven-plugin + + + + Multi1 + api/test-api.yml + + + Multi2 + api/test-api.yml + + + Multi3 + api/test-api.yml + + + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-config.xml new file mode 100644 index 0000000000..434de65370 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-config.xml @@ -0,0 +1,33 @@ + + 4.0.0 + + soap-config + + + + + citrus-test-api-generator-maven-plugin + + + + Minimal + api/test-api.yml + SOAP + + + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/test-api.yml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/test-api.yml new file mode 100644 index 0000000000..eea3f01335 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/test-api.yml @@ -0,0 +1,125 @@ +openapi: 3.0.3 +info: + title: Schema Test API + version: 1.0.0 + description: | + A very simple test OpenAPI specification that is compliant with the random response generator (e.g. only contains responses of + media-type `application/json`). + +servers: + - url: http://localhost:9000/services/rest/ping/v1 + - url: http://localhost:9000/ping/v1 + +paths: + /ping/{id}: + put: + tags: + - ping + summary: Do the ping + operationId: doPing + parameters: + - name: id + in: path + description: Id to ping + required: true + explode: true + schema: + type: integer + format: int64 + - name: q1 + in: query + description: Some queryParameter + required: true + explode: true + schema: + type: integer + format: int64 + - name: api_key + in: header + required: true + schema: + type: string + requestBody: + description: ping data + content: + application/json: + schema: + $ref: '#/components/schemas/PingReqType' + required: true + responses: + 200: + description: successful operation + headers: + Ping-Time: + required: false + description: response time + schema: + type: integer + format: int64 + content: + application/json: + schema: + $ref: '#/components/schemas/PingRespType' + 201: + description: successful operation + headers: + Ping-Time: + required: false + description: response time + schema: + type: integer + format: int64 + content: + application/xml: + schema: + $ref: '#/components/schemas/PingRespType' + application/json: + schema: + $ref: '#/components/schemas/PingRespType' + 400: + description: Some error + content: + text/plain: + schema: + type: string + /pung/{id}: + get: + tags: + - pung + summary: Do the pung + operationId: doPung + parameters: + - name: id + in: path + description: Id to pung + required: true + explode: true + schema: + type: integer + format: int64 + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/PingRespType' + 400: + description: Invalid status value + content: {} +components: + schemas: + PingReqType: + type: object + properties: + id: + type: integer + format: int64 + PingRespType: + type: object + properties: + id: + type: integer + format: int64 + value: + type: string diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml new file mode 100644 index 0000000000..f6298e3e11 --- /dev/null +++ b/test-api-generator/pom.xml @@ -0,0 +1,37 @@ + + 4.0.0 + + + org.citrusframework + citrus + 4.3.0-SNAPSHOT + ../pom.xml + + + citrus-test-api-generator + Citrus :: Test API Generator + Citrus Test API Generator + pom + + + true + + + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + + + citrus-test-api-generator-core + citrus-test-api-generator-maven-plugin + + + + diff --git a/validation/citrus-validation-text/src/main/java/org/citrusframework/validation/text/PlainTextMessageValidator.java b/validation/citrus-validation-text/src/main/java/org/citrusframework/validation/text/PlainTextMessageValidator.java index 42e53308e2..788a845ac8 100644 --- a/validation/citrus-validation-text/src/main/java/org/citrusframework/validation/text/PlainTextMessageValidator.java +++ b/validation/citrus-validation-text/src/main/java/org/citrusframework/validation/text/PlainTextMessageValidator.java @@ -16,9 +16,12 @@ package org.citrusframework.validation.text; +import static java.lang.Boolean.parseBoolean; +import static java.lang.Integer.parseInt; +import static org.citrusframework.message.MessagePayloadUtils.normalizeWhitespace; + import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; @@ -29,9 +32,6 @@ import org.citrusframework.validation.context.ValidationContext; import org.citrusframework.validation.matcher.ValidationMatcherUtils; -import static java.lang.Boolean.parseBoolean; -import static java.lang.Integer.parseInt; - /** * Plain text validator using simple String comparison. * @@ -58,8 +58,8 @@ public void validateMessage(Message receivedMessage, Message controlMessage, Tes logger.debug("Start text message validation"); try { - String resultValue = normalizeWhitespace(receivedMessage.getPayload(String.class).trim()); - String controlValue = normalizeWhitespace(context.replaceDynamicContentInString(controlMessage.getPayload(String.class).trim())); + String resultValue = normalizeWhitespace(receivedMessage.getPayload(String.class).trim(), ignoreWhitespace, ignoreNewLineType); + String controlValue = normalizeWhitespace(context.replaceDynamicContentInString(controlMessage.getPayload(String.class).trim()), ignoreWhitespace, ignoreNewLineType); controlValue = processIgnoreStatements(controlValue, resultValue); controlValue = processVariableStatements(controlValue, resultValue, context); @@ -180,38 +180,6 @@ private void validateText(String receivedMessagePayload, String controlMessagePa } } - /** - * Normalize whitespace characters if appropriate. Based on system property settings this method normalizes - * new line characters exclusively or filters all whitespaces such as double whitespaces and new lines. - * - * @param payload - * @return - */ - private String normalizeWhitespace(String payload) { - if (ignoreWhitespace) { - StringBuilder result = new StringBuilder(); - boolean lastWasSpace = true; - for (int i = 0; i < payload.length(); i++) { - char c = payload.charAt(i); - if (Character.isWhitespace(c)) { - if (!lastWasSpace) { - result.append(' '); - } - lastWasSpace = true; - } else { - result.append(c); - lastWasSpace = false; - } - } - return result.toString().trim(); - } - - if (ignoreNewLineType) { - return payload.replaceAll("\\r(\\n)?", "\n"); - } - - return payload; - } @Override public boolean supportsMessageType(String messageType, Message message) { From 2ace5e3a2607b0a67ecc0d3af0d8367a1595cbe1 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Tue, 21 May 2024 06:24:16 +0200 Subject: [PATCH 09/47] chore: remove author annotations --- .../citrusframework/variable/SegmentVariableExtractor.java | 1 - .../variable/SegmentVariableExtractorRegistry.java | 1 - .../citrusframework/variable/VariableExpressionIterator.java | 1 - .../config/handler/CitrusTestCaseNamespaceHandler.java | 2 -- .../org/citrusframework/config/xml/BaseTestCaseParser.java | 5 +---- .../citrusframework/openapi/generator/JavaCitrusCodegen.java | 3 --- .../org/citrusframework/maven/plugin/CodeGenMojoWrapper.java | 2 -- .../maven/plugin/SpringMetaFileGenerator.java | 2 -- .../citrusframework/maven/plugin/TestApiGeneratorMojo.java | 2 -- .../maven/plugin/TestApiGeneratorMojoIntegrationTest.java | 3 --- .../maven/plugin/TestApiGeneratorMojoUnitTest.java | 3 --- 11 files changed, 1 insertion(+), 24 deletions(-) diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractor.java b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractor.java index d1fe6c8b8c..ce32fe3c06 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractor.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractor.java @@ -20,7 +20,6 @@ /** * Class extracting values of segments of VariableExpressions. - * */ public interface SegmentVariableExtractor { diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java index b21f149618..0f4b6c22c8 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java @@ -37,7 +37,6 @@ * the extractors managed by this registry in order to access variable content from the TestContext expressed by variable expressions. *

    * Registry provides all known {@link SegmentVariableExtractor}s. - * */ public class SegmentVariableExtractorRegistry { diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExpressionIterator.java b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExpressionIterator.java index fe6b08b8b6..01dc2b02bd 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExpressionIterator.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExpressionIterator.java @@ -39,7 +39,6 @@ *

  • the third element of the persons property of the variable retrieved in the previous step
  • *
  • the first element of the firstnames property of the property retrieved in the previous step
  • * - * */ public class VariableExpressionIterator implements Iterator { diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusTestCaseNamespaceHandler.java b/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusTestCaseNamespaceHandler.java index 2174e5f056..e9b5c84024 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusTestCaseNamespaceHandler.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusTestCaseNamespaceHandler.java @@ -25,8 +25,6 @@ /** * Namespace handler registers bean definition parser * for Citrus testcase schema elements. - * - * @since 2007 */ public class CitrusTestCaseNamespaceHandler extends NamespaceHandlerSupport { diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/BaseTestCaseParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/BaseTestCaseParser.java index 8c100bd343..efd2ab6963 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/BaseTestCaseParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/BaseTestCaseParser.java @@ -35,10 +35,7 @@ import org.w3c.dom.Element; /** - * Base test case for parsing the test case - * - * @param - * + * Base test case for parsing the test case. */ @SuppressWarnings("PMD.AvoidDuplicateLiterals") public class BaseTestCaseParser implements BeanDefinitionParser { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java index 7aa18331b5..b86f40dbe3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java @@ -17,9 +17,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * @author Thorsten Schlathoelter - */ public class JavaCitrusCodegen extends AbstractJavaCodegen { private static final Logger logger = LoggerFactory.getLogger(JavaCitrusCodegen.class); diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index ea92db1efb..dddd8da625 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -14,8 +14,6 @@ /** * Wrapper class that uses reflection to expose several properties of the {@link CodeGenMojo} for explicit assignment. - * - * @author Thorsten Schlathoelter */ public class CodeGenMojoWrapper extends CodeGenMojo { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java index 23ae7b161f..b793b62346 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -26,8 +26,6 @@ * {@link TestApiGeneratorMojo#CITRUS_TEST_SCHEMA}. *

    * - * @author Thorsten Schlathoelter - * */ public class SpringMetaFileGenerator { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index d5b2b1cd53..fce0a54755 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -36,8 +36,6 @@ * of creating robust integration tests. *

    * - * @author Thorsten Schlathoelter - * */ @Mojo( name = "create-test-api", diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java index d4bcc740b9..4cccffe386 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -38,9 +38,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -/** - * @author Thorsten Schlathoelter - */ class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { public static final String OTHER_META_FILE_CONTENT = "somenamespace=somevalue"; diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java index c63753525f..1bb8781631 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -42,9 +42,6 @@ import org.openapitools.codegen.plugin.CodeGenMojo; -/** - * @author Thorsten Schlathoelter - */ @ExtendWith(MockitoExtension.class) @SuppressWarnings({"JUnitMalformedDeclaration", "JUnitMixedFramework"}) class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase { From a95a3f2ca93ca2154dadc66d495bdcd20cbb9cc6 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Tue, 21 May 2024 06:57:50 +0200 Subject: [PATCH 10/47] chore: add license to new files --- .../citrusframework/testapi/GeneratedApi.java | 16 ++++++++++++++++ .../testapi/GeneratedApiRequest.java | 16 ++++++++++++++++ .../ApiActionBuilderCustomizerService.java | 16 ++++++++++++++++ .../openapi/generator/JavaCitrusCodegen.java | 16 ++++++++++++++++ .../SimpleWsdlToOpenApiTransformer.java | 16 ++++++++++++++++ .../WsdlToOpenApiTransformationException.java | 16 ++++++++++++++++ .../main/resources/java-citrus/api.mustache | 16 ++++++++++++++++ .../resources/java-citrus/api_soap.mustache | 18 +++++++++++++++++- .../java-citrus/bean_configuration.mustache | 18 +++++++++++++++++- .../bean_definition_parser.mustache | 18 +++++++++++++++++- .../java-citrus/namespace_handler.mustache | 18 +++++++++++++++++- .../main/resources/java-citrus/schema.mustache | 16 ++++++++++++++++ .../resources/java-citrus/schema_soap.mustache | 16 ++++++++++++++++ .../resources/java-citrus/test_base.mustache | 16 ++++++++++++++++ .../java-citrus/test_base_soap.mustache | 18 +++++++++++++++++- .../maven/plugin/CodeGenMojoWrapper.java | 16 ++++++++++++++++ .../maven/plugin/SpringMetaFileGenerator.java | 16 ++++++++++++++++ .../maven/plugin/TestApiGeneratorMojo.java | 16 ++++++++++++++++ 18 files changed, 293 insertions(+), 5 deletions(-) diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java index a3d6bfdad2..a37867188c 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java +++ b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.testapi; import java.util.Map; diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java index 5b519ac118..1b86cc29b0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java +++ b/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.testapi; /** diff --git a/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java b/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java index 2b77d97f7b..3231b622af 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java +++ b/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.testapi; import org.citrusframework.TestAction; diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java index b86f40dbe3..a1c0de6e4c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.generator; import static java.util.Arrays.asList; diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java index 68d7bf3579..fc7487aff4 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.generator; import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java index fd845194bf..dd5946b512 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/exception/WsdlToOpenApiTransformationException.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.openapi.generator.exception; public class WsdlToOpenApiTransformationException extends Exception { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 5d90d5f80c..d384833fec 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache index d39d1aff12..6db53348df 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache index d4b8dd2e01..a895518c45 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache index 4e0957f1af..3707465ce5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache index ad260e35ba..5344d50a78 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache index faf2807dd1..1beddbdebc 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache @@ -1,4 +1,20 @@ + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache index 877bdc1884..096cdc9392 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache @@ -1,4 +1,20 @@ + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache index f3566c6716..56a31fe7b3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache index 051485041e..d688a453b8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index dddd8da625..513f9ace80 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.maven.plugin; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java index b793b62346..2e1cdd2e0f 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.maven.plugin; import static java.lang.String.format; diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index fce0a54755..aeee254011 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.citrusframework.maven.plugin; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_ENDPOINT; From e7b52a389aeec414bd030b7a31e45138d7b4de95 Mon Sep 17 00:00:00 2001 From: Sterchi Daniel Date: Wed, 5 Jun 2024 08:50:06 +0200 Subject: [PATCH 11/47] chore: cleanup generator tests --- .../resources/java-citrus/test_base.mustache | 4 ++-- .../java-citrus/test_base_soap.mustache | 4 ++-- .../MultipartTestAbstractTestRequest.java | 18 +++++++++++++++++- .../MultipartTestBeanDefinitionParser.java | 18 +++++++++++++++++- .../MultipartTestNamespaceHandler.java | 18 +++++++++++++++++- .../request/MultiparttestControllerApi.java | 16 ++++++++++++++++ .../spring/MultipartTestBeanConfiguration.java | 18 +++++++++++++++++- .../citrus/PetStoreAbstractTestRequest.java | 18 +++++++++++++++++- .../citrus/PetStoreBeanDefinitionParser.java | 18 +++++++++++++++++- .../extension/PetStoreNamespaceHandler.java | 18 +++++++++++++++++- .../rest/petstore/request/PetApi.java | 16 ++++++++++++++++ .../rest/petstore/request/StoreApi.java | 16 ++++++++++++++++ .../rest/petstore/request/UserApi.java | 16 ++++++++++++++++ .../spring/PetStoreBeanConfiguration.java | 18 +++++++++++++++++- .../OpenApiFromWsdlAbstractTestRequest.java | 18 +++++++++++++++++- .../OpenApiFromWsdlBeanDefinitionParser.java | 18 +++++++++++++++++- .../OpenApiFromWsdlNamespaceHandler.java | 18 +++++++++++++++++- .../request/BookServiceSoapApi.java | 18 +++++++++++++++++- .../OpenApiFromWsdlBeanConfiguration.java | 18 +++++++++++++++++- 19 files changed, 289 insertions(+), 17 deletions(-) diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache index 56a31fe7b3..fbf2003a58 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache index d688a453b8..bd49969597 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - /** + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java index d35d8934bf..478a8e8742 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java index d9730d0d42..1ca5480c9e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java index 0d81b2d521..9f36ba2472 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java index 36d2bca5f4..bde720eb16 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java index 090a9bfb7e..d93b11f104 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java index 9ff2150d21..1e9282b44b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java index 32920fb8ef..b52f5b5f42 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java index af5b731084..84de90fb2c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java index a014b1c53f..0eb28542e6 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java index 406f97f2f9..e8062b4fb0 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java index 01f4558954..d52e4351f1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java @@ -1,3 +1,19 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index cb89458c0b..bf6750e796 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java index 8acda64ca3..4e493250fc 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java index 1c72d58016..e59e1bc033 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java index 04773ddb99..b844e884ca 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index dd84878034..f253418eec 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java index e462cae9f8..919d03669b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java @@ -1,4 +1,20 @@ -/** +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** * ================================================== * GENERATED CLASS, ALL CHANGES WILL BE LOST * ================================================== From 06905bf9b48ae40e0a942e9f44236a3b0014dfa1 Mon Sep 17 00:00:00 2001 From: Sterchi Daniel Date: Wed, 5 Jun 2024 08:56:46 +0200 Subject: [PATCH 12/47] chore: improve OpenApi example --- src/manual/connector-openapi.adoc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc index 8bf9511afa..0f3355bd5f 100644 --- a/src/manual/connector-openapi.adoc +++ b/src/manual/connector-openapi.adoc @@ -130,6 +130,9 @@ private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( @CitrusTest public void openApiClientTest() { + // Define variables to set request parameters. + // Note that the path-param in `petstore-v3.yaml` is named `petId` + variable("petId", "1001"); when(openapi(petstoreSpec) .client(httpClient) .send("getPetById")); @@ -146,6 +149,9 @@ public void openApiClientTest() { + + @@ -241,6 +247,9 @@ private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( @CitrusTest public void openApiClientTest() { + // Define variables to set request parameters. + // Note that the path-param in `petstore-v3.yaml` is named `petId` + variable("petId", "1001"); when(openapi(petstoreSpec) .server(httpServer) .receive("addPet")); @@ -257,6 +266,9 @@ public void openApiClientTest() { + + From 092f8d4ea4c879714bd5c15b575f7cbbc2e5360a Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Tue, 2 Jul 2024 15:16:02 +0200 Subject: [PATCH 13/47] ci: connect openapi generator to maven reactor --- pom.xml | 16 ++- src/manual/connector-openapi.adoc | 22 ++-- .../citrus-test-api-generator-core/pom.xml | 15 ++- .../openapi/generator/JavaCitrusCodegen.java | 124 +++++------------- .../SimpleWsdlToOpenApiTransformer.java | 9 +- .../main/resources/java-citrus/api.mustache | 1 - .../bean_definition_parser.mustache | 6 +- .../java-citrus/namespace_handler.mustache | 1 - .../resources/java-citrus/test_base.mustache | 3 +- ...{GetPetByIdTest.java => GetPetByIdIT.java} | 4 +- .../generator/JavaCitrusCodegenIT.java | 2 - .../generator/JavaCitrusCodegenTest.java | 47 ++++++- .../openapi/generator/ServiceLoaderTest.java | 2 +- .../generator/SpringBeanConfigurationIT.java | 2 +- .../util/TestApiActionBuilderCustomizer.java | 1 - .../apis/multiparttest-rest-resource.yaml | 6 +- .../MultipartTestAbstractTestRequest.java | 3 +- .../MultipartTestBeanDefinitionParser.java | 6 +- .../MultipartTestNamespaceHandler.java | 1 - .../request/MultiparttestControllerApi.java | 1 - .../citrus/PetStoreAbstractTestRequest.java | 3 +- .../citrus/PetStoreBeanDefinitionParser.java | 6 +- .../extension/PetStoreNamespaceHandler.java | 1 - .../rest/petstore/request/PetApi.java | 1 - .../rest/petstore/request/StoreApi.java | 1 - .../rest/petstore/request/UserApi.java | 1 - .../OpenApiFromWsdlBeanDefinitionParser.java | 6 +- .../OpenApiFromWsdlNamespaceHandler.java | 1 - .../pom.xml | 7 +- .../maven/plugin/CodeGenMojoWrapper.java | 5 +- .../maven/plugin/SpringMetaFileGenerator.java | 14 +- .../maven/plugin/TestApiGeneratorMojo.java | 91 ++----------- .../plugin/TestApiGeneratorMojoUnitTest.java | 9 +- test-api-generator/pom.xml | 57 +++++++- 34 files changed, 192 insertions(+), 283 deletions(-) rename test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/{GetPetByIdTest.java => GetPetByIdIT.java} (98%) diff --git a/pom.xml b/pom.xml index 28a484cd68..736501e357 100644 --- a/pom.xml +++ b/pom.xml @@ -50,14 +50,16 @@ - core - utils - runtime - validation + catalog connectors + core endpoints + runtime + test-api-generator tools - catalog + utils + utils + validation @@ -251,7 +253,7 @@ 3.2.0 4.1.105.Final 4.12.0 - 7.5.0 + 7.5.0 4.7.6 42.7.5 3.17.4 @@ -529,7 +531,7 @@ org.openapitools openapi-generator - ${openapi-generator-maven-plugin} + ${org.openapitools.version} provided diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc index 0f3355bd5f..a67e97cc80 100644 --- a/src/manual/connector-openapi.adoc +++ b/src/manual/connector-openapi.adoc @@ -334,11 +334,11 @@ The generator provides the following features: * generation of a Test API ** from OpenAPI Specification ** [TODO #1163] from WSDL via an intermediate step that generates a "light" OpenApi specification from a WSDL -* integration into Citrus XML test cases +* integration into <> ** integration into XML editors via generated XSD *** schema validation *** auto completion -* integration into Citrus Java test cases via Java DSL [TODO #1161] +* integration into <> via Java DSL [TODO #1161] The following directory structure/table specifies the files, which are generated by the generator. Note that the `Prefix` is a configuration parameter which should uniquely identify a generated API. @@ -387,9 +387,9 @@ target/ ==== Configuration of Test API generation Code generation is typically performed during the build process. -For the Citrus Test API Generator, it is carried out by a Maven plugin. +For the Citrus Test API Generator, it is carried out by a Maven or Gradle plugin. While the standard generator plugin, `org.openapitools:openapi-generator-maven-plugin`, can be employed for this purpose, configuring it can be cumbersome, especially when dealing with multiple APIs. -To address this challenge, Citrus offers its adaptation of this standard generator Maven plugin. +To address this challenge, Citrus offers its adaptation of this standard generator plugin. This `Citrus OpenAPI Generator Plugin` simplifies the configuration of test API generation by providing predefined defaults and supporting the generation of multiple APIs. Additionally, it enhances support for generating Spring integration files (`spring.handlers` and `spring.schemas`), thereby facilitating the integration of generated APIs into Spring-based applications. Consequently, utilizing the Citrus Generator Plugin is recommended in most scenarios. @@ -535,27 +535,26 @@ The following shows the configuration of test api generation for different scena These are the primary elements you can configure in the `` section: |=== -| Configuration element | Maven Property | Description | Default Value +| Configuration element | Maven Property | Description | Default Value | `schemaFolder` | `citrus.test.api.generator.schema.folder` | Location for the generated XSD schemas | `schema/xsd/%VERSION%` | `resourceFolder` | `citrus.test.api.generator.resource.folder` | Location to which resources are generated | `generated-resources` | `sourceFolder` | `citrus.test.api.generator.source.folder` | Location to which sources are generated | `generated-sources` | `metaInfFolder` | `citrus.test.api.generator.meta.inf.folder` | Location to which spring meta files are generated/updated | `target/generated-test-resources/META-INF` | `generateSpringIntegrationFiles` | `citrus.test.api.generator.generate.spring.integration.files` | Specifies whether spring integration files should be generated | `true` -| Nested api element | | | +| Nested `` element | | | | `prefix` | `citrus.test.api.generator.prefix` | Specifies the prefix used for the test API, typically an acronym | (no default, required) | `source` | `citrus.test.api.generator.source` | Specifies the source of the test API | (no default, required) | `version` | `citrus.test.api.generator.version` | Specifies the version of the API, may be null | (none) | `endpoint` | `citrus.test.api.generator.endpoint` | Specifies the endpoint of the test API | `applicationServiceClient` | `type` | `citrus.test.api.generator.type` | Specifies the type of the test API | `REST`, other option is `SOAP` | `useTags` | `citrus.test.api.generator.use.tags` | Specifies whether tags should be used by the generator | `true` -| `invokerPackage` | `citrus.test.api.generator.invoker.package` | Package for the test API classes | `org.citrusframework.automation.%PREFIX%.%VERSION%` +| `invokerPackage` | `citrus.test.api.generator.invoker.package` | Package for the test API classes | `org.citrusframework.automation.%PREFIX%.%VERSION%` | `apiPackage` | `citrus.test.api.generator.api.package` | Package for the test API interface classes | `org.citrusframework.automation.%PREFIX%.%VERSION%.api` | `modelPackage` | `citrus.test.api.generator.model.package` | Package for the test API model classes | `org.citrusframework.automation.%PREFIX%.%VERSION%.model` -| `targetXmlnsNamespace` | `citrus.test.api.generator.namespace` | XML namespace used by the API | `http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api` +| `targetXmlnsNamespace` | `citrus.test.api.generator.namespace` | XML namespace used by the API | `http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api` |=== - Note: `%PREFIX%` and `%VERSION%` are placeholders that will be replaced by their specific values as configured. The plugin performs a conversion to lowercase for `PREFIX` used in package names and in `targetXmlnsNamespace`. @@ -568,7 +567,6 @@ To run the generator, execute the following command in your project directory: mvn citrus-test-api-generator-maven-plugin:create-test-api ---- - This command will generate the classes and XSD files as configured for your APIs in the specified locations. ==== Spring meta file generation @@ -683,8 +681,8 @@ Further examples can be found here `org.citrusframework.openapi.generator.Genera ---- To utilize the test API in Java, it's necessary to import the API configuration, that provides the respective request actions. -The request to test can then be autowired, configured and autowired, as illustrated in the sample below. -Further examples can be found here `org.citrusframework.openapi.generator.GetPetByIdTest`. +The request to test can then be configured and autowired, as illustrated in the sample below. +Further examples can be found here `org.citrusframework.openapi.generator.GetPetByIdIT`. .Java DSL [source,java,indent=0,role="secondary"] diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index c74f91249a..4681188d7e 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -18,7 +18,6 @@ Generates a Citrus Test-API for OpenAPI and WSDL specifications. - org.citrusframework citrus-api @@ -54,6 +53,7 @@ org.openapitools openapi-generator + ${org.openapitools.version} wsdl4j @@ -67,18 +67,18 @@ ${project.version} test - - org.springframework.boot - spring-boot-test - ${spring.boot.test.version} - test - org.citrusframework citrus-validation-json ${project.version} test + + org.springframework.boot + spring-boot-test + ${spring.boot.version} + test + @@ -121,6 +121,7 @@ org.openapitools openapi-generator-maven-plugin + ${org.openapitools.version} org.citrusframework diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java index a1c0de6e4c..d62d4c1a9d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java @@ -16,6 +16,7 @@ package org.citrusframework.openapi.generator; +import static java.lang.String.format; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toMap; import static org.openapitools.codegen.CliOption.newString; @@ -27,12 +28,16 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import lombok.Getter; +import lombok.Setter; import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.languages.AbstractJavaCodegen; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +@Getter +@Setter public class JavaCitrusCodegen extends AbstractJavaCodegen { private static final Logger logger = LoggerFactory.getLogger(JavaCitrusCodegen.class); @@ -68,6 +73,7 @@ public class JavaCitrusCodegen extends AbstractJavaCodegen { public JavaCitrusCodegen() { super(); + // the root folder where all files are emitted outputFolder = "generated-code" + File.separator + "java"; @@ -108,8 +114,9 @@ public JavaCitrusCodegen() { ); setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); - // add posibility to set a new value for the properties - cliOptions.add(newString(API_ENDPOINT, + // add possibility to set a new value for the properties + cliOptions.add( + newString(API_ENDPOINT, "Which http client should be used (default " + httpClient + ").")); cliOptions.add( newString( @@ -121,9 +128,11 @@ public JavaCitrusCodegen() { newString(GENERATED_SCHEMA_FOLDER, "The schema output directory (default " + generatedSchemaFolder + ").") ); - cliOptions.add(newString(HTTP_PATH_PREFIX, + cliOptions.add( + newString(HTTP_PATH_PREFIX, "Add a prefix to http path for all APIs (default " + httpPathPrefix + ").")); - cliOptions.add(newString(OPENAPI_SCHEMA, + cliOptions.add( + newString(OPENAPI_SCHEMA, "Which OpenAPI schema should be used (default " + openapiSchema + ").")); cliOptions.add( newString( @@ -133,7 +142,8 @@ public JavaCitrusCodegen() { ) ); cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); - cliOptions.add(newString(RESOURCE_FOLDER, + cliOptions.add( + newString(RESOURCE_FOLDER, "Where the resource files are emitted (default " + resourceFolder + ").")); cliOptions.add( newString(TARGET_XMLNS_NAMESPACE, @@ -184,8 +194,7 @@ public void processOpts() { additionalProperties.put(API_ENDPOINT, httpClient); if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { - this.setGeneratedSchemaFolder( - additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); + this.setGeneratedSchemaFolder(additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); } additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); @@ -222,17 +231,14 @@ public void processOpts() { additionalProperties.put(RESOURCE_FOLDER, resourceFolder); if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { - this.setTargetXmlnsNamespace( - additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); + this.setTargetXmlnsNamespace(additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); } else { - this.targetXmlnsNamespace = String.format( - "http://www.citrusframework.org/citrus-test-schema/%s-api", apiPrefix.toLowerCase()); + this.targetXmlnsNamespace = format("http://www.citrusframework.org/citrus-test-schema/%s-api", apiPrefix.toLowerCase()); } additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); // define different folders where the files will be emitted - final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", - File.separator); + final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator); final String citrusFolder = invokerFolder + File.separator + "citrus"; final String extensionFolder = citrusFolder + File.separator + "extension"; final String springFolder = invokerFolder + File.separator + "spring"; @@ -244,7 +250,7 @@ public void processOpts() { } else if (API_TYPE_SOAP.equals(apiType)) { addSoapSupportingFiles(citrusFolder, schemaFolder); } else { - throw new IllegalArgumentException(String.format("Unknown API_TYPE: '%s'", apiType)); + throw new IllegalArgumentException(format("Unknown API_TYPE: '%s'", apiType)); } addDefaultSupportingFiles(citrusFolder, extensionFolder, springFolder); @@ -260,74 +266,15 @@ public void preprocessOpenAPI(OpenAPI openAPI) { additionalProperties.putAll(extensions); Map infoExtensions = extensions.entrySet().stream() - .filter(entry -> entry.getKey().toUpperCase( - ).startsWith("X-")) + .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) .collect(toMap(Entry::getKey, Entry::getValue)); additionalProperties.put("infoExtensions", infoExtensions); } } - public void setApiPrefix(String apiPrefix) { - this.apiPrefix = apiPrefix; - } - - public String getHttpClient() { - return httpClient; - } - - public void setHttpClient(String httpClient) { - this.httpClient = httpClient; - } - - public String getHttpPathPrefix() { - return httpPathPrefix; - } - - public void setHttpPathPrefix(String httpPathPrefix) { - this.httpPathPrefix = httpPathPrefix; - } - - public String getOpenapiSchema() { - return openapiSchema; - } - - public void setOpenapiSchema(String openapiSchema) { - this.openapiSchema = openapiSchema; - } - - public String getResourceFolder() { - return resourceFolder; - } - - public void setResourceFolder(String resourceFolder) { - this.resourceFolder = resourceFolder; - } - - public String getGeneratedSchemaFolder() { - return generatedSchemaFolder; - } - - public void setGeneratedSchemaFolder(String generatedSchemaFolder) { - this.generatedSchemaFolder = generatedSchemaFolder; - } - - public String getTargetXmlnsNamespace() { - return targetXmlnsNamespace; - } - - public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { - this.targetXmlnsNamespace = targetXmlnsNamespace; - } - - public String getApiPrefix() { - return apiPrefix; - } - private void addRestSupportingFiles(final String citrusFolder, String schemaFolder) { - supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); - supportingFiles.add(new SupportingFile("test_base.mustache", citrusFolder, - apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); + supportingFiles.add(new SupportingFile("test_base.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); } private void addSoapSupportingFiles(final String citrusFolder, String schemaFolder) { @@ -335,24 +282,15 @@ private void addSoapSupportingFiles(final String citrusFolder, String schemaFold apiTemplateFiles().remove("api.mustache"); apiTemplateFiles().put("api_soap.mustache", ".java"); - supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); - supportingFiles.add(new SupportingFile("api_soap.mustache", citrusFolder, - apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); - supportingFiles.add(new SupportingFile("test_base_soap.mustache", citrusFolder, - apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); + supportingFiles.add(new SupportingFile("api_soap.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); + supportingFiles.add(new SupportingFile("test_base_soap.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); } - private void addDefaultSupportingFiles(final String citrusFolder, final String extensionFolder, - final String springFolder) { - supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, - apiPrefix + "BeanConfiguration.java")); - supportingFiles.add(new SupportingFile("bean_definition_parser.mustache", citrusFolder, - apiPrefix + "BeanDefinitionParser.java")); - supportingFiles.add(new SupportingFile("namespace_handler.mustache", extensionFolder, - apiPrefix + "NamespaceHandler.java")); - supportingFiles.add(new SupportingFile("api-model.mustache", resourceFolder, - apiPrefix.toLowerCase() + "-api-model.csv")); + private void addDefaultSupportingFiles(final String citrusFolder, final String extensionFolder, final String springFolder) { + supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, apiPrefix + "BeanConfiguration.java")); + supportingFiles.add(new SupportingFile("bean_definition_parser.mustache", citrusFolder, apiPrefix + "BeanDefinitionParser.java")); + supportingFiles.add(new SupportingFile("namespace_handler.mustache", extensionFolder, apiPrefix + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("api-model.mustache", resourceFolder, apiPrefix.toLowerCase() + "-api-model.csv")); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java index fc7487aff4..8243be5aa8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java @@ -86,9 +86,6 @@ public String transformToOpenApi() throws WsdlToOpenApiTransformationException { /** * Performs the actual transformation from bindings into OpenApi operations. - * - * @param bindings - * @return */ private OpenAPI transformToOpenApi(Map bindings) { OpenAPI openAPI = new OpenAPI(); @@ -100,10 +97,11 @@ private OpenAPI transformToOpenApi(Map bindings) { Object key = entry.getKey(); Object value = entry.getValue(); - if (key instanceof QName && value instanceof Binding) { - addOperations(openAPI, (QName) key, (Binding) value); + if (key instanceof QName qName && value instanceof Binding binding) { + addOperations(openAPI, qName, binding); } } + return openAPI; } @@ -138,6 +136,7 @@ private Info createInfo() { Contact contact = new Contact(); contact.setName("org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer"); info.setContact(contact); + return info; } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index d384833fec..36d6186da8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -52,7 +52,6 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class {{classname}} implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache index 3707465ce5..b6b205a521 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache @@ -22,7 +22,6 @@ package {{invokerPackage}}.citrus; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,20 +30,17 @@ import java.util.regex.Pattern; import javax.annotation.processing.Generated; -import org.citrusframework.exceptions.CitrusRuntimeException; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class {{prefix}}BeanDefinitionParser implements BeanDefinitionParser { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache index 5344d50a78..535f504b0b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -33,7 +33,6 @@ import javax.annotation.processing.Generated; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class {{prefix}}NamespaceHandler extends NamespaceHandlerSupport { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache index fbf2003a58..a3de4774fb 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache @@ -22,7 +22,6 @@ package {{invokerPackage}}.citrus; - import static org.springframework.util.CollectionUtils.isEmpty; import jakarta.annotation.Generated; @@ -39,10 +38,10 @@ import org.citrusframework.http.actions.HttpClientRequestActionBuilder; import org.citrusframework.http.actions.HttpClientResponseActionBuilder; import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; import org.citrusframework.http.client.HttpClient; +import org.citrusframework.spi.Resources; import org.citrusframework.message.Message; import org.citrusframework.testapi.ApiActionBuilderCustomizerService; import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.spi.Resources; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.PathExpressionValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java similarity index 98% rename from test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java rename to test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java index 6421cee946..72b9369ca3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java @@ -24,7 +24,7 @@ import org.citrusframework.message.Message; import org.citrusframework.messaging.Producer; import org.citrusframework.messaging.SelectiveConsumer; -import org.citrusframework.openapi.generator.GetPetByIdTest.Config; +import org.citrusframework.openapi.generator.GetPetByIdIT.Config; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; import org.citrusframework.spi.Resources; @@ -40,7 +40,7 @@ @ExtendWith(CitrusSpringExtension.class) @SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class, Config.class}) -class GetPetByIdTest { +class GetPetByIdIT { @Autowired private GetPetByIdRequest getPetByIdRequest; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java index dd4f52ece7..49230954ba 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java @@ -4,11 +4,9 @@ import java.io.File; import java.io.IOException; -import java.util.List; import java.util.stream.Stream; import org.apache.commons.lang3.stream.Streams; import org.citrusframework.exceptions.CitrusRuntimeException; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java index 57f49cd861..9c6874c5de 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java @@ -5,6 +5,7 @@ import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.HashMap; @@ -32,6 +33,31 @@ class JavaCitrusCodegenTest { + /** + * Get the absolute path to the test resources directory. + * + * @param pathToFileInTestResources The file within {@code src/test/resources} to look for + * @return the absolute path to the file + */ + private String getTestResource(String pathToFileInTestResources) { + URL resourceUrl = getClass().getClassLoader().getResource(pathToFileInTestResources); + assert resourceUrl != null; + File inputSpecFile = new File(resourceUrl.getFile()); + return inputSpecFile.getAbsolutePath(); + } + + /** + * Get the absolute path to the project's target directory. + * + * @param pathToFileInTargetDirectory The file within {@code target} to look for + * @return the absolute path to the file + */ + private static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { + String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project + File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); + return outputDirFile.getAbsolutePath(); + } + @Test void retrieveGeneratorBsSpi() { JavaCitrusCodegen codegen = (JavaCitrusCodegen) CodegenConfigLoader.forName("java-citrus"); @@ -83,10 +109,13 @@ void areAdditionalPropertiesProcessedTest() { @Test void areReservedWordsEscapedTest() throws IOException { + String absoluteInputSpecPath = getTestResource("apis/petstore_reservedWords.yaml"); + String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore_escapedWords"); + final CodegenConfigurator configurator = new CodegenConfigurator() .setGeneratorName(CODEGEN_NAME) - .setInputSpec("src/test/resources/apis/petstore_reservedWords.yaml") - .setOutputDir("target/JavaCitrusCodegenTest/petstore_escapedWords"); + .setInputSpec(absoluteInputSpecPath) + .setOutputDir(absoluteOutputDirPath); final ClientOptInput clientOptInput = configurator.toClientOptInput(); DefaultGenerator generator = new DefaultGenerator(); @@ -105,10 +134,13 @@ void areReservedWordsEscapedTest() throws IOException { @Test void arePathParamsFieldsPresent() throws IOException { + String absoluteInputSpecPath = getTestResource("apis/petstore.yaml"); + String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); + final CodegenConfigurator configurator = new CodegenConfigurator() .setGeneratorName(CODEGEN_NAME) - .setInputSpec("src/test/resources/apis/petstore.yaml") - .setOutputDir("target/JavaCitrusCodegenTest/petstore"); + .setInputSpec(absoluteInputSpecPath) + .setOutputDir(absoluteOutputDirPath); final ClientOptInput clientOptInput = configurator.toClientOptInput(); DefaultGenerator generator = new DefaultGenerator(); @@ -130,10 +162,13 @@ void arePathParamsFieldsPresent() throws IOException { @Test void areBasicAuthFieldsPresent() throws IOException { + String absoluteInputSpecPath = getTestResource("apis/petstore.yaml"); + String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); + final CodegenConfigurator configurator = new CodegenConfigurator() .setGeneratorName(CODEGEN_NAME) - .setInputSpec("src/test/resources/apis/petstore.yaml") - .setOutputDir("target/JavaCitrusCodegenTest/petstore"); + .setInputSpec(absoluteInputSpecPath) + .setOutputDir(absoluteOutputDirPath); final ClientOptInput clientOptInput = configurator.toClientOptInput(); DefaultGenerator generator = new DefaultGenerator(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java index 6b17f01f13..419cea9ade 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java @@ -5,8 +5,8 @@ import java.util.List; import java.util.ServiceLoader; import java.util.ServiceLoader.Provider; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; import org.citrusframework.openapi.generator.util.TestApiActionBuilderCustomizer; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; import org.junit.jupiter.api.Test; class ServiceLoaderTest { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java index 2f5dbf7179..15dfb85dc3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java @@ -9,10 +9,10 @@ import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpEndpointConfiguration; import org.citrusframework.junit.jupiter.spring.CitrusSpringSupport; +import org.citrusframework.openapi.generator.SpringBeanConfigurationIT.ClientConfiguration; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.AddPetRequest; import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; import org.junit.jupiter.api.Test; -import org.citrusframework.openapi.generator.SpringBeanConfigurationIT.ClientConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.ApplicationContext; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java index 0aaa9761ab..1b0b8824a7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java @@ -1,7 +1,6 @@ package org.citrusframework.openapi.generator.util; import org.citrusframework.TestAction; -import org.citrusframework.TestActionBuilder; import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.testapi.ApiActionBuilderCustomizerService; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml index b77b55c4d2..cfac634788 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml @@ -7,9 +7,9 @@ info: x-citrus-app: MPT x-citrus-api-name: multiparttest-rest-resource contact: - name: IT-Services-CI TAuBE - email: IT-Serv-CI-ETAdl@post.ch - url: https://confluence.pnet.ch/pages/viewpage.action?pageId=314828825 + name: Citrusframework Authors + email: citrus-dev@googlegroups.com + url: https://citrusframework.org tags: - name: multiparttest-controller paths: diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java index 478a8e8742..01092606ba 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java @@ -22,7 +22,6 @@ package org.citrusframework.openapi.generator.rest.multiparttest.citrus; - import static org.springframework.util.CollectionUtils.isEmpty; import jakarta.annotation.Generated; @@ -39,10 +38,10 @@ import org.citrusframework.http.actions.HttpClientResponseActionBuilder; import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; import org.citrusframework.http.client.HttpClient; +import org.citrusframework.spi.Resources; import org.citrusframework.message.Message; import org.citrusframework.testapi.ApiActionBuilderCustomizerService; import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.spi.Resources; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.PathExpressionValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java index 1ca5480c9e..37df5ee8b9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java @@ -22,7 +22,6 @@ package org.citrusframework.openapi.generator.rest.multiparttest.citrus; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,20 +30,17 @@ import javax.annotation.processing.Generated; -import org.citrusframework.exceptions.CitrusRuntimeException; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class MultipartTestBeanDefinitionParser implements BeanDefinitionParser { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java index 9f36ba2472..4517c7a801 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java @@ -29,7 +29,6 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class MultipartTestNamespaceHandler extends NamespaceHandlerSupport { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java index bde720eb16..7ced338bb8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java @@ -52,7 +52,6 @@ import java.util.Map; import java.util.stream.Collectors; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class MultiparttestControllerApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java index 1e9282b44b..29a409ea85 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java @@ -22,7 +22,6 @@ package org.citrusframework.openapi.generator.rest.petstore.citrus; - import static org.springframework.util.CollectionUtils.isEmpty; import jakarta.annotation.Generated; @@ -39,10 +38,10 @@ import org.citrusframework.http.actions.HttpClientResponseActionBuilder; import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; import org.citrusframework.http.client.HttpClient; +import org.citrusframework.spi.Resources; import org.citrusframework.message.Message; import org.citrusframework.testapi.ApiActionBuilderCustomizerService; import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.spi.Resources; import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.validation.PathExpressionValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java index b52f5b5f42..f7ee721e6c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java @@ -22,7 +22,6 @@ package org.citrusframework.openapi.generator.rest.petstore.citrus; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,20 +30,17 @@ import javax.annotation.processing.Generated; -import org.citrusframework.exceptions.CitrusRuntimeException; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class PetStoreBeanDefinitionParser implements BeanDefinitionParser { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java index 84de90fb2c..b7bb6298c1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java @@ -31,7 +31,6 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java index 0eb28542e6..570912da01 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java @@ -52,7 +52,6 @@ import java.util.Map; import java.util.stream.Collectors; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class PetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java index e8062b4fb0..b7d6754a4f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java @@ -52,7 +52,6 @@ import java.util.Map; import java.util.stream.Collectors; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class StoreApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java index d52e4351f1..7c89b95787 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java @@ -52,7 +52,6 @@ import java.util.Map; import java.util.stream.Collectors; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class UserApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java index e59e1bc033..6bb955eb0b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java @@ -22,7 +22,6 @@ package org.citrusframework.openapi.generator.soap.bookservice.citrus; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,20 +30,17 @@ import javax.annotation.processing.Generated; -import org.citrusframework.exceptions.CitrusRuntimeException; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.util.Assert; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class OpenApiFromWsdlBeanDefinitionParser implements BeanDefinitionParser { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java index b844e884ca..9c2f110274 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java @@ -29,7 +29,6 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - @Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") public class OpenApiFromWsdlNamespaceHandler extends NamespaceHandlerSupport { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index e92fd84d94..134d44aee9 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -36,13 +36,18 @@ - org.citrusframework citrus-test-api-generator-core ${project.version} + + org.openapitools + openapi-generator-maven-plugin + ${org.openapitools.version} + + commons-io commons-io diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index 513f9ace80..5b1d088727 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -16,16 +16,16 @@ package org.citrusframework.maven.plugin; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; import static java.lang.String.format; +import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; -import org.citrusframework.openapi.generator.JavaCitrusCodegen; import java.io.File; import java.util.HashMap; import java.util.Map; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; +import org.citrusframework.openapi.generator.JavaCitrusCodegen; import org.openapitools.codegen.plugin.CodeGenMojo; /** @@ -96,5 +96,4 @@ private void setPrivateField(String fieldName, Object fieldValue) throws MojoExe format("Could not reflectively set field value '%s' for field '%s'", fieldValue, fieldName)); } } - } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java index 2e1cdd2e0f..1d1f475bee 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -19,7 +19,6 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -30,6 +29,7 @@ import java.util.function.BiConsumer; import org.apache.maven.plugin.MojoExecutionException; import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; /** * Utility class responsible for generating the Spring meta files 'spring.handlers' and 'spring.schemas', used @@ -52,9 +52,7 @@ public SpringMetaFileGenerator(TestApiGeneratorMojo testApiGeneratorMojo) { } public void generateSpringIntegrationMetaFiles() throws MojoExecutionException { - - String springMetafileDirectory = format("%s/%s", testApiGeneratorMojo.getMavenProject().getBasedir(), - testApiGeneratorMojo.metaInfFolder()); + String springMetafileDirectory = format("%s/%s", testApiGeneratorMojo.getMavenProject().getBasedir(), testApiGeneratorMojo.metaInfFolder()); File metaFolder = new File(springMetafileDirectory); if (!metaFolder.exists() && !metaFolder.mkdirs()) { throw new CitrusRuntimeException( @@ -70,7 +68,6 @@ public void generateSpringIntegrationMetaFiles() throws MojoExecutionException { } private void writeSpringSchemaMetaFile(File springMetafileDirectory) throws MojoExecutionException { - String filename = "spring.schemas"; writeSpringMetaFile(springMetafileDirectory, filename, (fileWriter, apiConfig) -> { String targetXmlnsNamespace = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), @@ -94,14 +91,11 @@ private void writeSpringHandlerMetaFile(File springMetafileDirectory) throws Moj }); } - private void writeSpringMetaFile(File springMetafileDirectory, String filename, BiConsumer contentFormatter) - throws MojoExecutionException { - + private void writeSpringMetaFile(File springMetafileDirectory, String filename, BiConsumer contentFormatter) throws MojoExecutionException { File handlerFile = new File(format("%s/%s", springMetafileDirectory.getPath(), filename)); List filteredLines = readAndFilterLines(handlerFile); try (FileWriter fileWriter = new FileWriter(handlerFile)) { - for (String line : filteredLines) { fileWriter.write(format("%s%n", line)); } @@ -109,7 +103,6 @@ private void writeSpringMetaFile(File springMetafileDirectory, String filename, for (ApiConfig apiConfig : testApiGeneratorMojo.getApiConfigs()) { contentFormatter.accept(fileWriter, apiConfig); } - } catch (IOException e) { throw new MojoExecutionException("Unable to write spring meta file!", e); } @@ -133,7 +126,6 @@ private void writeSpringMetaFile(File springMetafileDirectory, String filename, * @throws CitrusRuntimeException if an error occurs while reading the file */ private static List readAndFilterLines(File file) { - if (!file.exists()) { return emptyList(); } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index aeee254011..d37b4d8ffe 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -16,18 +16,20 @@ package org.citrusframework.maven.plugin; +import static java.lang.String.format; +import static org.apache.commons.lang3.StringUtils.isBlank; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_ENDPOINT; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_TYPE; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.PREFIX; import static org.citrusframework.openapi.generator.JavaCitrusCodegen.TARGET_XMLNS_NAMESPACE; -import static java.lang.String.format; -import static org.apache.commons.lang3.StringUtils.isBlank; import com.google.common.annotations.VisibleForTesting; import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; +import lombok.Getter; +import lombok.Setter; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -66,8 +68,8 @@ public class TestApiGeneratorMojo extends AbstractMojo { public static final String DEFAULT_RESOURCE_FOLDER = "generated-test-resources"; public static final String DEFAULT_BASE_PACKAGE = "org.citrusframework.automation.%PREFIX%.%VERSION%"; public static final String DEFAULT_INVOKER_PACKAGE = DEFAULT_BASE_PACKAGE; - public static final String DEFAULT_API_PACKAGE = DEFAULT_BASE_PACKAGE+".api"; - public static final String DEFAULT_MODEL_PACKAGE = DEFAULT_BASE_PACKAGE+".model"; + public static final String DEFAULT_API_PACKAGE = DEFAULT_BASE_PACKAGE + ".api"; + public static final String DEFAULT_MODEL_PACKAGE = DEFAULT_BASE_PACKAGE + ".model"; public static final String DEFAULT_SCHEMA_FOLDER_TEMPLATE = "schema/xsd/%VERSION%"; public static final ApiType DEFAULT_API_TYPE = ApiType.REST; @@ -173,7 +175,6 @@ public String schemaFolder(ApiConfig apiConfig) { @Override public void execute() throws MojoExecutionException { - for (int index = 0; index < apis.size(); index++) { ApiConfig apiConfig = apis.get(index); validateApiConfig(index, apiConfig); @@ -199,6 +200,7 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept codeGenMojo.setPluginContext(getPluginContext()); codeGenMojo.setBuildContext(buildContext); + return codeGenMojo; } @@ -217,7 +219,6 @@ private void requireNonBlankParameter(String name, int index, String parameterVa * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text. */ static String replaceDynamicVars(String text, String prefix, String version) { - if (text == null) { return null; } @@ -244,6 +245,8 @@ public enum ApiType { * Note that the default values are not properly set by maven processor. Therefore, the default values have been assigned additionally * on field level. */ + @Getter + @Setter public static class ApiConfig { public static final String DEFAULT_ENDPOINT = "PREFIX_ENDPOINT"; @@ -324,83 +327,10 @@ public static class ApiConfig { @Parameter(property = API_NAMESPACE_PROPERTY, defaultValue = DEFAULT_TARGET_NAMESPACE_TEMPLATE) private String targetXmlnsNamespace = DEFAULT_TARGET_NAMESPACE_TEMPLATE; - - public String getPrefix() { - return prefix; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - public String getSource() { - return source; - } - - public void setSource(String source) { - this.source = source; - } - - public String getVersion() { - return version; - } - - public void setVersion(String version) { - this.version = version; - } - public String qualifiedEndpoint() { return DEFAULT_ENDPOINT.equals(endpoint) ? getPrefix().toLowerCase() + "Endpoint" : endpoint; } - public void setEndpoint(String endpoint) { - this.endpoint = endpoint; - } - - public ApiType getType() { - return type; - } - - public void setType(ApiType type) { - this.type = type; - } - - public void setUseTags(boolean useTags) { - this.useTags = useTags; - } - - public String getInvokerPackage() { - return invokerPackage; - } - - public void setInvokerPackage(String invokerPackage) { - this.invokerPackage = invokerPackage; - } - - public String getApiPackage() { - return apiPackage; - } - - public void setApiPackage(String apiPackage) { - this.apiPackage = apiPackage; - } - - public String getModelPackage() { - return modelPackage; - } - - public void setModelPackage(String modelPackage) { - this.modelPackage = modelPackage; - } - - public String getTargetXmlnsNamespace() { - return targetXmlnsNamespace; - } - - public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { - this.targetXmlnsNamespace = targetXmlnsNamespace; - } - Map toConfigOptionsProperties() { Map configOptionsProperties = new HashMap<>(); @@ -419,8 +349,5 @@ Map toConfigOptionsProperties() { return configOptionsProperties; } - } - - } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java index 1bb8781631..8309b94dcb 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -1,5 +1,7 @@ package org.citrusframework.maven.plugin; +import static java.lang.Boolean.TRUE; +import static org.assertj.core.api.Assertions.assertThat; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_PACKAGE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_TYPE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_INVOKER_PACKAGE; @@ -11,16 +13,11 @@ import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_TARGET_NAMESPACE_TEMPLATE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; -import static java.lang.Boolean.TRUE; -import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.mockito.Mockito.doReturn; import static org.springframework.test.util.ReflectionTestUtils.getField; import jakarta.validation.constraints.NotNull; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiType; import java.io.File; import java.util.HashMap; import java.util.Map; @@ -30,6 +27,8 @@ import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.project.MavenProject; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index f6298e3e11..b33d0f717e 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -19,19 +19,64 @@ true + + citrus-test-api-generator-core + citrus-test-api-generator-maven-plugin + + org.junit.jupiter junit-jupiter-engine - ${junit.jupiter.version} + ${junit.jupiter.version} + test + + + + org.junit.jupiter + junit-jupiter-params + ${junit.jupiter.version} test - - citrus-test-api-generator-core - citrus-test-api-generator-maven-plugin - + + + + org.apache.maven.plugins + maven-surefire-plugin + + + *IntegrationTest.java + *IT.java + + + + + org.apache.maven.surefire + surefire-junit-platform + ${maven.surefire.plugin.version} + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + *IntegrationTest.java + *IT.java + + + + + org.apache.maven.surefire + surefire-junit-platform + ${maven.surefire.plugin.version} + + + + + - From c77cb0745fe004aa53d4530cb6c5ff2df0d3d5de Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Wed, 3 Jul 2024 15:20:32 +0200 Subject: [PATCH 14/47] feat(#1156): generate Java models alongside citrus classes --- .../citrus-test-api-generator-core/pom.xml | 62 ++++ .../openapi/generator/JavaCitrusCodegen.java | 10 +- .../main/resources/java-citrus/api.mustache | 25 +- .../resources/java-citrus/api_soap.mustache | 25 +- .../java-citrus/bean_configuration.mustache | 25 +- .../bean_definition_parser.mustache | 26 +- .../java-citrus/licenseInfo.mustache | 15 + .../main/resources/java-citrus/model.mustache | 1 - .../resources/java-citrus/model_doc.mustache | 1 - .../java-citrus/namespace_handler.mustache | 26 +- .../resources/java-citrus/test_base.mustache | 25 +- .../java-citrus/test_base_soap.mustache | 25 +- .../openapi/generator/GeneratedApiIT.java | 6 +- .../generator/JavaCitrusCodegenIT.java | 95 ++++-- .../generator/JavaCitrusCodegenTest.java | 62 ++-- .../MultipartTestAbstractTestRequest.java | 37 +-- .../MultipartTestBeanDefinitionParser.java | 38 +-- .../MultipartTestNamespaceHandler.java | 38 +-- .../rest/multiparttest/model/Metadata.java | 294 ++++++++++++++++++ .../multiparttest/model/PutObjectResult.java | 251 +++++++++++++++ .../request/MultiparttestControllerApi.java | 37 +-- .../MultipartTestBeanConfiguration.java | 37 +-- .../citrus/PetStoreAbstractTestRequest.java | 37 +-- .../citrus/PetStoreBeanDefinitionParser.java | 38 +-- .../extension/PetStoreNamespaceHandler.java | 38 +-- .../rest/petstore/model/Category.java | 119 +++++++ .../rest/petstore/model/ModelApiResponse.java | 145 +++++++++ .../rest/petstore/model/Order.java | 259 +++++++++++++++ .../expectedgen/rest/petstore/model/Pet.java | 279 +++++++++++++++++ .../expectedgen/rest/petstore/model/Tag.java | 119 +++++++ .../expectedgen/rest/petstore/model/User.java | 275 ++++++++++++++++ .../rest/petstore/request/PetApi.java | 37 +-- .../rest/petstore/request/StoreApi.java | 37 +-- .../rest/petstore/request/UserApi.java | 37 +-- .../spring/PetStoreBeanConfiguration.java | 37 +-- .../OpenApiFromWsdlAbstractTestRequest.java | 37 +-- .../OpenApiFromWsdlBeanDefinitionParser.java | 38 +-- .../OpenApiFromWsdlNamespaceHandler.java | 38 +-- .../request/BookServiceSoapApi.java | 37 +-- .../OpenApiFromWsdlBeanConfiguration.java | 37 +-- .../rest/multiparttest/model/Metadata.java | 1 - .../multiparttest/model/PutObjectResult.java | 1 - .../rest/petstore/model/Category.java | 1 - .../rest/petstore/model/ModelApiResponse.java | 1 - .../rest/petstore/model/Order.java | 1 - .../expectedgen/rest/petstore/model/Pet.java | 1 - .../expectedgen/rest/petstore/model/Tag.java | 1 - .../expectedgen/rest/petstore/model/User.java | 1 - .../maven/plugin/TestApiGeneratorMojo.java | 1 - 49 files changed, 2203 insertions(+), 611 deletions(-) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/licenseInfo.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java (91%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java (92%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java (61%) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java (97%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java (65%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java (91%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java (92%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java (78%) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/request/PetApi.java (97%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/request/StoreApi.java (95%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/request/UserApi.java (97%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java (80%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java (89%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java (92%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java (50%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/soap/bookservice/request/BookServiceSoapApi.java (93%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIntegrationTest => JavaCitrusCodegenIT}/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java (52%) delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index 4681188d7e..5e1af11aa2 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -17,6 +17,10 @@ Citrus :: Test API Generator :: Core Generates a Citrus Test-API for OpenAPI and WSDL specifications. + + ${project.build.directory}/openapi-java-resources + + org.citrusframework @@ -118,6 +122,64 @@ + + org.apache.maven.plugins + maven-dependency-plugin + 3.7.1 + + + + org.openapitools + openapi-generator + ${org.openapitools.version} + Java/*Annotation*.mustache,Java/*Model*.mustache,Java/model*.mustache,Java/pojo*.mustache + + + + ${openapi-java-folder} + + + + + unpack-java-templates + generate-resources + + unpack + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + + prepare-java-templates + process-resources + + copy-resources + + + ${project.build.outputDirectory}/java-citrus + + + + ${openapi-java-folder}/Java + + + + *.mustache + + + + + + + + + org.openapitools openapi-generator-maven-plugin diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java index d62d4c1a9d..c624c885f6 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java @@ -85,6 +85,7 @@ public JavaCitrusCodegen() { // set default additionalProperties.put(API_TYPE, API_TYPE_REST); + additionalProperties.put("useJakartaEe", true); // add additional reserved words used in CitrusAbstractTestRequest and its base class to prevent name collisions Set reservedWordsTemp = reservedWords(); @@ -119,8 +120,7 @@ public JavaCitrusCodegen() { newString(API_ENDPOINT, "Which http client should be used (default " + httpClient + ").")); cliOptions.add( - newString( - API_TYPE, + newString(API_TYPE, "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" ) ); @@ -135,10 +135,8 @@ public JavaCitrusCodegen() { newString(OPENAPI_SCHEMA, "Which OpenAPI schema should be used (default " + openapiSchema + ").")); cliOptions.add( - newString( - PREFIX, - "Add a prefix before the name of the files. First character should be upper case (default " - + apiPrefix + ")." + newString(PREFIX, + "Add a prefix before the name of the files. First character should be upper case (default " + apiPrefix + ")." ) ); cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 36d6186da8..a023345fb7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -1,28 +1,7 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{package}}; -import jakarta.annotation.Generated; import org.citrusframework.testapi.GeneratedApi; import org.citrusframework.testapi.GeneratedApiRequest; import jakarta.servlet.http.Cookie; @@ -52,7 +31,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{classname}} implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache index 6db53348df..ba2f8d48a6 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -1,28 +1,7 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{package}}; -import jakarta.annotation.Generated; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -45,7 +24,7 @@ import org.springframework.util.CollectionUtils; import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{classname}} implements GeneratedApi { public static final {{classname}} INSTANCE = new {{classname}}(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache index a895518c45..7bf35af55f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -1,24 +1,4 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{invokerPackage}}.spring; @@ -29,13 +9,12 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT import {{package}}.{{classname}}; {{/apis}} {{/apiInfo}} -import javax.annotation.processing.Generated; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{prefix}}BeanConfiguration { {{#apiInfo}} {{#apis}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache index b6b205a521..01e502f284 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache @@ -1,24 +1,4 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{invokerPackage}}.citrus; @@ -28,8 +8,6 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.processing.Generated; - import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -42,7 +20,7 @@ import org.w3c.dom.Attr; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{prefix}}BeanDefinitionParser implements BeanDefinitionParser { private static final String COOKIE = "cookie"; diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/licenseInfo.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/licenseInfo.mustache new file mode 100644 index 0000000000..c719a5151a --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/licenseInfo.mustache @@ -0,0 +1,15 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model.mustache +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache deleted file mode 100644 index f8737ed4d9..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/model_doc.mustache +++ /dev/null @@ -1 +0,0 @@ -# not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache index 535f504b0b..8ca4a446da 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -1,24 +1,4 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{invokerPackage}}.citrus.extension; @@ -29,11 +9,9 @@ import {{package}}.{{classname}}; {{/apiInfo}} import {{invokerPackage}}.citrus.{{prefix}}BeanDefinitionParser; -import javax.annotation.processing.Generated; - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{prefix}}NamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache index a3de4774fb..be87ee214a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache @@ -1,30 +1,9 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{invokerPackage}}.citrus; import static org.springframework.util.CollectionUtils.isEmpty; -import jakarta.annotation.Generated; import jakarta.annotation.Nullable; import java.util.List; import java.util.Map; @@ -51,7 +30,7 @@ import org.slf4j.MarkerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache index bd49969597..04f3c5568c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache @@ -1,28 +1,7 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +{{>licenseInfo}} package {{invokerPackage}}.citrus; -import jakarta.annotation.Generated; import java.util.List; import java.util.ServiceLoader; import org.citrusframework.actions.AbstractTestAction; @@ -48,7 +27,7 @@ import org.springframework.util.CollectionUtils; import javax.sql.DataSource; import java.util.Map; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java index 0240db1100..4ad6df823a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java @@ -77,8 +77,10 @@ @ExtendWith({CitrusSpringExtension.class}) @SpringBootTest(classes = {CitrusSpringConfig.class, GeneratedApiIT.Config.class}) @TestPropertySource( - properties = {"applicationServiceClient.basic.username=Max Mustermann", - "applicationServiceClient.basic.password=Top secret"} + properties = { + "applicationServiceClient.basic.username=Max Mustermann", + "applicationServiceClient.basic.password=Top secret" + } ) class GeneratedApiIT { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java index 49230954ba..1d205f9400 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java @@ -1,12 +1,20 @@ package org.citrusframework.openapi.generator; +import static java.nio.file.Files.readString; +import static java.nio.file.Files.walk; import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.openapi.generator.JavaCitrusCodegenTest.getAbsoluteTargetDirectoryPath; +import static org.citrusframework.openapi.generator.JavaCitrusCodegenTest.getAbsoluteTestResourcePath; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.stream.Stream; import org.apache.commons.lang3.stream.Streams; import org.citrusframework.exceptions.CitrusRuntimeException; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -17,20 +25,41 @@ /** * This test case is designed to validate the consistency of the code generation process and detect * any discrepancies between the generated API files and the reference files stored in - * '/JavaCitrusCodegenIntegrationTest/expectedgen/'. It compares the results of API generation - * against the reference files, and a failure indicates potential changes in mustache templates or - * code generation logic. + * '/JavaCitrusCodegenIT/expectedgen/'. It compares the results of API generation against the + * reference files, and a failure indicates potential changes in mustache templates or code + * generation logic. *

    * If this test fails, it is essential to review the code generation process and underlying * templates carefully. If the changes are intentional and verified, update the reference files by - * copying the generated API sources to the '/JavaCitrusCodegenIntegrationTest/expectedgen/' - * directory. To ensure accurate copying, without unwanted code formatting, use a simple File - * Explorer instead of relying on IDE-based operations. + * copying the generated API sources to the '/JavaCitrusCodegenIT/expectedgen/' directory. To ensure + * accurate copying, without unwanted code formatting, use a simple File Explorer instead of relying + * on IDE-based operations. */ class JavaCitrusCodegenIT { + public static final String BASE_PACKAGE = "org/citrusframework/openapi/generator"; + + private static long countFilesRecursively(Path dir) throws IOException { + try (Stream walk = walk(dir)) { + return walk.filter(Files::isRegularFile).count(); + } + } + + @Test + void noAdditionalFiles() throws IOException { + long expectedFileCount = countFilesRecursively( + Path.of(getAbsoluteTestResourcePath( + BASE_PACKAGE + "/JavaCitrusCodegenIT/expectedgen/rest"))); + long actualFileCount = countFilesRecursively( + Path.of(getAbsoluteTargetDirectoryPath( + "generated-test-sources/" + BASE_PACKAGE + "/rest"))); + + assertEquals(expectedFileCount, actualFileCount, + "Directories do not have the same number of files."); + } + static Stream getResourcesForRest() throws IOException { - return geClassResourcesIgnoringInnerClasses("org/citrusframework/openapi/generator/rest"); + return geClassResourcesIgnoringInnerClasses(BASE_PACKAGE + "/rest"); } @ParameterizedTest @@ -38,7 +67,8 @@ static Stream getResourcesForRest() throws IOException { void testGeneratedFiles(Resource resource) throws IOException { File classFile = resource.getFile(); String absolutePath = classFile.getAbsolutePath(); - String javaFilePath = absolutePath.replace("test-classes", "generated-test-sources") + String javaFilePath = absolutePath + .replace("test-classes", "generated-test-sources") .replace(".class", ".java"); assertFileContent(new File(javaFilePath), "rest"); @@ -46,7 +76,7 @@ void testGeneratedFiles(Resource resource) throws IOException { static Stream getResourcesForSoap() throws IOException { return geClassResourcesIgnoringInnerClasses( - "org/citrusframework/openapi/generator/soap/bookservice"); + BASE_PACKAGE + "/soap/bookservice"); } @ParameterizedTest @@ -55,7 +85,8 @@ void testGeneratedSoapFiles(Resource resource) throws IOException { File classFile = resource.getFile(); String absolutePath = classFile.getAbsolutePath(); - String javaFilePath = absolutePath.replace("test-classes", "generated-test-sources") + String javaFilePath = absolutePath + .replace("test-classes", "generated-test-sources") .replace(".class", ".java"); assertFileContent(new File(javaFilePath), "soap"); @@ -63,29 +94,39 @@ void testGeneratedSoapFiles(Resource resource) throws IOException { private static Stream geClassResourcesIgnoringInnerClasses(String path) throws IOException { - return Streams.of(new PathMatchingResourcePatternResolver().getResources( - path + "/**/*.class")).filter(resource -> { - try { - return !resource.getURI().toString().contains("$"); - } catch (Exception e) { - throw new CitrusRuntimeException("Unable to retrieve URL from resource!"); - } - }).map(Arguments::arguments); + return Streams.of( + new PathMatchingResourcePatternResolver().getResources(path + "/**/*.class")) + .filter(resource -> { + try { + return !resource.getURI().toString().contains("$"); + } catch (Exception e) { + throw new CitrusRuntimeException("Unable to retrieve URL from resource!"); + } + } + ).map(Arguments::arguments); } + /* + * NOTE: when changes have been performed to mustache templates, the expected files need to be updated. + * Be aware that file content may change according to IDE formatting rules if the files are copied via IDE. + * Files should therefore be copied using a file explorer which ensures that content of files does not change. + */ private void assertFileContent(File file, String apiDir) throws IOException { assertThat(file).exists(); - String expectedFilePath = - "org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/" - + file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(apiDir)); + String expectedFilePath = BASE_PACKAGE + "/JavaCitrusCodegenIT/expectedgen/" + file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(apiDir)); ClassPathResource classPathResource = new ClassPathResource(expectedFilePath); - /* - * NOTE: when changes have been performed to mustache templates, the expected files need to be updated. - * Be aware that file content may change according to IDE formatting rules if the files are copied via IDE. - * Files should therefore be copied using a file explorer which ensures that content of files does not change. - */ - assertThat(file).hasSameTextualContentAs(classPathResource.getFile()); + String actualContent = readString(file.toPath()); + String expectedContent = readString(classPathResource.getFile().toPath()); + + // Replace "Generated" with a placeholder + String generatedAnnotationPattern = "@jakarta\\.annotation\\.Generated\\(.*?\\)"; + String placeholder = "@jakarta.annotation.Generated(value = \"org.citrusframework.openapi.generator.JavaCitrusCodegen\", date = \"TIMESTAMP\", comments = \"Generator version: VERSION\")"; + + actualContent = actualContent.replaceAll(generatedAnnotationPattern, placeholder); + expectedContent = expectedContent.replaceAll(generatedAnnotationPattern, placeholder); + + assertThat(actualContent).isEqualTo(expectedContent); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java index 9c6874c5de..f3860de3b4 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java @@ -39,8 +39,8 @@ class JavaCitrusCodegenTest { * @param pathToFileInTestResources The file within {@code src/test/resources} to look for * @return the absolute path to the file */ - private String getTestResource(String pathToFileInTestResources) { - URL resourceUrl = getClass().getClassLoader().getResource(pathToFileInTestResources); + static String getAbsoluteTestResourcePath(String pathToFileInTestResources) { + URL resourceUrl = JavaCitrusCodegenTest.class.getClassLoader().getResource(pathToFileInTestResources); assert resourceUrl != null; File inputSpecFile = new File(resourceUrl.getFile()); return inputSpecFile.getAbsolutePath(); @@ -52,7 +52,7 @@ private String getTestResource(String pathToFileInTestResources) { * @param pathToFileInTargetDirectory The file within {@code target} to look for * @return the absolute path to the file */ - private static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { + static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); return outputDirFile.getAbsolutePath(); @@ -109,7 +109,7 @@ void areAdditionalPropertiesProcessedTest() { @Test void areReservedWordsEscapedTest() throws IOException { - String absoluteInputSpecPath = getTestResource("apis/petstore_reservedWords.yaml"); + String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore_reservedWords.yaml"); String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore_escapedWords"); final CodegenConfigurator configurator = new CodegenConfigurator() @@ -121,7 +121,8 @@ void areReservedWordsEscapedTest() throws IOException { DefaultGenerator generator = new DefaultGenerator(); List outputFiles = generator.opts(clientOptInput).generate(); - Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + Optional file = outputFiles.stream() + .filter(x -> "PetApi.java".equals(x.getName())) .findFirst(); assertThat(file).isPresent(); @@ -129,12 +130,16 @@ void areReservedWordsEscapedTest() throws IOException { List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat(lines.stream().filter(x -> x.contains("\"name\", this._name")).count()).isEqualTo(1L); + assertThat( + lines.stream() + .filter(x -> x.contains("\"name\", this._name")) + .count()) + .isEqualTo(1L); } @Test void arePathParamsFieldsPresent() throws IOException { - String absoluteInputSpecPath = getTestResource("apis/petstore.yaml"); + String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore.yaml"); String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); final CodegenConfigurator configurator = new CodegenConfigurator() @@ -146,7 +151,8 @@ void arePathParamsFieldsPresent() throws IOException { DefaultGenerator generator = new DefaultGenerator(); List outputFiles = generator.opts(clientOptInput).generate(); - Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + Optional file = outputFiles.stream() + .filter(x -> "PetApi.java".equals(x.getName())) .findFirst(); assertThat(file).isPresent(); @@ -154,15 +160,22 @@ void arePathParamsFieldsPresent() throws IOException { List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat(lines.stream().filter(x -> x.contains("private String petId;")).count()).isEqualTo(4L); - assertThat(lines.stream().filter( - x -> x.contains("endpoint = endpoint.replace(\"{\" + \"petId\" + \"}\", petId);")) - .count()).isEqualTo(4L); + assertThat( + lines.stream() + .filter(x -> x.contains("private String petId;")) + .count()) + .isEqualTo(4L); + assertThat( + lines.stream() + .filter(x -> x.contains( + "endpoint = endpoint.replace(\"{\" + \"petId\" + \"}\", petId);")) + .count()) + .isEqualTo(4L); } @Test void areBasicAuthFieldsPresent() throws IOException { - String absoluteInputSpecPath = getTestResource("apis/petstore.yaml"); + String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore.yaml"); String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); final CodegenConfigurator configurator = new CodegenConfigurator() @@ -174,7 +187,8 @@ void areBasicAuthFieldsPresent() throws IOException { DefaultGenerator generator = new DefaultGenerator(); List outputFiles = generator.opts(clientOptInput).generate(); - Optional file = outputFiles.stream().filter(x -> "PetApi.java".equals(x.getName())) + Optional file = outputFiles.stream() + .filter(x -> "PetApi.java".equals(x.getName())) .findFirst(); assertThat(file).isPresent(); @@ -182,20 +196,24 @@ void areBasicAuthFieldsPresent() throws IOException { List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat(lines.stream() - .filter(x -> x.contains("@Value(\"${\" + \"apiEndpoint.basic.username:#{null}}\")")) - .count()).isEqualTo(1L); assertThat( - lines.stream().filter(x -> x.contains("private String basicUsername;")).count()).isEqualTo(1L); + lines.stream() + .filter(x -> x.contains("@Value(\"${\" + \"apiEndpoint.basic.username:#{null}}\")")) + .count()) + .isEqualTo(1L); + assertThat( + lines.stream() + .filter(x -> x.contains("private String basicUsername;")) + .count()) + .isEqualTo(1L); assertThat( - lines - .stream() + lines.stream() .filter(x -> x.contains( "messageBuilderSupport.header(\"Authorization\", \"Basic \" + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+\":\"+context.replaceDynamicContentInString(basicPassword)).getBytes()));" ) ) - .count() - ).isEqualTo(1L); + .count()) + .isEqualTo(1L); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java similarity index 91% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java index 01092606ba..d66cc3aa30 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java @@ -1,30 +1,23 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.multiparttest.citrus; import static org.springframework.util.CollectionUtils.isEmpty; -import jakarta.annotation.Generated; import jakarta.annotation.Nullable; import java.util.List; import java.util.Map; @@ -51,7 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public abstract class MultipartTestAbstractTestRequest extends AbstractTestAction { protected final Marker coverageMarker = MarkerFactory.getMarker("MULTIPARTTEST-API-COVERAGE"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java similarity index 92% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java index 37df5ee8b9..1102147b82 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java @@ -1,24 +1,18 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.multiparttest.citrus; @@ -28,8 +22,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.processing.Generated; - import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -42,7 +34,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class MultipartTestBeanDefinitionParser implements BeanDefinitionParser { private static final String COOKIE = "cookie"; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java similarity index 61% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java index 4517c7a801..edd3e67e73 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java @@ -1,35 +1,27 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.multiparttest.citrus.extension; import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; import org.citrusframework.openapi.generator.rest.multiparttest.citrus.MultipartTestBeanDefinitionParser; -import javax.annotation.processing.Generated; - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class MultipartTestNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java new file mode 100644 index 0000000000..dbd2bcb664 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java @@ -0,0 +1,294 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.multiparttest.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; + +/** + * Metadata + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Metadata { + private Map userMetadata = new HashMap<>(); + + private Map rawMetadata = new HashMap<>(); + + private OffsetDateTime httpExpiresDate; + + private OffsetDateTime expirationTime; + + private String expirationTimeRuleId; + + private Boolean ongoingRestore; + + private OffsetDateTime restoreExpirationTime; + + private Boolean bucketKeyEnabled; + + public Metadata() { + } + + public Metadata userMetadata(Map userMetadata) { + + this.userMetadata = userMetadata; + return this; + } + + public Metadata putUserMetadataItem(String key, String userMetadataItem) { + if (this.userMetadata == null) { + this.userMetadata = new HashMap<>(); + } + this.userMetadata.put(key, userMetadataItem); + return this; + } + + /** + * Get userMetadata + * @return userMetadata + **/ + @jakarta.annotation.Nullable + + public Map getUserMetadata() { + return userMetadata; + } + + + public void setUserMetadata(Map userMetadata) { + this.userMetadata = userMetadata; + } + + + public Metadata rawMetadata(Map rawMetadata) { + + this.rawMetadata = rawMetadata; + return this; + } + + public Metadata putRawMetadataItem(String key, String rawMetadataItem) { + if (this.rawMetadata == null) { + this.rawMetadata = new HashMap<>(); + } + this.rawMetadata.put(key, rawMetadataItem); + return this; + } + + /** + * Get rawMetadata + * @return rawMetadata + **/ + @jakarta.annotation.Nullable + + public Map getRawMetadata() { + return rawMetadata; + } + + + public void setRawMetadata(Map rawMetadata) { + this.rawMetadata = rawMetadata; + } + + + public Metadata httpExpiresDate(OffsetDateTime httpExpiresDate) { + + this.httpExpiresDate = httpExpiresDate; + return this; + } + + /** + * Get httpExpiresDate + * @return httpExpiresDate + **/ + @jakarta.annotation.Nullable + + public OffsetDateTime getHttpExpiresDate() { + return httpExpiresDate; + } + + + public void setHttpExpiresDate(OffsetDateTime httpExpiresDate) { + this.httpExpiresDate = httpExpiresDate; + } + + + public Metadata expirationTime(OffsetDateTime expirationTime) { + + this.expirationTime = expirationTime; + return this; + } + + /** + * Get expirationTime + * @return expirationTime + **/ + @jakarta.annotation.Nullable + + public OffsetDateTime getExpirationTime() { + return expirationTime; + } + + + public void setExpirationTime(OffsetDateTime expirationTime) { + this.expirationTime = expirationTime; + } + + + public Metadata expirationTimeRuleId(String expirationTimeRuleId) { + + this.expirationTimeRuleId = expirationTimeRuleId; + return this; + } + + /** + * Get expirationTimeRuleId + * @return expirationTimeRuleId + **/ + @jakarta.annotation.Nullable + + public String getExpirationTimeRuleId() { + return expirationTimeRuleId; + } + + + public void setExpirationTimeRuleId(String expirationTimeRuleId) { + this.expirationTimeRuleId = expirationTimeRuleId; + } + + + public Metadata ongoingRestore(Boolean ongoingRestore) { + + this.ongoingRestore = ongoingRestore; + return this; + } + + /** + * Get ongoingRestore + * @return ongoingRestore + **/ + @jakarta.annotation.Nullable + + public Boolean getOngoingRestore() { + return ongoingRestore; + } + + + public void setOngoingRestore(Boolean ongoingRestore) { + this.ongoingRestore = ongoingRestore; + } + + + public Metadata restoreExpirationTime(OffsetDateTime restoreExpirationTime) { + + this.restoreExpirationTime = restoreExpirationTime; + return this; + } + + /** + * Get restoreExpirationTime + * @return restoreExpirationTime + **/ + @jakarta.annotation.Nullable + + public OffsetDateTime getRestoreExpirationTime() { + return restoreExpirationTime; + } + + + public void setRestoreExpirationTime(OffsetDateTime restoreExpirationTime) { + this.restoreExpirationTime = restoreExpirationTime; + } + + + public Metadata bucketKeyEnabled(Boolean bucketKeyEnabled) { + + this.bucketKeyEnabled = bucketKeyEnabled; + return this; + } + + /** + * Get bucketKeyEnabled + * @return bucketKeyEnabled + **/ + @jakarta.annotation.Nullable + + public Boolean getBucketKeyEnabled() { + return bucketKeyEnabled; + } + + + public void setBucketKeyEnabled(Boolean bucketKeyEnabled) { + this.bucketKeyEnabled = bucketKeyEnabled; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Metadata metadata = (Metadata) o; + return Objects.equals(this.userMetadata, metadata.userMetadata) && + Objects.equals(this.rawMetadata, metadata.rawMetadata) && + Objects.equals(this.httpExpiresDate, metadata.httpExpiresDate) && + Objects.equals(this.expirationTime, metadata.expirationTime) && + Objects.equals(this.expirationTimeRuleId, metadata.expirationTimeRuleId) && + Objects.equals(this.ongoingRestore, metadata.ongoingRestore) && + Objects.equals(this.restoreExpirationTime, metadata.restoreExpirationTime) && + Objects.equals(this.bucketKeyEnabled, metadata.bucketKeyEnabled); + } + + @Override + public int hashCode() { + return Objects.hash(userMetadata, rawMetadata, httpExpiresDate, expirationTime, expirationTimeRuleId, ongoingRestore, restoreExpirationTime, bucketKeyEnabled); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Metadata {\n"); + sb.append(" userMetadata: ").append(toIndentedString(userMetadata)).append("\n"); + sb.append(" rawMetadata: ").append(toIndentedString(rawMetadata)).append("\n"); + sb.append(" httpExpiresDate: ").append(toIndentedString(httpExpiresDate)).append("\n"); + sb.append(" expirationTime: ").append(toIndentedString(expirationTime)).append("\n"); + sb.append(" expirationTimeRuleId: ").append(toIndentedString(expirationTimeRuleId)).append("\n"); + sb.append(" ongoingRestore: ").append(toIndentedString(ongoingRestore)).append("\n"); + sb.append(" restoreExpirationTime: ").append(toIndentedString(restoreExpirationTime)).append("\n"); + sb.append(" bucketKeyEnabled: ").append(toIndentedString(bucketKeyEnabled)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java new file mode 100644 index 0000000000..8e3abaa146 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java @@ -0,0 +1,251 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.multiparttest.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.OffsetDateTime; +import org.citrusframework.openapi.generator.rest.multiparttest.model.Metadata; + +/** + * PutObjectResult + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PutObjectResult { + private String versionId; + + private String eTag; + + private OffsetDateTime expirationTime; + + private String expirationTimeRuleId; + + private String contentMd5; + + private Metadata metadata; + + private Boolean isRequesterCharged; + + public PutObjectResult() { + } + + public PutObjectResult versionId(String versionId) { + + this.versionId = versionId; + return this; + } + + /** + * Get versionId + * @return versionId + **/ + @jakarta.annotation.Nullable + + public String getVersionId() { + return versionId; + } + + + public void setVersionId(String versionId) { + this.versionId = versionId; + } + + + public PutObjectResult eTag(String eTag) { + + this.eTag = eTag; + return this; + } + + /** + * Get eTag + * @return eTag + **/ + @jakarta.annotation.Nullable + + public String geteTag() { + return eTag; + } + + + public void seteTag(String eTag) { + this.eTag = eTag; + } + + + public PutObjectResult expirationTime(OffsetDateTime expirationTime) { + + this.expirationTime = expirationTime; + return this; + } + + /** + * Get expirationTime + * @return expirationTime + **/ + @jakarta.annotation.Nullable + + public OffsetDateTime getExpirationTime() { + return expirationTime; + } + + + public void setExpirationTime(OffsetDateTime expirationTime) { + this.expirationTime = expirationTime; + } + + + public PutObjectResult expirationTimeRuleId(String expirationTimeRuleId) { + + this.expirationTimeRuleId = expirationTimeRuleId; + return this; + } + + /** + * Get expirationTimeRuleId + * @return expirationTimeRuleId + **/ + @jakarta.annotation.Nullable + + public String getExpirationTimeRuleId() { + return expirationTimeRuleId; + } + + + public void setExpirationTimeRuleId(String expirationTimeRuleId) { + this.expirationTimeRuleId = expirationTimeRuleId; + } + + + public PutObjectResult contentMd5(String contentMd5) { + + this.contentMd5 = contentMd5; + return this; + } + + /** + * Get contentMd5 + * @return contentMd5 + **/ + @jakarta.annotation.Nullable + + public String getContentMd5() { + return contentMd5; + } + + + public void setContentMd5(String contentMd5) { + this.contentMd5 = contentMd5; + } + + + public PutObjectResult metadata(Metadata metadata) { + + this.metadata = metadata; + return this; + } + + /** + * Get metadata + * @return metadata + **/ + @jakarta.annotation.Nullable + + public Metadata getMetadata() { + return metadata; + } + + + public void setMetadata(Metadata metadata) { + this.metadata = metadata; + } + + + public PutObjectResult isRequesterCharged(Boolean isRequesterCharged) { + + this.isRequesterCharged = isRequesterCharged; + return this; + } + + /** + * Get isRequesterCharged + * @return isRequesterCharged + **/ + @jakarta.annotation.Nullable + + public Boolean getIsRequesterCharged() { + return isRequesterCharged; + } + + + public void setIsRequesterCharged(Boolean isRequesterCharged) { + this.isRequesterCharged = isRequesterCharged; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PutObjectResult putObjectResult = (PutObjectResult) o; + return Objects.equals(this.versionId, putObjectResult.versionId) && + Objects.equals(this.eTag, putObjectResult.eTag) && + Objects.equals(this.expirationTime, putObjectResult.expirationTime) && + Objects.equals(this.expirationTimeRuleId, putObjectResult.expirationTimeRuleId) && + Objects.equals(this.contentMd5, putObjectResult.contentMd5) && + Objects.equals(this.metadata, putObjectResult.metadata) && + Objects.equals(this.isRequesterCharged, putObjectResult.isRequesterCharged); + } + + @Override + public int hashCode() { + return Objects.hash(versionId, eTag, expirationTime, expirationTimeRuleId, contentMd5, metadata, isRequesterCharged); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PutObjectResult {\n"); + sb.append(" versionId: ").append(toIndentedString(versionId)).append("\n"); + sb.append(" eTag: ").append(toIndentedString(eTag)).append("\n"); + sb.append(" expirationTime: ").append(toIndentedString(expirationTime)).append("\n"); + sb.append(" expirationTimeRuleId: ").append(toIndentedString(expirationTimeRuleId)).append("\n"); + sb.append(" contentMd5: ").append(toIndentedString(contentMd5)).append("\n"); + sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); + sb.append(" isRequesterCharged: ").append(toIndentedString(isRequesterCharged)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java similarity index 97% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java index 7ced338bb8..85f1b174b2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.multiparttest.request; -import jakarta.annotation.Generated; import org.citrusframework.testapi.GeneratedApi; import org.citrusframework.testapi.GeneratedApiRequest; import jakarta.servlet.http.Cookie; @@ -52,7 +45,7 @@ import java.util.Map; import java.util.stream.Collectors; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class MultiparttestControllerApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java similarity index 65% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java index d93b11f104..d5fd2b4a60 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java @@ -1,37 +1,30 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.multiparttest.spring; import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; -import javax.annotation.processing.Generated; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class MultipartTestBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java similarity index 91% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java index 29a409ea85..222b2f239f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java @@ -1,30 +1,23 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.citrus; import static org.springframework.util.CollectionUtils.isEmpty; -import jakarta.annotation.Generated; import jakarta.annotation.Nullable; import java.util.List; import java.util.Map; @@ -51,7 +44,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public abstract class PetStoreAbstractTestRequest extends AbstractTestAction { protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java similarity index 92% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java index f7ee721e6c..d1018d8efb 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java @@ -1,24 +1,18 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.citrus; @@ -28,8 +22,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.processing.Generated; - import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -42,7 +34,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreBeanDefinitionParser implements BeanDefinitionParser { private static final String COOKIE = "cookie"; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java similarity index 78% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java index b7bb6298c1..ac9e93f527 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java @@ -1,24 +1,18 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.citrus.extension; @@ -27,11 +21,9 @@ import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreBeanDefinitionParser; -import javax.annotation.processing.Generated; - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java new file mode 100644 index 0000000000..e53e2d9247 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java @@ -0,0 +1,119 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * A category for a pet + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Category { + private Long id; + + private String _name; + + public Category() { + } + + public Category id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Category _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java new file mode 100644 index 0000000000..c75502f466 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -0,0 +1,145 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * Describes the result of uploading an image resource + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class ModelApiResponse { + private Integer code; + + private String _type; + + private String message; + + public ModelApiResponse() { + } + + public ModelApiResponse code(Integer code) { + + this.code = code; + return this; + } + + /** + * Get code + * @return code + **/ + @jakarta.annotation.Nullable + + public Integer getCode() { + return code; + } + + + public void setCode(Integer code) { + this.code = code; + } + + + public ModelApiResponse _type(String _type) { + + this._type = _type; + return this; + } + + /** + * Get _type + * @return _type + **/ + @jakarta.annotation.Nullable + + public String getType() { + return _type; + } + + + public void setType(String _type) { + this._type = _type; + } + + + public ModelApiResponse message(String message) { + + this.message = message; + return this; + } + + /** + * Get message + * @return message + **/ + @jakarta.annotation.Nullable + + public String getMessage() { + return message; + } + + + public void setMessage(String message) { + this.message = message; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModelApiResponse _apiResponse = (ModelApiResponse) o; + return Objects.equals(this.code, _apiResponse.code) && + Objects.equals(this._type, _apiResponse._type) && + Objects.equals(this.message, _apiResponse.message); + } + + @Override + public int hashCode() { + return Objects.hash(code, _type, message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ModelApiResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" _type: ").append(toIndentedString(_type)).append("\n"); + sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java new file mode 100644 index 0000000000..e35a75223b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java @@ -0,0 +1,259 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.OffsetDateTime; + +/** + * An order for a pets from the pet store + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Order { + private Long id; + + private Long petId; + + private Integer quantity; + + private OffsetDateTime shipDate; + + /** + * Order Status + */ + public enum StatusEnum { + PLACED("placed"), + + APPROVED("approved"), + + DELIVERED("delivered"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + private StatusEnum status; + + private Boolean complete = false; + + public Order() { + } + + public Order id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Order petId(Long petId) { + + this.petId = petId; + return this; + } + + /** + * Get petId + * @return petId + **/ + @jakarta.annotation.Nullable + + public Long getPetId() { + return petId; + } + + + public void setPetId(Long petId) { + this.petId = petId; + } + + + public Order quantity(Integer quantity) { + + this.quantity = quantity; + return this; + } + + /** + * Get quantity + * @return quantity + **/ + @jakarta.annotation.Nullable + + public Integer getQuantity() { + return quantity; + } + + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + + public Order shipDate(OffsetDateTime shipDate) { + + this.shipDate = shipDate; + return this; + } + + /** + * Get shipDate + * @return shipDate + **/ + @jakarta.annotation.Nullable + + public OffsetDateTime getShipDate() { + return shipDate; + } + + + public void setShipDate(OffsetDateTime shipDate) { + this.shipDate = shipDate; + } + + + public Order status(StatusEnum status) { + + this.status = status; + return this; + } + + /** + * Order Status + * @return status + **/ + @jakarta.annotation.Nullable + + public StatusEnum getStatus() { + return status; + } + + + public void setStatus(StatusEnum status) { + this.status = status; + } + + + public Order complete(Boolean complete) { + + this.complete = complete; + return this; + } + + /** + * Get complete + * @return complete + **/ + @jakarta.annotation.Nullable + + public Boolean getComplete() { + return complete; + } + + + public void setComplete(Boolean complete) { + this.complete = complete; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(this.id, order.id) && + Objects.equals(this.petId, order.petId) && + Objects.equals(this.quantity, order.quantity) && + Objects.equals(this.shipDate, order.shipDate) && + Objects.equals(this.status, order.status) && + Objects.equals(this.complete, order.complete); + } + + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java new file mode 100644 index 0000000000..ae8a438c5a --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java @@ -0,0 +1,279 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.citrusframework.openapi.generator.rest.petstore.model.Category; +import org.citrusframework.openapi.generator.rest.petstore.model.Tag; + +/** + * A pet for sale in the pet store + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Pet { + private Long id; + + private Category category; + + private String _name; + + private List photoUrls = new ArrayList<>(); + + private List tags = new ArrayList<>(); + + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + + PENDING("pending"), + + SOLD("sold"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + private StatusEnum status; + + public Pet() { + } + + public Pet id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Pet category(Category category) { + + this.category = category; + return this; + } + + /** + * Get category + * @return category + **/ + @jakarta.annotation.Nullable + + public Category getCategory() { + return category; + } + + + public void setCategory(Category category) { + this.category = category; + } + + + public Pet _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nonnull + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + + public Pet photoUrls(List photoUrls) { + + this.photoUrls = photoUrls; + return this; + } + + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); + } + this.photoUrls.add(photoUrlsItem); + return this; + } + + /** + * Get photoUrls + * @return photoUrls + **/ + @jakarta.annotation.Nonnull + + public List getPhotoUrls() { + return photoUrls; + } + + + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + + public Pet tags(List tags) { + + this.tags = tags; + return this; + } + + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); + } + this.tags.add(tagsItem); + return this; + } + + /** + * Get tags + * @return tags + **/ + @jakarta.annotation.Nullable + + public List getTags() { + return tags; + } + + + public void setTags(List tags) { + this.tags = tags; + } + + + public Pet status(StatusEnum status) { + + this.status = status; + return this; + } + + /** + * pet status in the store + * @return status + **/ + @jakarta.annotation.Nullable + + public StatusEnum getStatus() { + return status; + } + + + public void setStatus(StatusEnum status) { + this.status = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this.category, pet.category) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, category, _name, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java new file mode 100644 index 0000000000..aefcc664e3 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java @@ -0,0 +1,119 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * A tag for a pet + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Tag { + private Long id; + + private String _name; + + public Tag() { + } + + public Tag id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Tag _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java new file mode 100644 index 0000000000..3581497dda --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java @@ -0,0 +1,275 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * A User who is purchasing from the pet store + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class User { + private Long id; + + private String username; + + private String firstName; + + private String lastName; + + private String email; + + private String password; + + private String phone; + + private Integer userStatus; + + public User() { + } + + public User id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public User username(String username) { + + this.username = username; + return this; + } + + /** + * Get username + * @return username + **/ + @jakarta.annotation.Nullable + + public String getUsername() { + return username; + } + + + public void setUsername(String username) { + this.username = username; + } + + + public User firstName(String firstName) { + + this.firstName = firstName; + return this; + } + + /** + * Get firstName + * @return firstName + **/ + @jakarta.annotation.Nullable + + public String getFirstName() { + return firstName; + } + + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + + public User lastName(String lastName) { + + this.lastName = lastName; + return this; + } + + /** + * Get lastName + * @return lastName + **/ + @jakarta.annotation.Nullable + + public String getLastName() { + return lastName; + } + + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + + public User email(String email) { + + this.email = email; + return this; + } + + /** + * Get email + * @return email + **/ + @jakarta.annotation.Nullable + + public String getEmail() { + return email; + } + + + public void setEmail(String email) { + this.email = email; + } + + + public User password(String password) { + + this.password = password; + return this; + } + + /** + * Get password + * @return password + **/ + @jakarta.annotation.Nullable + + public String getPassword() { + return password; + } + + + public void setPassword(String password) { + this.password = password; + } + + + public User phone(String phone) { + + this.phone = phone; + return this; + } + + /** + * Get phone + * @return phone + **/ + @jakarta.annotation.Nullable + + public String getPhone() { + return phone; + } + + + public void setPhone(String phone) { + this.phone = phone; + } + + + public User userStatus(Integer userStatus) { + + this.userStatus = userStatus; + return this; + } + + /** + * User Status + * @return userStatus + **/ + @jakarta.annotation.Nullable + + public Integer getUserStatus() { + return userStatus; + } + + + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(this.id, user.id) && + Objects.equals(this.username, user.username) && + Objects.equals(this.firstName, user.firstName) && + Objects.equals(this.lastName, user.lastName) && + Objects.equals(this.email, user.email) && + Objects.equals(this.password, user.password) && + Objects.equals(this.phone, user.phone) && + Objects.equals(this.userStatus, user.userStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(toIndentedString(email)).append("\n"); + sb.append(" password: ").append(toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java similarity index 97% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java index 570912da01..41a154158e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.request; -import jakarta.annotation.Generated; import org.citrusframework.testapi.GeneratedApi; import org.citrusframework.testapi.GeneratedApiRequest; import jakarta.servlet.http.Cookie; @@ -52,7 +45,7 @@ import java.util.Map; import java.util.stream.Collectors; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java similarity index 95% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java index b7d6754a4f..db50a61387 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.request; -import jakarta.annotation.Generated; import org.citrusframework.testapi.GeneratedApi; import org.citrusframework.testapi.GeneratedApiRequest; import jakarta.servlet.http.Cookie; @@ -52,7 +45,7 @@ import java.util.Map; import java.util.stream.Collectors; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class StoreApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java similarity index 97% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java index 7c89b95787..6b07c599a5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.request; -import jakarta.annotation.Generated; import org.citrusframework.testapi.GeneratedApi; import org.citrusframework.testapi.GeneratedApiRequest; import jakarta.servlet.http.Cookie; @@ -52,7 +45,7 @@ import java.util.Map; import java.util.stream.Collectors; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class UserApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java similarity index 80% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index bf6750e796..9b31309e7a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -1,24 +1,18 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.spring; @@ -27,13 +21,12 @@ import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; -import javax.annotation.processing.Generated; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java similarity index 89% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java index 4e493250fc..78cc8b5bcf 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.soap.bookservice.citrus; -import jakarta.annotation.Generated; import java.util.List; import java.util.ServiceLoader; import org.citrusframework.actions.AbstractTestAction; @@ -48,7 +41,7 @@ import javax.sql.DataSource; import java.util.Map; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public abstract class OpenApiFromWsdlAbstractTestRequest extends AbstractTestAction { protected final Marker coverageMarker = MarkerFactory.getMarker("OPENAPIFROMWSDL-API-COVERAGE"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java similarity index 92% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java index 6bb955eb0b..e777f4608c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java @@ -1,24 +1,18 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.soap.bookservice.citrus; @@ -28,8 +22,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.processing.Generated; - import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -42,7 +34,7 @@ import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class OpenApiFromWsdlBeanDefinitionParser implements BeanDefinitionParser { private static final String COOKIE = "cookie"; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java similarity index 50% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java index 9c2f110274..6454ee52fa 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java @@ -1,35 +1,27 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.soap.bookservice.citrus.extension; import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlBeanDefinitionParser; -import javax.annotation.processing.Generated; - import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class OpenApiFromWsdlNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java similarity index 93% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index f253418eec..ae5505df35 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -1,28 +1,21 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.soap.bookservice.request; -import jakarta.annotation.Generated; import java.io.IOException; import java.util.HashMap; import java.util.Map; @@ -45,7 +38,7 @@ import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class BookServiceSoapApi implements GeneratedApi { public static final BookServiceSoapApi INSTANCE = new BookServiceSoapApi(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java similarity index 52% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java index 919d03669b..b1bfeaee9d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java @@ -1,37 +1,30 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * ================================================== - * GENERATED CLASS, ALL CHANGES WILL BE LOST - * ================================================== - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.soap.bookservice.spring; import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; -import javax.annotation.processing.Generated; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; @Configuration -@Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class OpenApiFromWsdlBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/Metadata.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/multiparttest/model/PutObjectResult.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Category.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/ModelApiResponse.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Order.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Pet.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/Tag.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java deleted file mode 100644 index d5341fea2c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIntegrationTest/expectedgen/rest/petstore/model/User.java +++ /dev/null @@ -1 +0,0 @@ -// not in use diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index d37b4d8ffe..0c079c7402 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -332,7 +332,6 @@ public String qualifiedEndpoint() { } Map toConfigOptionsProperties() { - Map configOptionsProperties = new HashMap<>(); configOptionsProperties.put(PREFIX, prefix); configOptionsProperties.put(API_ENDPOINT, qualifiedEndpoint()); From 28226f6128b050df3fca5f340623a9e46323fff6 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Mon, 22 Jul 2024 00:46:39 +0200 Subject: [PATCH 15/47] new api generation --- .../actions/SendMessageAction.java | 2 +- .../citrus-test-api-generator-core/pom.xml | 5 + .../TestApiClientRequestActionBuilder.java | 69 ++++ .../main/resources/java-citrus/api.mustache | 255 +++------------ .../resources/java-citrus/api_old.mustache | 259 +++++++++++++++ .../resources/java-citrus/openApi.mustache | 83 +++++ .../openapi/generator/GetPetByIdIT.java | 172 +++++++++- .../generator/OpenApiPetStoreTest.java | 181 +++++++++++ .../generator/sample/OpenApiPetStore.java | 306 ++++++++++++++++++ .../generator/sample/OpenApiPetStore_.java | 304 +++++++++++++++++ .../openapi/generator/sample/PetApi.java | 273 ++++++++++++++++ .../PetStoreAbstractReceiveActionBuilder.java | 250 ++++++++++++++ .../PetStoreAbstractSendActionBuilder.java | 234 ++++++++++++++ 13 files changed, 2166 insertions(+), 227 deletions(-) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java index 53f6fcabd6..20fa11ccff 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java @@ -381,7 +381,7 @@ public String getEndpointUri() { /** * Action builder. */ - public static final class Builder extends SendMessageActionBuilder { + public static class Builder extends SendMessageActionBuilder { /** * Fluent API action building entry method used in Java DSL. diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index 5e1af11aa2..3af2a0689e 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -32,6 +32,11 @@ citrus-http ${project.version} + + org.citrusframework + citrus-openapi + ${project.version} + org.citrusframework citrus-spring diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java new file mode 100644 index 0000000000..7945002312 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java @@ -0,0 +1,69 @@ +package org.citrusframework.openapi.generator; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class TestApiClientRequestActionBuilder extends OpenApiClientRequestActionBuilder { + + // TODO: do we really need this? + protected OpenApiSpecification openApiSpec; + + private final String path; + + private final Map pathParameters = new HashMap<>(); + + private final MultiValueMap formData = new LinkedMultiValueMap<>(); + + // TODO: can we just pass in the operation? + public TestApiClientRequestActionBuilder(OpenApiSpecification openApiSpec, String method, String path, String operationName) { + super(openApiSpec, "%s_%s".formatted(method, path)); + name(String.format("%s:%s", "PetStore".toLowerCase(), operationName)); + getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); + getMessageBuilderSupport().header("citrus_open_api_method", method); + getMessageBuilderSupport().header("citrus_open_api_path", path); + + this.openApiSpec = openApiSpec; + this.path = path; + } + + protected void pathParameter(String name, String value) { + pathParameters.put(name, value); + } + + protected void formData(String name, String value) { + formData.add(name, value); + } + + protected String qualifiedPath(String path) { + + String qualifiedPath = path; + for (Entry entry : pathParameters.entrySet()) { + qualifiedPath = qualifiedPath.replace("{%s}".formatted(entry.getKey()), entry.getValue()); + } + return qualifiedPath; + } + + protected String toQueryParam(String...arrayElements) { + return String.join(",", arrayElements); + } + + @Override + public SendMessageAction doBuild() { + // TODO: register callback to modify builder + path(qualifiedPath(path)); + if (!formData.isEmpty()) { + // TODO: do we have to explicitly set the content type or is this done by citrus + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE); + getMessageBuilderSupport().body(formData); + } + return super.doBuild(); + } + + } \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index a023345fb7..cb2473c14b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -2,34 +2,15 @@ package {{package}}; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.stream.Collectors; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.TestApiClientRequestActionBuilder; +import org.citrusframework.openapi.generator.rest.petstore.model.Pet; +import org.citrusframework.testapi.GeneratedApi; + +import {{invokerPackage}}.citrus.{{prefix}}AbstractSendAction; {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{classname}} implements GeneratedApi @@ -37,223 +18,67 @@ public class {{classname}} implements GeneratedApi public static final {{classname}} INSTANCE = new {{classname}}(); + private OpenApiSpecification openApiSpecification = null; + public String getApiTitle() { - return "{{appName}}"; + return "{{appName}}"; } public String getApiVersion() { - return "{{appVersion}}"; + return "{{appVersion}}"; } public String getApiPrefix() { - return "{{prefix}}"; + return "{{prefix}}"; } public Map getApiInfoExtensions() { Map infoExtensionMap = new HashMap<>(); {{#infoExtensions}} {{#entrySet}} - infoExtensionMap.put("{{key}}", "{{value}}"); + infoExtensionMap.put("{{key}}", "{{value}}"); {{/entrySet}} {{/infoExtensions}} return infoExtensionMap; } - {{#operations}} +{{#operations}} {{#operation}} - /** {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) - {{summary}} - {{description}} - **/ - public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "{{httpPathPrefix}}{{{path}}}"; - private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); - - {{#queryParams}} - private String {{paramName}}; - - {{/queryParams}} - {{#pathParams}} - private String {{paramName}}; - - {{/pathParams}} - {{#isMultipart}} - {{#formParams}} - private String {{paramName}}; - - {{/formParams}} - {{/isMultipart}} - {{#authMethods}}{{#isBasic}} - @Value("${" + "{{apiEndpoint}}.basic.username:#{null}}") - private String basicUsername; - @Value("${" + "{{apiEndpoint}}.basic.password:#{null}}") - private String basicPassword; - - {{/isBasic}} - {{/authMethods}} - - public {{operationIdCamelCase}}Request() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); - } - - public String getOperationName() { - return "{{operationId}}"; + public {{operationIdCamelCase}}ActionBuilder {{operationId}}() { + return new {{operationIdCamelCase}}ActionBuilder(); } - public String getMethod() { - return "{{httpMethod}}"; - } - - public String getPath() { - return "{{path}}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - {{#isMultipart}} - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - {{#formParams}} - {{#required}} - if(StringUtils.isBlank({{paramName}})) { - throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "{{paramName}}")); - } - {{/required}} - {{#isBinary}} - if (StringUtils.isNotBlank({{paramName}})) { - multiValues.add("{{paramName}}", new ClassPathResource({{paramName}})); - bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - {{/isBinary}} - {{^isBinary}} - if (StringUtils.isNotBlank({{paramName}})) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource({{paramName}}); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("{{paramName}}", resource); - } else { - multiValues.add("{{paramName}}", {{paramName}}); - } - bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - {{/isBinary}} - {{/formParams}} - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - {{/isMultipart}} - {{^isMultipart}} - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - {{/isMultipart}} - - Map queryParams = new HashMap<>(); - {{#allParams}}{{#isQueryParam}} - - if (StringUtils.isNotBlank(this.{{paramName}})) { - queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); - httpClientRequestActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); - } - {{/isQueryParam}}{{/allParams}} - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - {{#authMethods}}{{#isBasic}} + {{/operation}} +{{/operations}} - if(basicUsername != null && basicPassword != null){ - messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); - } - {{/isBasic}}{{/authMethods}} - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); +{{#operations}} + {{#operation}} + public class {{operationIdCamelCase}}ActionBuilder extends TestApiClientRequestActionBuilder { - httpClientRequestActionBuilder.build().execute(context); + private static final String METHOD = "{{httpMethod}}"; - coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - {{#queryParams}} + private static final String ENDPOINT = "{{path}}"; - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/queryParams}} - {{#pathParams}} + private static final String OPERATION_NAME = "{{operationId}}"; - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/pathParams}} - {{#isMultipart}} - {{#formParams}} + public AddPetActionBuilder() { + super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/formParams}} - {{/isMultipart}} - {{#authMethods}}{{#isBasic}} + {{#queryParams}} + public {{operationIdCamelCase}}ActionBuilder with{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + queryParam("{{paramName}}", {{paramName}}); + return this; + } + {{/queryParams}} - public void setBasicUsername(String basicUsername) { - this.basicUsername = basicUsername; - } + // public AddPetActionBuilder withPet(Pet pet) { + // // TODO: fix this + // getMessageBuilderSupport().body(pet.toString()); + // return this; + // } - public void setBasicPassword(String basicPassword) { - this.basicPassword = basicPassword; - } - {{/isBasic}}{{/authMethods}} - private String replacePathParams(String endpoint) { - {{#pathParams}}endpoint = endpoint.replace("{" + "{{baseName}}" + "}", {{paramName}});{{/pathParams}} - return endpoint; - } } {{/operation}} - {{/operations}} -} +{{/operations}} +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache new file mode 100644 index 0000000000..a023345fb7 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache @@ -0,0 +1,259 @@ +{{>licenseInfo}} + +package {{package}}; + +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.testapi.GeneratedApiRequest; +import jakarta.servlet.http.Cookie; +import org.apache.commons.lang3.StringUtils; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resources; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; + +import java.io.IOException; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +public class {{classname}} implements GeneratedApi +{ + + public static final {{classname}} INSTANCE = new {{classname}}(); + + public String getApiTitle() { + return "{{appName}}"; + } + + public String getApiVersion() { + return "{{appVersion}}"; + } + + public String getApiPrefix() { + return "{{prefix}}"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + {{#infoExtensions}} + {{#entrySet}} + infoExtensionMap.put("{{key}}", "{{value}}"); + {{/entrySet}} + {{/infoExtensions}} + return infoExtensionMap; + } + + {{#operations}} + {{#operation}} + /** {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) + {{summary}} + {{description}} + **/ + public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { + + private static final String ENDPOINT = "{{httpPathPrefix}}{{{path}}}"; + private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); + + {{#queryParams}} + private String {{paramName}}; + + {{/queryParams}} + {{#pathParams}} + private String {{paramName}}; + + {{/pathParams}} + {{#isMultipart}} + {{#formParams}} + private String {{paramName}}; + + {{/formParams}} + {{/isMultipart}} + {{#authMethods}}{{#isBasic}} + @Value("${" + "{{apiEndpoint}}.basic.username:#{null}}") + private String basicUsername; + @Value("${" + "{{apiEndpoint}}.basic.password:#{null}}") + private String basicPassword; + + {{/isBasic}} + {{/authMethods}} + + public {{operationIdCamelCase}}Request() { + // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml + setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); + } + + public String getOperationName() { + return "{{operationId}}"; + } + + public String getMethod() { + return "{{httpMethod}}"; + } + + public String getPath() { + return "{{path}}"; + } + + /** + * This method sends the HTTP-Request + */ + public void sendRequest(TestContext context) { + HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() + .{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(replacePathParams(ENDPOINT)); + + HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); + messageBuilderSupport.accept(responseAcceptType); + + if (cookies != null) { + cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + } + + if (headers != null) { + headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); + headers.forEach(messageBuilderSupport::header); + } + + String bodyLog = ""; + {{#isMultipart}} + MultiValueMap multiValues = new LinkedMultiValueMap<>(); + {{#formParams}} + {{#required}} + if(StringUtils.isBlank({{paramName}})) { + throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "{{paramName}}")); + } + {{/required}} + {{#isBinary}} + if (StringUtils.isNotBlank({{paramName}})) { + multiValues.add("{{paramName}}", new ClassPathResource({{paramName}})); + bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + {{/isBinary}} + {{^isBinary}} + if (StringUtils.isNotBlank({{paramName}})) { + // first try to load from resource + ClassPathResource resource = null; + try { + resource = new ClassPathResource({{paramName}}); + } + catch(Exception ignore) { + // Use plain text instead of resource + } + + if(resource != null && resource.exists()){ + multiValues.add("{{paramName}}", resource); + } else { + multiValues.add("{{paramName}}", {{paramName}}); + } + bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; + } + {{/isBinary}} + {{/formParams}} + + bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) + .body(multiValues); + + {{/isMultipart}} + {{^isMultipart}} + String payload = null; + String payloadType = null; + if (StringUtils.isNotBlank(this.bodyFile)) { + try { + payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); + } catch (IOException e) { + throw new CitrusRuntimeException("Failed to read payload resource", e); + } + payloadType = this.bodyContentType; + } else if (StringUtils.isNotBlank(this.bodyLiteral)) { + payload = this.bodyLiteral; + payloadType = this.bodyLiteralContentType; + } + String body = ""; + String bodyType = ""; + if(payload != null && payloadType != null) { + messageBuilderSupport.body(payload).contentType(payloadType); + body = context.replaceDynamicContentInString(payload); + bodyType = context.replaceDynamicContentInString(payloadType); + } + + bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; + {{/isMultipart}} + + Map queryParams = new HashMap<>(); + {{#allParams}}{{#isQueryParam}} + + if (StringUtils.isNotBlank(this.{{paramName}})) { + queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); + httpClientRequestActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); + } + {{/isQueryParam}}{{/allParams}} + String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + {{#authMethods}}{{#isBasic}} + + if(basicUsername != null && basicPassword != null){ + messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); + } + {{/isBasic}}{{/authMethods}} + httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); + httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); + + httpClientRequestActionBuilder.build().execute(context); + + coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + + query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + + bodyLog); + } + {{#queryParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/queryParams}} + {{#pathParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/pathParams}} + {{#isMultipart}} + {{#formParams}} + + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + this.{{paramName}} = {{paramName}}; + } + {{/formParams}} + {{/isMultipart}} + {{#authMethods}}{{#isBasic}} + + public void setBasicUsername(String basicUsername) { + this.basicUsername = basicUsername; + } + + public void setBasicPassword(String basicPassword) { + this.basicPassword = basicPassword; + } + {{/isBasic}}{{/authMethods}} + private String replacePathParams(String endpoint) { + {{#pathParams}}endpoint = endpoint.replace("{" + "{{baseName}}" + "}", {{paramName}});{{/pathParams}} + return endpoint; + } + } + {{/operation}} + {{/operations}} +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache new file mode 100644 index 0000000000..b59349ae63 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache @@ -0,0 +1,83 @@ +{{>licenseInfo}} + +package {{package}}; + +import java.util.HashMap; +import java.util.Map; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.rest.petstore.model.Pet; +import org.citrusframework.testapi.GeneratedApi; + +import {{invokerPackage}}.citrus.{{prefix}}AbstractSendAction; + +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +public class {{classname}} implements GeneratedApi +{ + + public static final {{classname}} INSTANCE = new {{classname}}(); + + private OpenApiSpecification openApiSpecification = null; + + public String getApiTitle() { + return "{{appName}}"; + } + + public String getApiVersion() { + return "{{appVersion}}"; + } + + public String getApiPrefix() { + return "{{prefix}}"; + } + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + {{#infoExtensions}} + {{#entrySet}} + infoExtensionMap.put("{{key}}", "{{value}}"); + {{/entrySet}} + {{/infoExtensions}} + return infoExtensionMap; + } + + {{#operations}} + {{#operation}} + public {{operationIdCamelCase}}ActionBuilder {{operationId}}() { + return new {{operationIdCamelCase}}ActionBuilder(); + } + {{/operation}} + {{/operations}} + + {{#operations}} + {{#operation}} + public class {{operationIdCamelCase}}ActionBuilder extends {{prefix}}AbstractSendAction.Builder { + + private static final String METHOD = ""{{httpMethod}}"; + + private static final String ENDPOINT = "{{path}}"; + + private static final String OPERATION_NAME = "{{operationId}}"; + + public AddPetActionBuilder() { + super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + {{#queryParams}} + public {{operationIdCamelCase}}ActionBuilder with{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { + queryParam("{{paramName}}", {{paramName}}); + return this; + } + } + {{/queryParams}} + +// public AddPetActionBuilder withPet(Pet pet) { +// // TODO: fix this +// getMessageBuilderSupport().body(pet.toString()); +// return this; +// } + + } + {{/operation}} + {{/operations}} +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java index 72b9369ca3..77961399e3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java @@ -2,7 +2,15 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.citrusframework.container.Assert.Builder.assertException; +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AddressEntityValidationContext.Builder.address; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.allOf; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.anyOf; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.oneOf; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder.pet; +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.openApiPetStore; import static org.citrusframework.util.FileUtils.readToString; +import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -10,6 +18,7 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.Map; import org.citrusframework.TestCaseRunner; import org.citrusframework.annotations.CitrusResource; @@ -19,6 +28,8 @@ import org.citrusframework.endpoint.EndpointConfiguration; import org.citrusframework.http.client.HttpClient; import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; @@ -27,7 +38,13 @@ import org.citrusframework.openapi.generator.GetPetByIdIT.Config; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AddressEntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; +import org.citrusframework.openapi.generator.sample.PetApi; +import org.citrusframework.spi.BindToRegistry; import org.citrusframework.spi.Resources; +import org.citrusframework.util.SocketUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -42,6 +59,16 @@ @SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class, Config.class}) class GetPetByIdIT { + private final int port = SocketUtils.findAvailableTcpPort(8080); + + @BindToRegistry + private final HttpServer httpServer = new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + @Autowired private GetPetByIdRequest getPetByIdRequest; @@ -66,22 +93,145 @@ public void beforeTest() throws IOException { */ @Test @CitrusTest - void testByJsonPath(@CitrusResource TestCaseRunner runner) { - - // Given - getPetByIdRequest.setPetId("1234"); + void testByEntityMatcher(@CitrusResource TestCaseRunner runner) { + + when(PetApi.openApiPetStore(httpClient) + .getPetById() + .withId("1234") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(HttpStatus.OK) + .message() + .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) + .contentType("application/json")); + + runner.then(openApiPetStore(httpClient) + .receivePetById(HttpStatus.OK) + .message() + .validate(pet().id("1234") + .name("Garfield") + .category("Cat") + .address(address -> address + .street("Nina Hagen Hang") + .zip("12345") + .city("Hagen ATW")) + .owners(anyOf(List.of( + owner -> owner.name("Peter Lustig"), + owner -> owner.name("Hans Meier") + ))) + .owners(oneOf(List.of( + owner -> owner.name("Seppel Hinterhuber") + ))) + .urls(0, "url1") + .urls(1, "url2") + .urls("@contains('url1', 'url2')")). + validate(jsonPath().expression("$.name", "Garfield"))); + + runner.then(openApiPetStore(httpClient) + .receivePetById200() + .withPet(validator -> validator.id("1234") + .name("Garfield") + .category("Cat") + .urls(0,"url1") + .urls(1,"url2") + .urls("@contains('url1', 'url2')")). + validate(jsonPath().expression("$.name", "Garfield")) + ); + } - // Then - getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); - getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); + @Test + @CitrusTest + void testFindByStatus(@CitrusResource TestCaseRunner runner) { + + when(openApiPetStore(httpClient) + .findByStatus() + .withStatus("SOLD") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(HttpStatus.OK) + .message() + .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) + .contentType("application/json")); + + runner.then(openApiPetStore(httpClient) + .receivePetById(HttpStatus.OK) + .message() + .validate(pet().id("1234") + .name("Garfield") + .category("Cat") + .address(address -> address + .street("Nina Hagen Hang") + .zip("12345") + .city("Hagen ATW")) + .owners(anyOf(List.of( + owner -> owner.name("Peter Lustig"), + owner -> owner.name("Hans Meier") + ))) + .owners(oneOf(List.of( + owner -> owner.name("Seppel Hinterhuber") + ))) + .urls(0, "url1") + .urls(1, "url2") + .urls("@contains('url1', 'url2')")). + validate(jsonPath().expression("$.name", "Garfield"))); + + runner.then(openApiPetStore(httpClient) + .receivePetById200() + .withPet(validator -> validator.id("1234") + .name("Garfield") + .category("Cat") + .urls(0,"url1") + .urls(1,"url2") + .urls("@contains('url1', 'url2')")). + validate(jsonPath().expression("$.name", "Garfield")) + ); + } - // Assert body by json path - getPetByIdRequest.setResponseValue(Map.of("$.name", "Snoopy")); + @Test + @CitrusTest + void testByJsonPath(@CitrusResource TestCaseRunner runner) { - // When - runner.$(getPetByIdRequest); + when(openApiPetStore(httpClient) + .getPetById() + .withPetId("1234") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(HttpStatus.OK) + .message() + .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) + .contentType("application/json")); + + runner.then(openApiPetStore(httpClient) + .receivePetById(HttpStatus.OK) + .message().validate(jsonPath().expression("$.name", "Garfield")) + ); } + /** * TODO #1161 - Improve with builder pattern */ diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java new file mode 100644 index 0000000000..372219d262 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java @@ -0,0 +1,181 @@ +package org.citrusframework.openapi.generator; + +import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder.pet; +import static org.mockito.Mockito.mock; + +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.ReadContext; +import java.util.Map; +import net.minidev.json.parser.JSONParser; +import net.minidev.json.parser.ParseException; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.functions.DefaultFunctionRegistry; +import org.citrusframework.json.JsonPathUtils; +import org.citrusframework.message.DefaultMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.EntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; +import org.citrusframework.validation.AbstractMessageValidator; +import org.citrusframework.validation.DefaultMessageValidatorRegistry; +import org.citrusframework.validation.ValidationUtils; +import org.testng.annotations.Test; + +public class OpenApiPetStoreTest { + + @Test + public void test() { + Builder petValidationContextBuilder = pet().id("1234") + .name("Garfield") + .category("Cat") + .address(address -> address + .street("Nina Hagen Hang") + .zip("12345") + .city("Hagen ATW")) +// .owners(anyOf(List.of( +// owner -> owner.name("Peter Lustig"), +// owner -> owner.name("Hans Meier") +// ))) +// .owners(oneOf(List.of( +// owner -> owner.name("Seppel Hinterhuber") +// ))) +// .urls(0, "url1") +// .urls(1, "url2") +// .urls("@contains('url1', 'url2')") + ; + + PetEntityValidationContext petValidationContext = petValidationContextBuilder.build(); + OpenApiEntityValidator validator = new OpenApiEntityValidator(); + + Message receivedMessage = new DefaultMessage(); + receivedMessage.setPayload(""" + { + "id": 1234, + "name": "Garfield", + "category": "Cat", + "address": { + "street": "Nina Hagen Hang", + "zip": "12345", + "city": "Hagen ATW" + }, + "owners": [ + { + "name": "Peter Lustig" + }, + { + "name": "Hans Meier" + } + ] + } + """); + TestContext testContext = new TestContext(); + testContext.setReferenceResolver(mock()); + testContext.setMessageValidatorRegistry(new DefaultMessageValidatorRegistry()); + testContext.setFunctionRegistry(new DefaultFunctionRegistry()); + + validator.validateMessage(receivedMessage, null, testContext, petValidationContext); + + + } + + public class OpenApiEntityValidator extends + AbstractMessageValidator { + + public void validateMessage(Message receivedMessage, Message controlMessage, + TestContext context, EntityValidationContext validationContext) { + System.out.println("asSD"); + + validateJson(receivedMessage.getPayload(String.class), context, validationContext); + + + } + + private void validateJson(String jsonString, TestContext context, + EntityValidationContext validationContext) { + validateJsonPathExpressions(jsonString, context, validationContext); + validateNestedJsonPathExpressions(jsonString, context, validationContext); + } + + @Override + protected Class getRequiredValidationContextType() { + return EntityValidationContext.class; + } + + @Override + public boolean supportsMessageType(String messageType, Message message) { + return true; + } + + + private void validateJsonPathExpressions(String jsonString, TestContext context, + EntityValidationContext validationContext) { + String jsonPathExpression; + try { + JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE); + Object receivedJson = parser.parse(jsonString); + ReadContext readerContext = JsonPath.parse(receivedJson); + + for (Map.Entry entry : validationContext.getJsonPathExpressions() + .entrySet()) { + Object expectedValue = entry.getValue(); + + jsonPathExpression = context.replaceDynamicContentInString(entry.getKey()); + Object jsonPathResult = JsonPathUtils.evaluate(readerContext, + jsonPathExpression); + + if (expectedValue instanceof EntityValidationContext entityValidationContext) { + validateJson((String) jsonPathResult, context, entityValidationContext); + } else if (expectedValue instanceof AggregateEntityValidationContext) { + + } else { + + if (expectedValue instanceof String) { + //check if expected value is variable or function (and resolve it, if yes) + expectedValue = context.replaceDynamicContentInString( + String.valueOf(expectedValue)); + } + + //do the validation of actual and expected value for element + ValidationUtils.validateValues(jsonPathResult, expectedValue, + jsonPathExpression, context); + + logger.debug("Validating element: {}='{}': OK", jsonPathExpression, + expectedValue); + } + + } + + logger.debug("JSONPath element validation successful: All values OK"); + } catch (ParseException e) { + throw new CitrusRuntimeException("Failed to parse JSON text", e); + } + } + + private void validateNestedJsonPathExpressions(String jsonString, TestContext context, + EntityValidationContext validationContext) { + String jsonPathExpression; + try { + JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE); + Object receivedJson = parser.parse(jsonString); + ReadContext readerContext = JsonPath.parse(receivedJson); + + for (Map.Entry entry : validationContext.getNestedValidationContextsBuilders() + .entrySet()) { + + jsonPathExpression = context.replaceDynamicContentInString(entry.getKey()); + Object jsonPathResult = JsonPathUtils.evaluate(readerContext, + jsonPathExpression); + + validateJson(jsonPathResult.toString(), context, entry.getValue()); + + } + + logger.debug("JSONPath element validation successful: All values OK"); + } catch (ParseException e) { + throw new CitrusRuntimeException("Failed to parse JSON text", e); + } + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java new file mode 100644 index 0000000000..5ed27a3765 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java @@ -0,0 +1,306 @@ +package org.citrusframework.openapi.generator.sample; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.citrusframework.builder.WithExpressions; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.DelegatingPathExpressionProcessor; +import org.citrusframework.message.MessageProcessor; +import org.citrusframework.message.MessageProcessorAdapter; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.EntityValidationContext; +import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; +import org.citrusframework.openapi.generator.sample.PetApi.FindPetByStatusActionBuilder; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.context.DefaultValidationContext; +import org.citrusframework.validation.context.ValidationContext; +import org.citrusframework.variable.VariableExtractor; +import org.citrusframework.variable.VariableExtractorAdapter; +import org.springframework.http.HttpStatus; + +public class OpenApiPetStore { + + public static OpenApiPetStore openApiPetStore(HttpClient httpClient) { + return new OpenApiPetStore(); + } + + public GetPetIdRequestActionBuilder getPetById() { + return new GetPetIdRequestActionBuilder(); + } + + public FindPetByStatusActionBuilder findByStatus() { + return new PetApi.FindPetByStatusActionBuilder(); + } + + public static class GetPetIdRequestActionBuilder extends HttpClientRequestActionBuilder { + + public GetPetIdRequestActionBuilder withPetId(String petId) { + return this; + } + + } + + public GetPetIdResponseActionBuilder receivePetById(HttpStatus status) { + return new GetPetIdResponseActionBuilder(); + } + + public GetPetIdResponseActionBuilder200 receivePetById200() { + return new GetPetIdResponseActionBuilder200(); + } + + public static class GetPetIdResponseActionBuilder extends HttpClientResponseActionBuilder { + + } + + // Per configured response + public static class GetPetIdResponseActionBuilder200 extends HttpClientResponseActionBuilder { + + public HttpMessageBuilderSupport withPet( + Consumer validator) { + PetEntityValidationContext.Builder builder = new PetEntityValidationContext.Builder(); + validator.accept(builder); + return message().validate(builder); + } + } + + public static class EntityValidationContext extends DefaultValidationContext { + + private Map expressions; + + + private Map nestedValidationContextsBuilders = new HashMap<>(); + + public EntityValidationContext(Builder builder) { + super(); + this.expressions = builder.expressions; + builder.nestedValidationContextBuilders.forEach((key, value) -> + nestedValidationContextsBuilders.put(key, value.build())); + + } + + public Map getJsonPathExpressions() { + return expressions; + } + + public Map getNestedValidationContextsBuilders() { + return nestedValidationContextsBuilders; + } + + public static class Builder> implements + ValidationContext.Builder, + WithExpressions, VariableExtractorAdapter, + MessageProcessorAdapter { + + private final Map expressions = new HashMap<>(); + + protected final Map> nestedValidationContextBuilders= new HashMap<>(); + + @Override + public B expressions(Map expressions) { + this.expressions.putAll(expressions); + return (B) this; + } + + @Override + public B expression(final String expression, + final Object value) { + this.expressions.put(expression, value); + return (B) this; + } + + @Override + public EntityValidationContext build() { + return new EntityValidationContext(this); + } + + @Override + public MessageProcessor asProcessor() { + return new DelegatingPathExpressionProcessor.Builder() + .expressions(expressions) + .build(); + } + + @Override + public VariableExtractor asExtractor() { + return new DelegatingPayloadVariableExtractor.Builder() + .expressions(expressions) + .build(); + } + + } + } + + public static class PetEntityValidationContext extends EntityValidationContext { + + public PetEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + public Builder id(String expression) { + return expression("$.id", expression); + } + + public Builder name(String expression) { + return expression("$.name", expression); + } + + public Builder category(String expression) { + return expression("$.category", expression); + } + + public Builder urls(String expression) { + return expression("$.urls", expression); + } + + + public Builder urls(int index, String expression) { + return expression("$.urls[%d]".formatted(index), expression); + } + + public Builder address(Consumer validator) { + AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); + validator.accept(addressEntityValidationContextBuilder); + nestedValidationContextBuilders.put("$.address", addressEntityValidationContextBuilder); + + return this; + } + + + public Builder owners(AggregateEntityValidationContext.Builder aggregateContext) { + nestedValidationContextBuilders.put("$.owners", aggregateContext); + return this; + } + + public static Builder pet() { + return new Builder(); + } + + @Override + public PetEntityValidationContext build() { + return new PetEntityValidationContext(this); + } + + } + } + + public static class AddressEntityValidationContext extends EntityValidationContext { + + public AddressEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + + public Builder street(String expression) { + return expression("$.street", expression); + } + + public Builder city(String expression) { + return expression("$.city", expression); + } + + public Builder zip(String expression) { + return expression("$.zip", expression); + } + + public static Builder address() { + return new Builder(); + } + + @Override + public AddressEntityValidationContext build() { + return new AddressEntityValidationContext(this); + } + + } + } + + public static class OwnerEntityValidationContext extends EntityValidationContext { + + public OwnerEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + public OwnerEntityValidationContext.Builder address(Consumer validator) { + AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); + validator.accept(addressEntityValidationContextBuilder); + nestedValidationContextBuilders.put("address", addressEntityValidationContextBuilder); + return this; + } + + public OwnerEntityValidationContext.Builder name(String expression) { + expression("$.name", expression); + return this; + } + + @Override + public OwnerEntityValidationContext build() { + return new OwnerEntityValidationContext(this); + } + } + } + + public static class AggregateEntityValidationContext> extends EntityValidationContext { + + private final Type type; + + private List> validator; + + public AggregateEntityValidationContext(Builder builder) { + super(builder); + + this.type = builder.type; + this.validator = builder.validator; + } + + public enum Type { + ONE_OF, ANY_OF, ALL_OF, NONE_OF + } + + public static class Builder> extends EntityValidationContext.Builder, Builder> { + + private final Type type; + + private final List> validator; + + public Builder(Type type, List> validator) { + this.type = type; + this.validator = validator; + } + + public static > AggregateEntityValidationContext.Builder anyOf(List> validator) { + return new Builder<>(Type.ANY_OF, validator); + } + + public static > AggregateEntityValidationContext.Builder allOf(List> validator) { + return new Builder<>(Type.ALL_OF, validator); + } + + public static > AggregateEntityValidationContext.Builder noneOf(List> validator) { + + return new Builder<>(Type.NONE_OF, validator); + } + + public static > AggregateEntityValidationContext.Builder oneOf(List> validator) { + return new Builder<>(Type.ONE_OF, validator); + } + + @Override + public AggregateEntityValidationContext build() { + return null; + } + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java new file mode 100644 index 0000000000..b810d81281 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java @@ -0,0 +1,304 @@ +package org.citrusframework.openapi.generator.sample; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import org.citrusframework.builder.WithExpressions; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.DelegatingPathExpressionProcessor; +import org.citrusframework.message.MessageProcessor; +import org.citrusframework.message.MessageProcessorAdapter; +import org.citrusframework.openapi.generator.sample.PetApi.FindPetByStatusActionBuilder; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.context.DefaultValidationContext; +import org.citrusframework.validation.context.ValidationContext; +import org.citrusframework.variable.VariableExtractor; +import org.citrusframework.variable.VariableExtractorAdapter; +import org.springframework.http.HttpStatus; + +public class OpenApiPetStore_ { + + public static OpenApiPetStore_ openApiPetStore(HttpClient httpClient) { + return new OpenApiPetStore_(); + } + + public GetPetIdRequestActionBuilder getPetById() { + return new GetPetIdRequestActionBuilder(); + } + + public FindPetByStatusActionBuilder findByStatus() { + return new FindPetByStatusActionBuilder(); + } + + public static class GetPetIdRequestActionBuilder extends HttpClientRequestActionBuilder { + + public GetPetIdRequestActionBuilder withPetId(String petId) { + return this; + } + + } + + public GetPetIdResponseActionBuilder receivePetById(HttpStatus status) { + return new GetPetIdResponseActionBuilder(); + } + + public GetPetIdResponseActionBuilder200 receivePetById200() { + return new GetPetIdResponseActionBuilder200(); + } + + public static class GetPetIdResponseActionBuilder extends HttpClientResponseActionBuilder { + + } + + // Per configured response + public static class GetPetIdResponseActionBuilder200 extends HttpClientResponseActionBuilder { + + public HttpMessageBuilderSupport withPet( + Consumer validator) { + PetEntityValidationContext.Builder builder = new PetEntityValidationContext.Builder(); + validator.accept(builder); + return message().validate(builder); + } + } + + public static class EntityValidationContext extends DefaultValidationContext { + + private Map expressions; + + + private Map nestedValidationContextsBuilders = new HashMap<>(); + + public EntityValidationContext(Builder builder) { + super(); + this.expressions = builder.expressions; + builder.nestedValidationContextBuilders.forEach((key, value) -> + nestedValidationContextsBuilders.put(key, value.build())); + + } + + public Map getJsonPathExpressions() { + return expressions; + } + + public Map getNestedValidationContextsBuilders() { + return nestedValidationContextsBuilders; + } + + public static class Builder> implements + ValidationContext.Builder, + WithExpressions, VariableExtractorAdapter, + MessageProcessorAdapter { + + private final Map expressions = new HashMap<>(); + + protected final Map> nestedValidationContextBuilders= new HashMap<>(); + + @Override + public B expressions(Map expressions) { + this.expressions.putAll(expressions); + return (B) this; + } + + @Override + public B expression(final String expression, + final Object value) { + this.expressions.put(expression, value); + return (B) this; + } + + @Override + public EntityValidationContext build() { + return new EntityValidationContext(this); + } + + @Override + public MessageProcessor asProcessor() { + return new DelegatingPathExpressionProcessor.Builder() + .expressions(expressions) + .build(); + } + + @Override + public VariableExtractor asExtractor() { + return new DelegatingPayloadVariableExtractor.Builder() + .expressions(expressions) + .build(); + } + + } + } + + public static class PetEntityValidationContext extends EntityValidationContext { + + public PetEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + public Builder id(String expression) { + return expression("$.id", expression); + } + + public Builder name(String expression) { + return expression("$.name", expression); + } + + public Builder category(String expression) { + return expression("$.category", expression); + } + + public Builder urls(String expression) { + return expression("$.urls", expression); + } + + + public Builder urls(int index, String expression) { + return expression("$.urls[%d]".formatted(index), expression); + } + + public Builder address(Consumer validator) { + AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); + validator.accept(addressEntityValidationContextBuilder); + nestedValidationContextBuilders.put("$.address", addressEntityValidationContextBuilder); + + return this; + } + + + public Builder owners(AggregateEntityValidationContext.Builder aggregateContext) { + nestedValidationContextBuilders.put("$.owners", aggregateContext); + return this; + } + + public static Builder pet() { + return new Builder(); + } + + @Override + public PetEntityValidationContext build() { + return new PetEntityValidationContext(this); + } + + } + } + + public static class AddressEntityValidationContext extends EntityValidationContext { + + public AddressEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + + public Builder street(String expression) { + return expression("$.street", expression); + } + + public Builder city(String expression) { + return expression("$.city", expression); + } + + public Builder zip(String expression) { + return expression("$.zip", expression); + } + + public static Builder address() { + return new Builder(); + } + + @Override + public AddressEntityValidationContext build() { + return new AddressEntityValidationContext(this); + } + + } + } + + public static class OwnerEntityValidationContext extends EntityValidationContext { + + public OwnerEntityValidationContext(Builder builder) { + super(builder); + } + + public static class Builder extends + EntityValidationContext.Builder { + + public Builder address(Consumer validator) { + AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); + validator.accept(addressEntityValidationContextBuilder); + nestedValidationContextBuilders.put("address", addressEntityValidationContextBuilder); + return this; + } + + public Builder name(String expression) { + expression("$.name", expression); + return this; + } + + @Override + public OwnerEntityValidationContext build() { + return new OwnerEntityValidationContext(this); + } + } + } + + public static class AggregateEntityValidationContext> extends EntityValidationContext { + + private final Type type; + + private List> validator; + + public AggregateEntityValidationContext(Builder builder) { + super(builder); + + this.type = builder.type; + this.validator = builder.validator; + } + + public enum Type { + ONE_OF, ANY_OF, ALL_OF, NONE_OF + } + + public static class Builder> extends EntityValidationContext.Builder, Builder> { + + private final Type type; + + private final List> validator; + + public Builder(Type type, List> validator) { + this.type = type; + this.validator = validator; + } + + public static > Builder anyOf(List> validator) { + return new Builder<>(Type.ANY_OF, validator); + } + + public static > Builder allOf(List> validator) { + return new Builder<>(Type.ALL_OF, validator); + } + + public static > Builder noneOf(List> validator) { + + return new Builder<>(Type.NONE_OF, validator); + } + + public static > Builder oneOf(List> validator) { + return new Builder<>(Type.ONE_OF, validator); + } + + @Override + public AggregateEntityValidationContext build() { + return null; + } + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java new file mode 100644 index 0000000000..325be20a88 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java @@ -0,0 +1,273 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.generator.sample; + +import java.util.HashMap; +import java.util.Map; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.TestApiClientRequestActionBuilder; +import org.citrusframework.openapi.generator.rest.petstore.model.Pet; +import org.citrusframework.testapi.GeneratedApi; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetApi implements GeneratedApi { + + public static final PetApi INSTANCE = new PetApi(); + + public String getApiTitle() { + return "OpenAPI Petstore"; + } + + public String getApiVersion() { + return "1.0.0"; + } + + public String getApiPrefix() { + return "PetStore"; + } + + private OpenApiSpecification openApiSpecification = null; + + public Map getApiInfoExtensions() { + Map infoExtensionMap = new HashMap<>(); + infoExtensionMap.put("x-citrus-api-name", "petstore"); + infoExtensionMap.put("x-citrus-app", "PETS"); + return infoExtensionMap; + } + + public static PetApi openApiPetStore(HttpClient httpClient) { + + return new PetApi(); + } + + private static OpenApiSpecification petApi() { + // TODO implement me + return null; + } + + public AddPetActionBuilder addPet() { + return new AddPetActionBuilder(); + } + + public DeletePetActionBuilder deletePet() { + return new DeletePetActionBuilder(); + } + + public FindPetByStatusActionBuilder findPetsByStatus() { + return new FindPetByStatusActionBuilder(); + } + + public FindPetsByTagsActionBuilder findPetsByTags() { + return new FindPetsByTagsActionBuilder(); + } + + public GetPetByIdActionBuilder getPetById() { + return new GetPetByIdActionBuilder(); + } + + public class AddPetActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/pet"; + + private static final String OPERATION_NAME = "addPet"; + + public AddPetActionBuilder() { + super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public AddPetActionBuilder withStatus(String status) { + queryParam("status", status); + return this; + } + + public AddPetActionBuilder withPet(Pet pet) { + // TODO: fix this + getMessageBuilderSupport().body(pet.toString()); + return this; + } + + } + + public class DeletePetActionBuilder extends TestApiClientRequestActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/pet/{petId}"; + + private static final String OPERATION_NAME = "deletePet"; + + public DeletePetActionBuilder() { + super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public DeletePetActionBuilder withId(String id) { + pathParameter("id", id); + return this; + } + + public DeletePetActionBuilder withPet(Pet pet) { + // TODO: fix this pet.toString will not properly work + getMessageBuilderSupport().body(pet.toString()); + return this; + } + + } + + public static class FindPetByStatusActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/pet/findByStatus"; + + private static final String OPERATION_NAME = "findPetsByStatus"; + + public FindPetByStatusActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetByStatusActionBuilder withStatus(String status) { + queryParam("status", status); + return this; + } + + } + + public static class FindPetsByTagsActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/pet/findByTags"; + + private static final String OPERATION_NAME = "findPetsByTags"; + + public FindPetsByTagsActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetsByTagsActionBuilder withTags(String... tags) { + queryParam("tags", toQueryParam(tags)); + return this; + } + } + + public static class GetPetByIdActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetById"; + + public GetPetByIdActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public GetPetByIdActionBuilder withId(String id) { + pathParameter("id", id); + return this; + } + + + + // TODO: find solution for authentication +// public GetPetByIdActionBuilder withBasicUsername(String basicUsername) { +// this.basicUsername = basicUsername; +// return this; +// } +// +// public GetPetByIdActionBuilder withBasicPassword(String basicPassword) { +// this.basicPassword = basicPassword; +// return this; +// } + } + + public static class UpdatePetActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/pet"; + + private static final String OPERATION_NAME = "updatePet"; + + public UpdatePetActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public UpdatePetActionBuilder withId(String id) { + pathParameter("id", id); + return this; + } + + public UpdatePetActionBuilder withPet(Pet pet) { + // TODO: fix this pet.toString + getMessageBuilderSupport().body(pet.toString()); + return this; + } + } + + public static class UpdatePetWithFormDataActionBuilder extends + PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/pet/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithForm"; + + public UpdatePetWithFormDataActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public UpdatePetWithFormDataActionBuilder withId(String id) { + pathParameter("id", id); + return this; + } + + // TODO: what is the magic about form data request? + } + + public static class UploadFileActionBuilder extends PetStoreAbstractSendAction.Builder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/pet/{petId}/uploadImage"; + + private static final String OPERATION_NAME = "uploadImage"; + + public UploadFileActionBuilder() { + super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public UploadFileActionBuilder withId(String id) { + pathParameter("id", id); + return this; + } + + public UploadFileActionBuilder withAdditionalMetadata(String additionalMetadata) { + + // TODO: what is the magic about form data request? + formData("additionalMetadata", additionalMetadata); + return this; + } + } + + + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java new file mode 100644 index 0000000000..e8f1e5c473 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java @@ -0,0 +1,250 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.sample; + +import static org.springframework.util.CollectionUtils.isEmpty; + +import jakarta.annotation.Nullable; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.citrusframework.actions.AbstractTestAction; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.message.Message; +import org.citrusframework.spi.Resources; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.validation.DelegatingPayloadVariableExtractor; +import org.citrusframework.validation.PathExpressionValidationContext; +import org.citrusframework.validation.json.JsonMessageValidationContext; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public abstract class PetStoreAbstractReceiveActionBuilder extends AbstractTestAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); + + @Autowired + @Qualifier("petStoreEndpoint") + protected HttpClient httpClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected boolean schemaValidation; + protected String schema; + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + protected String responseAcceptType = "*/*"; + protected String responseType = "json"; + protected int responseStatus = 200; + protected String responseReasonPhrase = "OK"; + protected String responseVersion = "HTTP/1.1"; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value + protected Map cookies; + protected Map headers; + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + + @Override + public void doExecute(TestContext context) { + recieveResponse(context); + } + + /** + * This method receives the HTTP-Response. + * + * @deprecated use {@link PetStoreAbstractReceiveActionBuilder#receiveResponse(TestContext)} instead. + */ + public ReceiveMessageAction recieveResponse(TestContext context) { + + HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); + HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); + + messageBuilderSupport + .statusCode(responseStatus) + .reasonPhrase(responseReasonPhrase) + .version(responseVersion) + .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); + + if (resource != null) { + messageBuilderSupport.body(Resources.create(resource)); + } + + if (!isEmpty(responseVariable)) { + DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); + responseVariable.forEach(extractorBuilder::expression); + messageBuilderSupport.extract(extractorBuilder); + } + + if (!isEmpty(responseValue)) { + PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); + responseValue.forEach(validationContextBuilder::expression); + messageBuilderSupport.validate(validationContextBuilder); + } + + if (script != null) { + ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); + if (type != null) { + scriptValidationContextBuilder.scriptType(type); + } + scriptValidationContextBuilder.script(script); + messageBuilderSupport.validate(scriptValidationContextBuilder); + } + + messageBuilderSupport.type(responseType); + httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); + var responseAction = httpClientResponseActionBuilder.build(); + + responseAction.execute(context); + + return responseAction; + } + + public @Nullable Message receiveResponse(TestContext context) { + var responseAction = recieveResponse(context); + + var messageStore = context.getMessageStore(); + return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); + } + + public void setSchemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setResponseAcceptType(String responseAcceptType) { + this.responseAcceptType = responseAcceptType; + } + + public void setCookie(Map cookies) { + this.cookies = cookies; + } + + public void setHeader(Map headers) { + this.headers = headers; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResponseType(String responseType) { + this.responseType = responseType; + } + + public void setResponseStatus(int responseStatus) { + this.responseStatus = responseStatus; + } + + public void setResponseReasonPhrase(String responseReasonPhrase) { + this.responseReasonPhrase = responseReasonPhrase; + } + + public void setResponseVersion(String responseVersion) { + this.responseVersion = responseVersion; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, + TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + + httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, + httpClientRequestActionBuilder); + + httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); + + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); + } + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeByBeans( + GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, httpClientRequestActionBuilder); + } + } + return httpClientRequestActionBuilder; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java new file mode 100644 index 0000000000..a02a8d4639 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java @@ -0,0 +1,234 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.sample; + +import static org.springframework.util.CollectionUtils.isEmpty; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.ServiceLoader; +import javax.sql.DataSource; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; +import org.citrusframework.testapi.ApiActionBuilderCustomizerService; +import org.citrusframework.testapi.GeneratedApi; +import org.slf4j.Marker; +import org.slf4j.MarkerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public abstract class PetStoreAbstractSendAction extends SendMessageAction { + + protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); + + @Autowired + @Qualifier("petStoreEndpoint") + protected HttpClient httpClient; + + @Autowired(required = false) + protected DataSource dataSource; + + @Autowired(required = false) + private List actionBuilderCustomizerServices; + + // attributes of differentNodes + protected boolean schemaValidation; + protected String schema; + protected String bodyContentType; + protected String bodyLiteralContentType; + protected String bodyFile; + protected String bodyLiteral; + protected String responseAcceptType = "*/*"; + protected String responseType = "json"; + protected int responseStatus = 200; + protected String responseReasonPhrase = "OK"; + protected String responseVersion = "HTTP/1.1"; + + // children of response element + protected String resource; + protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value + protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value + protected Map cookies; + protected Map headers; + protected String script; + protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes + + @Override + public void doExecute(TestContext context) { + sendRequest(context); + } + + + public abstract void sendRequest(TestContext context); + + public void setSchemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public void setBodyLiteral(String bodyLiteral) { + this.bodyLiteral = bodyLiteral; + } + + public void setBodyContentType(String bodyContentType) { + this.bodyContentType = bodyContentType; + } + + public void setBodyLiteralContentType(String bodyLiteralContentType) { + this.bodyLiteralContentType = bodyLiteralContentType; + } + + public void setResponseAcceptType(String responseAcceptType) { + this.responseAcceptType = responseAcceptType; + } + + public void setCookie(Map cookies) { + this.cookies = cookies; + } + + public void setHeader(Map headers) { + this.headers = headers; + } + + public void setBodyFile(String bodyFile) { + this.bodyFile = bodyFile; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public void setResponseVariable(Map responseVariable) { + this.responseVariable = responseVariable; + } + + public void setResponseValue(Map responseValue) { + this.responseValue = responseValue; + } + + public void setScript(String script) { + this.script = script; + } + + public void setType(String type) { + this.type = type; + } + + protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, + TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + + httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, + httpClientRequestActionBuilder); + + httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); + + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + ServiceLoader serviceLoader = ServiceLoader.load( + ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); + for (ApiActionBuilderCustomizerService service :serviceLoader) { + httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); + } + return httpClientRequestActionBuilder; + } + + private HttpClientRequestActionBuilder customizeByBeans( + GeneratedApi generatedApi, TestContext context, + HttpClientRequestActionBuilder httpClientRequestActionBuilder) { + if (actionBuilderCustomizerServices != null) { + for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { + httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, + context, httpClientRequestActionBuilder); + } + } + return httpClientRequestActionBuilder; + } + + public static class Builder extends OpenApiClientRequestActionBuilder { + + // TODO: do we really need this? + protected OpenApiSpecification openApiSpec; + + private final String path; + + private final Map pathParameters = new HashMap<>(); + + private final MultiValueMap formData = new LinkedMultiValueMap<>(); + + // TODO: can we just pass in the operation? + public Builder(OpenApiSpecification openApiSpec, String method, String path, String operationName) { + super(openApiSpec, "%s_%s".formatted(method, path)); + name(String.format("%s:%s", "PetStore".toLowerCase(), operationName)); + getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); + getMessageBuilderSupport().header("citrus_open_api_method", method); + getMessageBuilderSupport().header("citrus_open_api_path", path); + + this.openApiSpec = openApiSpec; + this.path = path; + } + + protected void pathParameter(String name, String value) { + pathParameters.put(name, value); + } + + protected void formData(String name, String value) { + formData.add(name, value); + } + + protected String qualifiedPath(String path) { + + String qualifiedPath = path; + for (Entry entry : pathParameters.entrySet()) { + qualifiedPath = qualifiedPath.replace("{%s}".formatted(entry.getKey()), entry.getValue()); + } + return qualifiedPath; + } + + protected String toQueryParam(String...arrayElements) { + return String.join(",", arrayElements); + } + + @Override + public SendMessageAction doBuild() { + // TODO: register callback to modify builder + path(qualifiedPath(path)); + if (!formData.isEmpty()) { + // TODO: do we have to explicitly set the content type or is this done by citrus + messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE); + getMessageBuilderSupport().body(formData); + } + return super.doBuild(); + } + + } +} From fb37b1b9cc1644faf5d7e472455869322ad5ea35 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Sun, 21 Jul 2024 07:33:39 +0200 Subject: [PATCH 16/47] feat(#1175): adds open api validation by standard citrus schema validaton mechanism --- connectors/citrus-openapi/pom.xml | 2 +- .../openapi/OpenApiMessageHeaders.java | 24 +++ .../openapi/OpenApiMessageType.java | 22 +++ .../openapi/OpenApiRepository.java | 21 ++- .../openapi/OpenApiSpecification.java | 6 +- .../openapi/actions/OpenApiActionBuilder.java | 45 +++-- .../actions/OpenApiClientActionBuilder.java | 20 ++- .../OpenApiClientRequestActionBuilder.java | 127 +++++++++----- .../OpenApiClientResponseActionBuilder.java | 46 +++-- .../actions/OpenApiServerActionBuilder.java | 16 +- .../OpenApiServerRequestActionBuilder.java | 74 ++++---- .../OpenApiServerResponseActionBuilder.java | 77 ++++---- .../actions/OpenApiSpecificationSource.java | 61 +++++++ .../openapi/model/OperationPathAdapter.java | 2 +- .../openapi/util/OpenApiUtils.java | 17 ++ .../validation/OpenApiMessageProcessor.java | 56 ++++++ .../OpenApiMessageValidationContext.java | 117 ++++++++++++ .../OpenApiRequestValidationProcessor.java | 3 + .../validation/OpenApiRequestValidator.java | 11 ++ .../OpenApiResponseValidationProcessor.java | 57 ------ .../validation/OpenApiResponseValidator.java | 18 +- .../validation/OpenApiSchemaValidation.java | 166 ++++++++++++++++++ .../citrus/message/schemaValidator/openApi | 2 + .../META-INF/citrus/message/validator/openApi | 2 + .../openapi/OpenApiMessageTypeTest.java | 18 ++ .../openapi/OpenApiRepositoryTest.java | 4 +- .../openapi/OpenApiUtilsTest.java | 60 +++++++ .../openapi/groovy/OpenApiClientTest.java | 6 +- .../openapi/integration/OpenApiClientIT.java | 19 +- .../openapi/integration/OpenApiServerIT.java | 50 +++--- .../model/OperationPathAdapterTest.java | 3 +- .../OpenApiMessageProcessorTest.java | 59 +++++++ ...penApiResponseValidationProcessorTest.java | 123 ------------- .../openapi/xml/OpenApiClientTest.java | 6 +- .../openapi/yaml/OpenApiClientTest.java | 6 +- .../validation/MessageValidatorRegistry.java | 13 +- .../validation/SchemaValidator.java | 12 ++ .../actions/SendMessageAction.java | 105 ++++------- .../HttpClientRequestActionBuilder.java | 7 +- .../HttpClientResponseActionBuilder.java | 9 +- .../HttpServerRequestActionBuilder.java | 9 +- .../HttpServerResponseActionBuilder.java | 6 +- pom.xml | 2 +- test-api-generator/pom.xml | 1 + .../json/schema/JsonSchemaValidation.java | 38 +++- .../json/SendMessageActionTest.java | 71 +++++--- .../xml/schema/XmlSchemaValidation.java | 54 ++++-- .../validation/xml/SendMessageActionTest.java | 11 +- 48 files changed, 1173 insertions(+), 511 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageHeaders.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageType.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java delete mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java create mode 100644 connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/schemaValidator/openApi create mode 100644 connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/validator/openApi create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java delete mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java diff --git a/connectors/citrus-openapi/pom.xml b/connectors/citrus-openapi/pom.xml index d01061c17e..b182d4d4ad 100644 --- a/connectors/citrus-openapi/pom.xml +++ b/connectors/citrus-openapi/pom.xml @@ -48,7 +48,7 @@ com.atlassian.oai swagger-request-validator-core - 2.40.0 + ${swagger-request-validator.version} com.fasterxml.jackson.datatype diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageHeaders.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageHeaders.java new file mode 100644 index 0000000000..5629c91c36 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageHeaders.java @@ -0,0 +1,24 @@ +package org.citrusframework.openapi; + +import org.citrusframework.message.MessageHeaders; + +public class OpenApiMessageHeaders { + + public static final String OAS_PREFIX = MessageHeaders.PREFIX + "oas_"; + + public static final String OAS_OPERATION = OAS_PREFIX + "operation"; + + public static final String OAS_MEDIA_TYPE = OAS_PREFIX + "media_type"; + + public static final String OAS_UNIQUE_OPERATION_ID = OAS_PREFIX + "unique_operation_id"; + + public static final String OAS_MESSAGE_TYPE = OAS_PREFIX + "message_type"; + + public static final String RESPONSE_TYPE = OAS_PREFIX + "response"; + + public static final String REQUEST_TYPE = OAS_PREFIX + "request"; + + private OpenApiMessageHeaders() { + // Static access only + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageType.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageType.java new file mode 100644 index 0000000000..e6b747d5ae --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiMessageType.java @@ -0,0 +1,22 @@ +package org.citrusframework.openapi; + +/** + * The {@code OpenApiMessageType} enum defines the types of OpenAPI messages, + * specifically REQUEST and RESPONSE. Each type is associated with a specific + * header name, which is used to identify the type of message in the OpenAPI + * message headers. + */ +public enum OpenApiMessageType { + + REQUEST(OpenApiMessageHeaders.REQUEST_TYPE), RESPONSE(OpenApiMessageHeaders.RESPONSE_TYPE); + + private final String headerName; + + OpenApiMessageType(String headerName) { + this.headerName = headerName; + } + + public String toHeaderName() { + return headerName; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 20f845d604..7479040c33 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -115,7 +115,12 @@ static Optional determineResourceAlias(Resource openApiResource) { try { File file = openApiResource.getFile(); if (file != null) { - return Optional.of(file.getName()); + resourceAlias = file.getName(); + int index = resourceAlias.lastIndexOf("."); + if (index != -1 && index != resourceAlias.length()-1) { + resourceAlias = resourceAlias.substring(0, index); + } + return Optional.of(resourceAlias); } } catch (Exception e) { // Ignore and try with url @@ -130,6 +135,11 @@ static Optional determineResourceAlias(Resource openApiResource) { if (index != -1 && index != urlString.length()-1) { resourceAlias = resourceAlias.substring(index+1); } + index = resourceAlias.lastIndexOf("."); + if (index != -1 && index != resourceAlias.length()-1) { + resourceAlias = resourceAlias.substring(0, index); + } + } } catch (MalformedURLException e) { logger.error("Unable to determine resource alias from resource!", e); @@ -141,4 +151,13 @@ static Optional determineResourceAlias(Resource openApiResource) { public List getOpenApiSpecifications() { return openApiSpecifications; } + + public OpenApiRepository locations(List locations) { + setLocations(locations); + return this; + } + + public OpenApiSpecification openApi(String alias) { + return getOpenApiSpecifications().stream().filter(spec -> spec.getAliases().contains(alias)).findFirst().orElse(null); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index f27f1bed48..b344e7d9cd 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -323,13 +323,13 @@ private void storeOperationPathAdapter(OasOperation operation, String path) { String basePath = OasModelHelper.getBasePath(openApiDoc); String fullOperationPath = StringUtils.appendSegmentToUrlPath(basePath, path); - OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, - StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation); - String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(fullOperationPath, operation); operationToUniqueId.put(operation, uniqueOperationId); + OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, + StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation, uniqueOperationId); + operationIdToOperationPathAdapter.put(uniqueOperationId, operationPathAdapter); if (StringUtils.hasText(operation.operationId)) { operationIdToOperationPathAdapter.put(operation.operationId, operationPathAdapter); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java index cee2f0c207..73ece7f474 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java @@ -35,13 +35,17 @@ */ public class OpenApiActionBuilder extends AbstractReferenceResolverAwareTestActionBuilder { - private OpenApiSpecification specification; + private OpenApiSpecificationSource openApiSpecificationSource; public OpenApiActionBuilder() { } public OpenApiActionBuilder(OpenApiSpecification specification) { - this.specification = specification; + this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); + } + + public OpenApiActionBuilder(String openApiAlias) { + this.openApiSpecificationSource = new OpenApiSpecificationSource(openApiAlias); } /** @@ -55,8 +59,17 @@ public static OpenApiActionBuilder openapi(OpenApiSpecification specification) { return new OpenApiActionBuilder(specification); } + public static OpenApiActionBuilder openapi(String openApiAlias) { + return new OpenApiActionBuilder(openApiAlias); + } + public OpenApiActionBuilder specification(OpenApiSpecification specification) { - this.specification = specification; + this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); + return this; + } + + public OpenApiActionBuilder specificationByAlias(String openApiAlias) { + this.openApiSpecificationSource = new OpenApiSpecificationSource(openApiAlias); return this; } @@ -70,7 +83,11 @@ public OpenApiActionBuilder specification(String specUrl) { public OpenApiClientActionBuilder client() { assertSpecification(); - return client(specification.getRequestUrl()); + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder( + openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = clientActionBuilder; + return clientActionBuilder; } /** @@ -80,10 +97,11 @@ public OpenApiClientActionBuilder client(HttpClient httpClient) { assertSpecification(); if (httpClient.getEndpointConfiguration().getRequestUrl() != null) { - specification.setRequestUrl(httpClient.getEndpointConfiguration().getRequestUrl()); + openApiSpecificationSource.setHttpClient(httpClient.getEndpointConfiguration().getRequestUrl()); } - OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, specification) + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, + openApiSpecificationSource) .withReferenceResolver(referenceResolver); this.delegate = clientActionBuilder; return clientActionBuilder; @@ -95,9 +113,10 @@ public OpenApiClientActionBuilder client(HttpClient httpClient) { public OpenApiClientActionBuilder client(String httpClient) { assertSpecification(); - specification.setHttpClient(httpClient); + openApiSpecificationSource.setHttpClient(httpClient); - OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, specification) + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, + openApiSpecificationSource) .withReferenceResolver(referenceResolver); this.delegate = clientActionBuilder; return clientActionBuilder; @@ -109,15 +128,16 @@ public OpenApiClientActionBuilder client(String httpClient) { public OpenApiServerActionBuilder server(Endpoint endpoint) { assertSpecification(); - OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(endpoint, specification) + OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(endpoint, + openApiSpecificationSource) .withReferenceResolver(referenceResolver); this.delegate = serverActionBuilder; return serverActionBuilder; } private void assertSpecification() { - if (specification == null) { - throw new CitrusRuntimeException("Invalid OpenApi specification - please set specification first"); + if (openApiSpecificationSource == null) { + throw new CitrusRuntimeException("Invalid OpenApiSpecificationSource - please set specification first"); } } @@ -127,7 +147,8 @@ private void assertSpecification() { public OpenApiServerActionBuilder server(String httpServer) { assertSpecification(); - OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(httpServer, specification) + OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(httpServer, + openApiSpecificationSource) .withReferenceResolver(referenceResolver); this.delegate = serverActionBuilder; return serverActionBuilder; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java index a80cd953ba..ed1b099e6b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java @@ -31,7 +31,7 @@ */ public class OpenApiClientActionBuilder extends AbstractReferenceResolverAwareTestActionBuilder { - private final OpenApiSpecification specification; + private final OpenApiSpecificationSource openApiSpecificationSource; /** Target http client instance */ private Endpoint httpClient; @@ -40,24 +40,29 @@ public class OpenApiClientActionBuilder extends AbstractReferenceResolverAwareTe /** * Default constructor. */ - public OpenApiClientActionBuilder(Endpoint httpClient, OpenApiSpecification specification) { + public OpenApiClientActionBuilder(Endpoint httpClient, OpenApiSpecificationSource openApiSpecificationSource) { this.httpClient = httpClient; - this.specification = specification; + this.openApiSpecificationSource = openApiSpecificationSource; } /** * Default constructor. */ - public OpenApiClientActionBuilder(String httpClientUri, OpenApiSpecification specification) { + public OpenApiClientActionBuilder(String httpClientUri, OpenApiSpecificationSource openApiSpecificationSource) { this.httpClientUri = httpClientUri; - this.specification = specification; + this.openApiSpecificationSource = openApiSpecificationSource; + } + + public OpenApiClientActionBuilder(OpenApiSpecificationSource openApiSpecificationSource) { + this.openApiSpecificationSource = openApiSpecificationSource; } /** * Sends Http requests as client. */ public OpenApiClientRequestActionBuilder send(String operationId) { - OpenApiClientRequestActionBuilder builder = new OpenApiClientRequestActionBuilder(specification, operationId); + OpenApiClientRequestActionBuilder builder = new OpenApiClientRequestActionBuilder( + openApiSpecificationSource, operationId); if (httpClient != null) { builder.endpoint(httpClient); } else { @@ -90,7 +95,8 @@ public OpenApiClientResponseActionBuilder receive(String operationId, HttpStatus * Receives Http response messages as client. */ public OpenApiClientResponseActionBuilder receive(String operationId, String statusCode) { - OpenApiClientResponseActionBuilder builder = new OpenApiClientResponseActionBuilder(specification, operationId, statusCode); + OpenApiClientResponseActionBuilder builder = new OpenApiClientResponseActionBuilder( + openApiSpecificationSource, operationId, statusCode); if (httpClient != null) { builder.endpoint(httpClient); } else { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index a7722559f1..ee009fe5aa 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -31,11 +31,12 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiRequestValidationProcessor; +import org.citrusframework.openapi.validation.OpenApiMessageProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -44,40 +45,56 @@ */ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBuilder { - private final OpenApiSpecification openApiSpec; + private OpenApiMessageProcessor openApiMessageProcessor; + + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; private boolean oasValidationEnabled = true; - private OpenApiRequestValidationProcessor openApiRequestValidationProcessor; - /** * Default constructor initializes http request message builder. */ - public OpenApiClientRequestActionBuilder(OpenApiSpecification openApiSpec, String operationId) { + public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, + String operationId) { this(new HttpMessage(), openApiSpec, operationId); } - public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId) { - super(new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage); + public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, + OpenApiSpecificationSource openApiSpec, + String operationId) { + super(new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), + httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; - } + } @Override public SendMessageAction doBuild() { - - if (oasValidationEnabled && !messageProcessors.contains(openApiRequestValidationProcessor)) { - openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); - process(openApiRequestValidationProcessor); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + referenceResolver); + if (oasValidationEnabled && !messageProcessors.contains( + openApiMessageProcessor)) { + openApiMessageProcessor = new OpenApiMessageProcessor(openApiSpecification, operationId, + OpenApiMessageType.REQUEST); + process(openApiMessageProcessor); } return super.doBuild(); } + /** + * By default, enable schema validation as the OpenAPI is always available. + */ + @Override + protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { + HttpMessageBuilderSupport httpMessageBuilderSupport = super.createHttpMessageBuilderSupport(); + httpMessageBuilderSupport.schemaValidation(true); + return httpMessageBuilderSupport; + } + public OpenApiClientRequestActionBuilder disableOasValidation(boolean disabled) { oasValidationEnabled = !disabled; return this; @@ -85,41 +102,52 @@ public OpenApiClientRequestActionBuilder disableOasValidation(boolean disabled) private static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilder { - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; + private final String operationId; private final HttpMessage httpMessage; - public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecification openApiSpec, - String operationId) { + public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, + OpenApiSpecificationSource openApiSpec, + String operationId) { super(httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; this.httpMessage = httpMessage; } @Override public Message build(TestContext context, String messageType) { - openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(operationPathAdapter, context), () -> { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); - }); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + context.getReferenceResolver()); + openApiSpecification.getOperation(operationId, context) + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), + () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); return super.build(context, messageType); } - private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { - OasOperation operation = operationPathAdapter.operation(); - String path = operationPathAdapter.apiPath(); - HttpMethod method = HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); + private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter, TestContext context) { + OasOperation operation = operationPathAdapter.operation(); + String path = operationPathAdapter.apiPath(); + HttpMethod method = HttpMethod.valueOf( + operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); if (operation.parameters != null) { - setSpecifiedHeaders(context, operation); + setSpecifiedHeaders(openApiSpecification, context, operation); setSpecifiedQueryParameters(context, operation); } - if(httpMessage.getPayload() == null || (httpMessage.getPayload() instanceof String p && p.isEmpty())) { - setSpecifiedBody(context, operation); + if (httpMessage.getPayload() == null || (httpMessage.getPayload() instanceof String p + && p.isEmpty())) { + setSpecifiedBody(openApiSpecification, context, operation); } String randomizedPath = path; @@ -130,9 +158,11 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter for (OasParameter parameter : pathParams) { String parameterValue; if (context.getVariables().containsKey(parameter.getName())) { - parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; + parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + + CitrusSettings.VARIABLE_SUFFIX; } else { - parameterValue = OpenApiTestDataGenerator.createRandomValueExpression((OasSchema) parameter.schema); + parameterValue = OpenApiTestDataGenerator.createRandomValueExpression( + (OasSchema) parameter.schema); } randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") .matcher(randomizedPath) @@ -141,44 +171,55 @@ private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter } OasModelHelper.getRequestContentType(operation) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + .ifPresent( + contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); httpMessage.path(randomizedPath); httpMessage.method(method); - } - private void setSpecifiedBody(TestContext context, OasOperation operation) { + private void setSpecifiedBody(OpenApiSpecification openApiSpecification, + TestContext context, OasOperation operation) { Optional body = OasModelHelper.getRequestBodySchema( - openApiSpec.getOpenApiDoc(context), operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, openApiSpec))); + openApiSpecification.getOpenApiDoc(context), operation); + body.ifPresent(oasSchema -> httpMessage.setPayload( + OpenApiTestDataGenerator.createOutboundPayload(oasSchema, + openApiSpecification))); } private void setSpecifiedQueryParameters(TestContext context, OasOperation operation) { operation.parameters.stream() .filter(param -> "query".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .filter( + param -> (param.required != null && param.required) || context.getVariables() + .containsKey(param.getName())) .forEach(param -> { - if(!httpMessage.getQueryParams().containsKey(param.getName())) { + if (!httpMessage.getQueryParams().containsKey(param.getName())) { httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), + (OasSchema) param.schema, context)); } }); } - private void setSpecifiedHeaders(TestContext context, OasOperation operation) { + private void setSpecifiedHeaders(OpenApiSpecification openApiSpecification, TestContext context, OasOperation operation) { List configuredHeaders = getHeaderBuilders() .stream() .flatMap(b -> b.builderHeaders(context).keySet().stream()) .toList(); operation.parameters.stream() .filter(param -> "header".equals(param.in)) - .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .filter( + param -> (param.required != null && param.required) || context.getVariables() + .containsKey(param.getName())) .forEach(param -> { - if(httpMessage.getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { + if (httpMessage.getHeader(param.getName()) == null + && !configuredHeaders.contains(param.getName())) { httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, openApiSpec, context)); + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), + (OasSchema) param.schema, + openApiSpecification, context)); } }); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index 3bc4b9d1c4..adf514cc0d 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -16,6 +16,9 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; +import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; @@ -37,7 +40,7 @@ import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; +import org.citrusframework.openapi.validation.OpenApiMessageProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -47,9 +50,9 @@ */ public class OpenApiClientResponseActionBuilder extends HttpClientResponseActionBuilder { - private OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; @@ -58,26 +61,30 @@ public class OpenApiClientResponseActionBuilder extends HttpClientResponseAction /** * Default constructor initializes http response message builder. */ - public OpenApiClientResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, + public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, String operationId, String statusCode) { this(new HttpMessage(), openApiSpec, operationId, statusCode); } public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode) { - super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpec, operationId, + super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, statusCode), httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } @Override public ReceiveMessageAction doBuild() { - if (oasValidationEnabled && !messageProcessors.contains(openApiResponseValidationProcessor)) { - openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); - validate(openApiResponseValidationProcessor); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); + validate(openApi(openApiSpecification)); + if (oasValidationEnabled && !messageProcessors.contains(openApiMessageProcessor)) { + openApiMessageProcessor = new OpenApiMessageProcessor( + openApiSpecification, operationId, + RESPONSE); + process(openApiMessageProcessor); } return super.doBuild(); @@ -151,7 +158,7 @@ private static void fillRequiredHeaders( private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuilder { - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; private final String statusCode; @@ -160,10 +167,10 @@ private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuil private boolean oasValidationEnabled = true; public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource oopenApiSpecificationSourceenApiSpec, String operationId, String statusCode) { super(httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = oopenApiSpecificationSourceenApiSpec; this.operationId = operationId; this.statusCode = statusCode; this.httpMessage = httpMessage; @@ -172,23 +179,24 @@ public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, @Override public Message build(TestContext context, String messageType) { - openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(operationPathAdapter, context), () -> { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); + openApiSpecification.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); }); return super.build(context, messageType); } - private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { + private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { OasOperation operation = operationPathAdapter.operation(); if (oasValidationEnabled && operation.responses != null) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - openApiSpec.getOpenApiDoc(context), operation, statusCode, null); + openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); responseForRandomGeneration.ifPresent( - oasResponse -> fillMessageFromResponse(openApiSpec, context, httpMessage, + oasResponse -> fillMessageFromResponse(openApiSpecification, context, httpMessage, operation, oasResponse)); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java index 304893486b..e0404854e8 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java @@ -31,7 +31,7 @@ */ public class OpenApiServerActionBuilder extends AbstractReferenceResolverAwareTestActionBuilder { - private final OpenApiSpecification specification; + private final OpenApiSpecificationSource openApiSpecificationSource; /** Target http client instance */ private Endpoint httpServer; @@ -40,24 +40,25 @@ public class OpenApiServerActionBuilder extends AbstractReferenceResolverAwareTe /** * Default constructor. */ - public OpenApiServerActionBuilder(Endpoint httpServer, OpenApiSpecification specification) { + public OpenApiServerActionBuilder(Endpoint httpServer, OpenApiSpecificationSource specification) { this.httpServer = httpServer; - this.specification = specification; + this.openApiSpecificationSource = specification; } /** * Default constructor. */ - public OpenApiServerActionBuilder(String httpServerUri, OpenApiSpecification specification) { + public OpenApiServerActionBuilder(String httpServerUri, OpenApiSpecificationSource specification) { this.httpServerUri = httpServerUri; - this.specification = specification; + this.openApiSpecificationSource = specification; } /** * Receive Http requests as server. */ public OpenApiServerRequestActionBuilder receive(String operationId) { - OpenApiServerRequestActionBuilder builder = new OpenApiServerRequestActionBuilder(specification, operationId); + OpenApiServerRequestActionBuilder builder = new OpenApiServerRequestActionBuilder( + openApiSpecificationSource, operationId); if (httpServer != null) { builder.endpoint(httpServer); } else { @@ -104,7 +105,8 @@ public OpenApiServerResponseActionBuilder send(String operationId, String status * Send Http response messages as server to client. */ public OpenApiServerResponseActionBuilder send(String operationId, String statusCode, String accept) { - OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder(specification, operationId, statusCode, accept); + OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder( + openApiSpecificationSource, operationId, statusCode, accept); if (httpServer != null) { builder.endpoint(httpServer); } else { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java index bfb8c4ea5c..6ace067846 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java @@ -39,11 +39,12 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiRequestValidationProcessor; +import org.citrusframework.openapi.validation.OpenApiMessageProcessor; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -52,9 +53,9 @@ */ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBuilder { - private OpenApiRequestValidationProcessor openApiRequestValidationProcessor; + private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; @@ -63,25 +64,27 @@ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBu /** * Default constructor initializes http request message builder. */ - public OpenApiServerRequestActionBuilder(OpenApiSpecification openApiSpec, String operationId) { - this(new HttpMessage(), openApiSpec, operationId); + public OpenApiServerRequestActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, String operationId) { + this(new HttpMessage(), openApiSpecificationSource, operationId); } public OpenApiServerRequestActionBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource openApiSpecificationSource, String operationId) { - super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpec, operationId), + super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpecificationSource, operationId), httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } @Override public ReceiveMessageAction doBuild() { - if (oasValidationEnabled && !messageProcessors.contains(openApiRequestValidationProcessor)) { - openApiRequestValidationProcessor = new OpenApiRequestValidationProcessor(openApiSpec, operationId); - validate(openApiRequestValidationProcessor); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); + if (oasValidationEnabled && !messageProcessors.contains(openApiMessageProcessor)) { + openApiMessageProcessor = new OpenApiMessageProcessor( + openApiSpecification, operationId, OpenApiMessageType.REQUEST); + process(openApiMessageProcessor); } return super.doBuild(); @@ -94,16 +97,16 @@ public OpenApiServerRequestActionBuilder disableOasValidation(boolean disable) { private static class OpenApiServerRequestMessageBuilder extends HttpMessageBuilder { - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; private final HttpMessage httpMessage; public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource openApiSpec, String operationId) { super(httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; this.httpMessage = httpMessage; } @@ -111,21 +114,23 @@ public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, @Override public Message build(TestContext context, String messageType) { - openApiSpec.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(operationPathAdapter, context), () -> { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpec.getSpecUrl())); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); + + openApiSpecification.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); }); return super.build(context, messageType); } - private void buildMessageFromOperation(OperationPathAdapter operationPathAdapter, TestContext context) { + private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { setSpecifiedMessageType(operationPathAdapter); - setSpecifiedHeaders(context, operationPathAdapter); - setSpecifiedQueryParameters(context, operationPathAdapter); - setSpecifiedPath(context, operationPathAdapter); - setSpecifiedBody(context, operationPathAdapter); + setSpecifiedHeaders(context, openApiSpecification, operationPathAdapter); + setSpecifiedQueryParameters(context, openApiSpecification, operationPathAdapter); + setSpecifiedPath(context, openApiSpecification, operationPathAdapter); + setSpecifiedBody(context, openApiSpecification, operationPathAdapter); setSpecifiedRequestContentType(operationPathAdapter); setSpecifiedMethod(operationPathAdapter); @@ -137,12 +142,12 @@ private void setSpecifiedRequestContentType(OperationPathAdapter operationPathAd String.format("@startsWith(%s)@", contentType))); } - private void setSpecifiedPath(TestContext context, OperationPathAdapter operationPathAdapter) { - String randomizedPath = OasModelHelper.getBasePath(openApiSpec.getOpenApiDoc(context)) + private void setSpecifiedPath(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { + String randomizedPath = OasModelHelper.getBasePath(openApiSpecification.getOpenApiDoc(context)) + operationPathAdapter.apiPath(); randomizedPath = randomizedPath.replace("//", "/"); - randomizedPath = appendSegmentToUrlPath(openApiSpec.getRootContextPath(), randomizedPath); + randomizedPath = appendSegmentToUrlPath(openApiSpecification.getRootContextPath(), randomizedPath); if (operationPathAdapter.operation().parameters != null) { randomizedPath = determinePath(context, operationPathAdapter.operation(), @@ -152,13 +157,14 @@ private void setSpecifiedPath(TestContext context, OperationPathAdapter operatio httpMessage.path(randomizedPath); } - private void setSpecifiedBody(TestContext context, OperationPathAdapter operationPathAdapter) { + private void setSpecifiedBody(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { Optional body = OasModelHelper.getRequestBodySchema( - openApiSpec.getOpenApiDoc(context), operationPathAdapter.operation()); + openApiSpecification.getOpenApiDoc(context), operationPathAdapter.operation()); body.ifPresent(oasSchema -> httpMessage.setPayload( OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, OasModelHelper.getSchemaDefinitions( - openApiSpec.getOpenApiDoc(context)), openApiSpec))); + openApiSpecification.getOpenApiDoc(context)), + openApiSpecification))); } private String determinePath(TestContext context, OasOperation operation, @@ -189,7 +195,7 @@ private String determinePath(TestContext context, OasOperation operation, return randomizedPath; } - private void setSpecifiedQueryParameters(TestContext context, + private void setSpecifiedQueryParameters(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { @@ -204,13 +210,13 @@ private void setSpecifiedQueryParameters(TestContext context, .forEach(param -> httpMessage.queryParam(param.getName(), OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, - openApiSpec, + OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), false, + openApiSpecification, context))); } - private void setSpecifiedHeaders(TestContext context, + private void setSpecifiedHeaders(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { @@ -225,8 +231,8 @@ private void setSpecifiedHeaders(TestContext context, .forEach(param -> httpMessage.setHeader(param.getName(), OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(openApiSpec.getOpenApiDoc(context)), false, - openApiSpec, + OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), false, + openApiSpecification, context))); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index 3b4a522f92..4518f1e6b3 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -37,6 +37,7 @@ import java.util.function.Predicate; import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; +import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -51,7 +52,7 @@ import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiResponseValidationProcessor; +import org.citrusframework.openapi.validation.OpenApiMessageProcessor; import org.springframework.http.HttpStatus; /** @@ -59,9 +60,9 @@ */ public class OpenApiServerResponseActionBuilder extends HttpServerResponseActionBuilder { - private OpenApiResponseValidationProcessor openApiResponseValidationProcessor; + private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; @@ -70,26 +71,27 @@ public class OpenApiServerResponseActionBuilder extends HttpServerResponseAction /** * Default constructor initializes http response message builder. */ - public OpenApiServerResponseActionBuilder(OpenApiSpecification openApiSpec, String operationId, + public OpenApiServerResponseActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode, String accept) { - this(new HttpMessage(), openApiSpec, operationId, statusCode, accept); + this(new HttpMessage(), openApiSpecificationSource, operationId, statusCode, accept); } public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode, String accept) { - super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpec, operationId, + super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, statusCode, accept), httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } @Override public SendMessageAction doBuild() { - - if (oasValidationEnabled && !messageProcessors.contains(openApiResponseValidationProcessor)) { - openApiResponseValidationProcessor = new OpenApiResponseValidationProcessor(openApiSpec, operationId); - process(openApiResponseValidationProcessor); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); + if (oasValidationEnabled && !messageProcessors.contains(openApiMessageProcessor)) { + openApiMessageProcessor = new OpenApiMessageProcessor( + openApiSpecification, operationId, OpenApiMessageType.RESPONSE); + process(openApiMessageProcessor); } return super.doBuild(); @@ -100,6 +102,16 @@ public OpenApiServerResponseActionBuilder disableOasValidation(boolean disable) return this; } + /** + * By default, enable schema validation as the OpenAPI is always available. + */ + @Override + protected HttpMessageBuilderSupport createMessageBuilderSupport() { + HttpMessageBuilderSupport messageBuilderSupport = super.createMessageBuilderSupport(); + messageBuilderSupport.schemaValidation(true); + return messageBuilderSupport; + } + public OpenApiServerResponseActionBuilder enableRandomGeneration(boolean enable) { ((OpenApiServerResponseMessageBuilder)getMessageBuilderSupport().getMessageBuilder()).enableRandomGeneration(enable); return this; @@ -109,17 +121,17 @@ private static class OpenApiServerResponseMessageBuilder extends HttpMessageBuil private static final Pattern STATUS_CODE_PATTERN = Pattern.compile("\\d+"); - private final OpenApiSpecification openApiSpec; + private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; private final String statusCode; private final String accept; private boolean randomGenerationEnabled = true; public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecification openApiSpec, + OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode, String accept) { super(httpMessage); - this.openApiSpec = openApiSpec; + this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; this.statusCode = statusCode; this.accept = accept; @@ -133,6 +145,7 @@ public OpenApiServerResponseMessageBuilder enableRandomGeneration(boolean enable @Override public Message build(TestContext context, String messageType) { + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); if (STATUS_CODE_PATTERN.matcher(statusCode).matches()) { getMessage().status(HttpStatus.valueOf(parseInt(statusCode))); } else { @@ -143,12 +156,12 @@ public Message build(TestContext context, String messageType) { getHeaderBuilders().clear(); if (randomGenerationEnabled) { - openApiSpec.getOperation(operationId, context) + openApiSpecification.getOperation(operationId, context) .ifPresentOrElse(operationPathAdapter -> - fillRandomData(operationPathAdapter, context), () -> { + fillRandomData(openApiSpecification, operationPathAdapter, context), () -> { throw new CitrusRuntimeException( "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpec.getSpecUrl())); + operationId, openApiSpecification.getSpecUrl())); }); } @@ -158,25 +171,25 @@ public Message build(TestContext context, String messageType) { return super.build(context, messageType); } - private void fillRandomData(OperationPathAdapter operationPathAdapter, TestContext context) { + private void fillRandomData(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { if (operationPathAdapter.operation().responses != null) { - buildResponse(context, operationPathAdapter.operation()); + buildResponse(context, openApiSpecification, operationPathAdapter.operation()); } } - private void buildResponse(TestContext context, OasOperation operation) { + private void buildResponse(TestContext context, OpenApiSpecification openApiSpecification, OasOperation operation) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - openApiSpec.getOpenApiDoc(context), operation, statusCode, null); + openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); if (responseForRandomGeneration.isPresent()) { - buildRandomHeaders(context, responseForRandomGeneration.get()); - buildRandomPayload(operation, responseForRandomGeneration.get()); + buildRandomHeaders(context, openApiSpecification, responseForRandomGeneration.get()); + buildRandomPayload(openApiSpecification, operation, responseForRandomGeneration.get()); } } - private void buildRandomHeaders(TestContext context, OasResponse response) { + private void buildRandomHeaders(TestContext context, OpenApiSpecification openApiSpecification, OasResponse response) { Set filteredHeaders = new HashSet<>(getMessage().getHeaders().keySet()); Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains( entry.getKey()); @@ -188,7 +201,7 @@ private void buildRandomHeaders(TestContext context, OasResponse response) { .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), entry.getValue(), - openApiSpec, + openApiSpecification, context)))) ); @@ -205,7 +218,7 @@ private void buildRandomHeaders(TestContext context, OasResponse response) { + CitrusSettings.VARIABLE_SUFFIX))))); } - private void buildRandomPayload(OasOperation operation, OasResponse response) { + private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOperation operation, OasResponse response) { Optional> schemaForMediaTypeOptional; if (statusCode.startsWith("2")) { @@ -222,7 +235,7 @@ private void buildRandomPayload(OasOperation operation, OasResponse response) { OasAdapter schemaForMediaType = schemaForMediaTypeOptional.get(); if (getMessage().getPayload() == null || ( getMessage().getPayload() instanceof String string && string.isEmpty())) { - createRandomPayload(getMessage(), schemaForMediaType); + createRandomPayload(getMessage(), openApiSpecification, schemaForMediaType); } // If we have a schema and a media type and the content type has not yet been set, do it. @@ -233,7 +246,7 @@ private void buildRandomPayload(OasOperation operation, OasResponse response) { } } - private void createRandomPayload(HttpMessage message, OasAdapter schemaForMediaType) { + private void createRandomPayload(HttpMessage message, OpenApiSpecification openApiSpecification, OasAdapter schemaForMediaType) { if (schemaForMediaType.node() == null) { // No schema means no payload, no type @@ -241,11 +254,13 @@ private void createRandomPayload(HttpMessage message, OasAdapter openApiRepository.openApi(openApiAlias)).filter( + Objects::nonNull).findFirst().orElseThrow(() -> + new CitrusRuntimeException( + "Unable to resolve OpenApiSpecification from alias '%s'. Known aliases for open api specs are '%s'".formatted( + openApiAlias, OpenApiUtils.getKnownOpenApiAliases(resolver))) + ); + } else { + throw new CitrusRuntimeException( + "Unable to resolve OpenApiSpecification. Neither OpenAPI spec, nor OpenAPI alias are specified."); + } + } + + if (httpClient != null) { + openApiSpecification.setHttpClient(httpClient); + } + + return openApiSpecification; + } + + public void setHttpClient(String httpClient) { + this.httpClient = httpClient; + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java index c1a1999ac9..e5aebaea7e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -30,7 +30,7 @@ * @param fullPath The full path combining context path and API path. * @param operation The {@link OasOperation} object representing the operation details. */ -public record OperationPathAdapter(String apiPath, String contextPath, String fullPath, OasOperation operation) { +public record OperationPathAdapter(String apiPath, String contextPath, String fullPath, OasOperation operation, String uniqueOperationId) { @Override public String toString() { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java index ae4008111a..3e9ea0951e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java @@ -21,9 +21,12 @@ import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nonnull; +import java.util.stream.Collectors; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.OpenApiConstants; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.util.StringUtils; public class OpenApiUtils { @@ -73,4 +76,18 @@ public static boolean isRequired(OasSchema schema, String field) { return schema.required.contains(field); } + /** + * Retrieves all known OpenAPI aliases from {@link org.citrusframework.openapi.OpenApiSpecification}s + * registered in {@link OpenApiRepository}s. + * + * @param resolver the {@code ReferenceResolver} to use for resolving {@code OpenApiRepository} instances. + * @return a comma-separated string of all known OpenAPI aliases. + */ + public static String getKnownOpenApiAliases(ReferenceResolver resolver) { + return resolver.resolveAll(OpenApiRepository.class).values() + .stream().flatMap( + openApiRepository -> openApiRepository.getOpenApiSpecifications() + .stream()).flatMap(spec -> spec.getAliases().stream()).collect( + Collectors.joining(", ")); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java new file mode 100644 index 0000000000..d20c899fc2 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java @@ -0,0 +1,56 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.validation; + +import org.citrusframework.openapi.OpenApiMessageType; +import org.citrusframework.context.TestContext; +import org.citrusframework.message.Message; +import org.citrusframework.message.MessageProcessor; +import org.citrusframework.openapi.OpenApiMessageHeaders; +import org.citrusframework.openapi.OpenApiSpecification; + +/** + * {@code MessageProcessor} that prepares the message for OpenAPI validation by setting respective + * message headers. + */ +public class OpenApiMessageProcessor implements MessageProcessor { + + private final OpenApiSpecification openApiSpecification; + + private final String operationId; + + private final OpenApiMessageType type; + + public OpenApiMessageProcessor(OpenApiSpecification openApiSpecification, + String operationId, OpenApiMessageType type) { + this.operationId = operationId; + this.openApiSpecification = openApiSpecification; + this.type = type; + } + + @Override + public void process(Message message, TestContext context) { + + openApiSpecification + .getOperation(operationId, context) + .ifPresent(operationPathAdapter -> { + // Store the uniqueId of the operation, rather than the operationId, to avoid clashes. + message.setHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID, operationPathAdapter.uniqueOperationId()); + message.setHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE, type.toHeaderName()); + }); + } +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java new file mode 100644 index 0000000000..cc79a4a5a4 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java @@ -0,0 +1,117 @@ +package org.citrusframework.openapi.validation; + +import org.citrusframework.openapi.OpenApiSettings; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.validation.context.DefaultValidationContext; +import org.citrusframework.validation.context.SchemaValidationContext; +import org.citrusframework.validation.context.ValidationContext; + +/** + * Validation context holding OpenAPI specific validation information. + * + * @since 4.3 + */ +public class OpenApiMessageValidationContext extends DefaultValidationContext implements + SchemaValidationContext { + + /** + * Should message be validated with its schema definition. This is enabled with respect to + * global settings, which are true by default. as only messages processed by open api actions + * will be processed and validation information will be derived from open api spec. + * + *

    Note that the default registered validation context is used for received messages. This is + * why the schema validation is initialized with response validation enabled globally. + */ + private boolean schemaValidation = OpenApiSettings.isResponseValidationEnabledGlobally(); + + + public OpenApiMessageValidationContext(Builder builder) { + super(); + + // If not explicitly specified, goe for the default. + this.schemaValidation = builder.schemaValidation != null ? builder.schemaValidation + : builder.openApiSpecification.isApiRequestValidationEnabled() + || builder.openApiSpecification.isApiResponseValidationEnabled(); + + } + + @Override + public boolean isSchemaValidationEnabled() { + return schemaValidation; + } + + @Override + public String getSchemaRepository() { + return null; + } + + @Override + public String getSchema() { + return null; + } + + /** + * Fluent builder + */ + public static final class Builder implements + ValidationContext.Builder, + SchemaValidationContext.Builder { + + private OpenApiSpecification openApiSpecification; + + /** + * Mapped as object to be able to indicate "not explicitly set" in which case the default is + * chosen. + * + *

    Note that a message validation context is explicitly created only for send messages, + * whereas default request validation enabled is chosen as default value. + */ + private Boolean schemaValidation = OpenApiSettings.isRequestValidationEnabledGlobally(); + + public static OpenApiMessageValidationContext.Builder openApi( + OpenApiSpecification openApiSpecification) { + Builder builder = new Builder(); + builder.openApiSpecification = openApiSpecification; + return builder; + } + + public OpenApiMessageValidationContext.Builder expressions() { + return new OpenApiMessageValidationContext.Builder(); + } + + public OpenApiMessageValidationContext.Builder expression(String path, + Object expectedValue) { + return new OpenApiMessageValidationContext.Builder().expression(path, expectedValue); + } + + /** + * Sets schema validation enabled/disabled for this message. + */ + public OpenApiMessageValidationContext.Builder schemaValidation(final boolean enabled) { + this.schemaValidation = enabled; + return this; + } + + /** + * Not used for open api validation. Schema is automatically be derived from associated openApiSpecification. + */ + @Override + public OpenApiMessageValidationContext.Builder schema(final String schemaName) { + return this; + } + + /** + * Not used for open api validation. Schema is automatically be derived from associated openApiSpecification. + */ + @Override + public OpenApiMessageValidationContext.Builder schemaRepository( + final String schemaRepository) { + return this; + } + + @Override + public OpenApiMessageValidationContext build() { + return new OpenApiMessageValidationContext(this); + } + } +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java index cb14d44c89..e8c49cb2b6 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java @@ -19,6 +19,7 @@ import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiMessageHeaders; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.validation.ValidationProcessor; @@ -49,6 +50,8 @@ public void validate(Message message, TestContext context) { return; } + message.setHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID, operationId); + openApiSpecification.getOperation( operationId, context).ifPresent(operationPathAdapter -> openApiRequestValidator.validateRequest(operationPathAdapter, httpMessage)); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java index 94aa08ae9a..b37e53f660 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -57,6 +57,17 @@ public void validateRequest(OperationPathAdapter operationPathAdapter, } } + public ValidationReport validateRequestToReport(OperationPathAdapter operationPathAdapter, + HttpMessage requestMessage) { + + if (enabled && openApiInteractionValidator != null) { + return openApiInteractionValidator.validateRequest( + createRequestFromMessage(operationPathAdapter, requestMessage)); + } + + return ValidationReport.empty(); + } + Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { var payload = httpMessage.getPayload(); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java deleted file mode 100644 index c098fda6a0..0000000000 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessor.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.validation.ValidationProcessor; - -/** - * {@code ValidationProcessor} that delegates validation of OpenApi responses to instances of - * {@link OpenApiResponseValidator}. - */ -public class OpenApiResponseValidationProcessor implements - ValidationProcessor { - - private final OpenApiSpecification openApiSpecification; - - private final String operationId; - - private final OpenApiResponseValidator openApiResponseValidator; - - public OpenApiResponseValidationProcessor(OpenApiSpecification openApiSpecification, - String operationId) { - this.operationId = operationId; - this.openApiSpecification = openApiSpecification; - this.openApiResponseValidator = new OpenApiResponseValidator(openApiSpecification); - } - - @Override - public void validate(Message message, TestContext context) { - - if (!(message instanceof HttpMessage httpMessage)) { - return; - } - - openApiSpecification.getOperation( - operationId, context).ifPresent(operationPathAdapter -> - openApiResponseValidator.validateResponse(operationPathAdapter, httpMessage)); - } - -} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java index faefe24a9b..8a08242617 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -59,7 +59,23 @@ public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMess } } - Response createResponseFromMessage(HttpMessage message, Integer statusCode) { + public ValidationReport validateResponseToReport(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { + + if (enabled && openApiInteractionValidator != null) { + HttpStatusCode statusCode = httpMessage.getStatusCode(); + Response response = createResponseFromMessage(httpMessage, + statusCode != null ? statusCode.value() : null); + + return openApiInteractionValidator.validateResponse( + operationPathAdapter.apiPath(), + Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), + response); + + } + return ValidationReport.empty(); + } + + Response createResponseFromMessage(HttpMessage message, Integer statusCode) { var payload = message.getPayload(); SimpleResponse.Builder responseBuilder = new SimpleResponse.Builder(statusCode); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java new file mode 100644 index 0000000000..74b5a55046 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -0,0 +1,166 @@ +package org.citrusframework.openapi.validation; + +import com.atlassian.oai.validator.report.ValidationReport; +import jakarta.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiMessageHeaders; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.openapi.util.OpenApiUtils; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder; +import org.citrusframework.validation.MessageValidator; +import org.citrusframework.validation.SchemaValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OpenApiSchemaValidation implements MessageValidator, + SchemaValidator { + + private Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); + + @Override + public void validateMessage(Message receivedMessage, Message controlMessage, + TestContext context, List list) throws ValidationException { + validate(receivedMessage, context, new Builder().schemaValidation(true).build()); + } + + @Override + public void validate( + Message message, TestContext context, OpenApiMessageValidationContext validationContext) { + logger.debug("Starting OpenApi schema validation ..."); + + if (!(message instanceof HttpMessage httpMessage)) { + return; + } + + ValidationReportData validationReportData = validate(context, httpMessage, + findSchemaRepositories(context), + validationContext); + if (validationReportData != null && validationReportData.report.hasErrors()) { + if (logger.isErrorEnabled()) { + logger.error("Failed to validate Json schema for message:\n{}", + message.getPayload(String.class)); + } + throw new ValidationException(constructErrorMessage(validationReportData)); + } + + logger.debug("Json schema validation successful: All values OK"); + } + + @Override + public boolean supportsMessageType(String messageType, Message message) { + return message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null; + } + + private String constructErrorMessage(ValidationReportData validationReportData) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("OpenApi "); + stringBuilder.append(validationReportData.type); + stringBuilder.append(" validation failed for operation: "); + stringBuilder.append(validationReportData.operationPathAdapter); + validationReportData.report.getMessages() + .forEach(message -> stringBuilder.append("\n\t").append(message)); + return stringBuilder.toString(); + } + + /** + * Find json schema repositories in test context. + */ + private List findSchemaRepositories(TestContext context) { + return new ArrayList<>( + context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); + } + + @Nullable + private ValidationReportData validate(TestContext context, HttpMessage message, + List schemaRepositories, + OpenApiMessageValidationContext validationContext) { + + if (!validationContext.isSchemaValidationEnabled()) { + return null; + } + if (schemaRepositories.isEmpty()) { + return null; + } else { + + // Is it request or response? + String uniqueOperationId = (String) message.getHeader( + OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); + + OpenApiSpecification openApiSpecification = schemaRepositories + .stream() + .flatMap(repository -> repository.getOpenApiSpecifications().stream()) + .filter(spec -> spec.getOperation(uniqueOperationId, + context).isPresent()).findFirst().orElse(null); + + if (openApiSpecification == null) { + throw new CitrusRuntimeException(""" + Unable to derive OpenAPI spec for operation '%s' for validation of message from available " + schema repositories. Known repository aliases are: %s""".formatted( + uniqueOperationId, OpenApiUtils.getKnownOpenApiAliases( + context.getReferenceResolver()))); + } + + OperationPathAdapter operationPathAdapter = openApiSpecification.getOperation( + uniqueOperationId, context).orElseThrow(() -> new CitrusRuntimeException( + "Unexpectedly could not resolve operation path adapter for operationId: " + + uniqueOperationId)); + ValidationReportData validationReportData = null; + if (isRequestMessage(message)) { + ValidationReport validationReport = new OpenApiRequestValidator( + openApiSpecification).validateRequestToReport(operationPathAdapter, message); + validationReportData = new ValidationReportData(operationPathAdapter, "request", + validationReport); + } else if (isResponseMessage(message)) { + ValidationReport validationReport = new OpenApiResponseValidator( + openApiSpecification).validateResponseToReport(operationPathAdapter, message); + validationReportData = new ValidationReportData(operationPathAdapter, "response", + validationReport); + } + return validationReportData; + } + } + + private boolean isResponseMessage(HttpMessage message) { + return OpenApiMessageHeaders.RESPONSE_TYPE.equals( + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); + } + + private boolean isRequestMessage(HttpMessage message) { + return OpenApiMessageHeaders.REQUEST_TYPE.equals( + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); + } + + private record ValidationReportData(OperationPathAdapter operationPathAdapter, String type, + ValidationReport report) { + + } + + @Override + public boolean canValidate(Message message, boolean schemaValidationEnabled) { + return schemaValidationEnabled && + message instanceof HttpMessage httpMessage && (isRequestMessage(httpMessage) + || isResponseMessage(httpMessage)); + } + + @Override + public void validate(Message message, TestContext context, String schemaRepository, + String schema) { + + if (!(message instanceof HttpMessage)) { + return; + } + + validate(message, context, + new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) + .build()); + + } +} diff --git a/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/schemaValidator/openApi b/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/schemaValidator/openApi new file mode 100644 index 0000000000..897edb75c0 --- /dev/null +++ b/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/schemaValidator/openApi @@ -0,0 +1,2 @@ +name=defaultOpenApiSchemaValidator +type=org.citrusframework.openapi.validation.OpenApiSchemaValidation diff --git a/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/validator/openApi b/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/validator/openApi new file mode 100644 index 0000000000..ad5d27c497 --- /dev/null +++ b/connectors/citrus-openapi/src/main/resources/META-INF/citrus/message/validator/openApi @@ -0,0 +1,2 @@ +name=defaultOpenApiMessageValidator +type=org.citrusframework.openapi.validation.OpenApiSchemaValidation diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java new file mode 100644 index 0000000000..39486d14f8 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java @@ -0,0 +1,18 @@ +package org.citrusframework.openapi; + +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +public class OpenApiMessageTypeTest { + + @Test + public void testToHeaderNameRequest() { + assertEquals(OpenApiMessageType.REQUEST.toHeaderName(), OpenApiMessageHeaders.REQUEST_TYPE); + } + + @Test + public void testToHeaderNameResponse() { + assertEquals(OpenApiMessageHeaders.REQUEST_TYPE, OpenApiMessageHeaders.RESPONSE_TYPE); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index fe61791bf2..15f6fa113e 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -71,7 +71,7 @@ public void shouldResolveResourceAliasFromFile() { Optional alias = OpenApiRepository.determineResourceAlias(resourceMock); assertTrue(alias.isPresent()); - assertEquals(alias.get(), "MyApi.json"); + assertEquals(alias.get(), "MyApi"); } @Test @@ -84,7 +84,7 @@ public void shouldResolveResourceAliasFromUrl() throws MalformedURLException { Optional alias = OpenApiRepository.determineResourceAlias(resourceMock); assertTrue(alias.isPresent()); - assertEquals(alias.get(), "MyApi.json"); + assertEquals(alias.get(), "MyApi"); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java index 9dbc709fa6..533ccb5211 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java @@ -16,17 +16,25 @@ package org.citrusframework.openapi; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.util.OpenApiUtils; +import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.spi.ReferenceResolver; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.citrusframework.openapi.util.OpenApiUtils.getKnownOpenApiAliases; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; public class OpenApiUtilsTest { @@ -94,4 +102,56 @@ public void shouldReturnFormattedMethodPathWhenMethodAndPathAreEmpty() { // Then assertEquals(methodPath, "//"); } + + @Test + public void testGetKnownOpenApiAliases() { + + ReferenceResolver resolver = mock(); + OpenApiRepository repository1 = mock(); + OpenApiRepository repository2 = mock(); + OpenApiSpecification spec1 = mock(); + OpenApiSpecification spec2 = mock(); + + when(resolver.resolveAll(OpenApiRepository.class)).thenReturn( + Map.of( + "repo1", repository1, + "repo2", repository2 + ) + ); + + when(repository1.getOpenApiSpecifications()).thenReturn(List.of(spec1)); + when(repository2.getOpenApiSpecifications()).thenReturn(List.of(spec2)); + + when(spec1.getAliases()).thenReturn(Set.of("alias1", "alias2")); + when(spec2.getAliases()).thenReturn(Set.of("alias3")); + + String result = getKnownOpenApiAliases(resolver); + + assertTrue(result.contains("alias1")); + assertTrue(result.contains("alias2")); + assertTrue(result.contains("alias3")); + } + + @Test + public void testGetKnownOpenApiAliasesNoAliases() { + ReferenceResolver resolver = mock(); + OpenApiRepository repository1 = mock(); + OpenApiRepository repository2 = mock(); + + when(resolver.resolveAll(OpenApiRepository.class)).thenReturn( + Map.of( + "repo1", repository1, + "repo2", repository2 + ) + ); + + when(repository1.getOpenApiSpecifications()).thenReturn(List.of()); + when(repository2.getOpenApiSpecifications()).thenReturn(List.of()); + + // Call the method under test + String result = getKnownOpenApiAliases(resolver); + + // Verify the result + assertEquals(result, ""); + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index 607d1b3c54..33aad7e924 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -178,7 +178,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { validator.validateMessage(request, controlMessage, context, new DefaultValidationContext()); ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); @@ -197,7 +197,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); - Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 0); + Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); @@ -218,7 +218,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(sendMessageAction.getEndpoint(), httpClient); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index 94786d08c2..c210208820 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -23,6 +23,7 @@ import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; @@ -35,6 +36,8 @@ import org.testng.annotations.Ignore; import org.testng.annotations.Test; +import java.util.List; + import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; import static org.testng.Assert.assertThrows; @@ -61,8 +64,12 @@ public class OpenApiClientIT extends TestNGCitrusSpringSupport { .requestUrl("http://localhost:%d".formatted(port)) .build(); + @BindToRegistry + private final OpenApiRepository openApiRepository = new OpenApiRepository() + .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); private final OpenApiSpecification pingSpec = OpenApiSpecification.from( Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); @@ -140,8 +147,7 @@ public void shouldFailOnMissingNameInRequest() { HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) .client(httpClient) .send("addPet") - .message().body(Resources.create(INVALID_PET_PATH)) - .fork(true); + .message().body(Resources.create(INVALID_PET_PATH)); assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); } @@ -153,9 +159,7 @@ public void shouldFailOnWrongQueryIdType() { HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) .client(httpClient) .send("addPet") - .message().body(Resources.create(VALID_PET_PATH)) - .fork(true); - + .message().body(Resources.create(VALID_PET_PATH)); assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); } @@ -167,8 +171,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { .client(httpClient) .send("addPet") .disableOasValidation(true) - .message().body(Resources.create(VALID_PET_PATH)) - .fork(true); + .message().body(Resources.create(VALID_PET_PATH)); try { when(addPetBuilder); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 82d48fa427..808c84cdc2 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -23,7 +23,7 @@ import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; -import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerResponseActionBuilder; @@ -34,6 +34,8 @@ import org.springframework.http.HttpStatus; import org.testng.annotations.Test; +import java.util.List; + import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; import static org.testng.Assert.assertThrows; @@ -60,11 +62,10 @@ public class OpenApiServerIT extends TestNGCitrusSpringSupport { .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) .build(); - /** - * Directly loaded open api. - */ - private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + @BindToRegistry + private final OpenApiRepository openApiRepository = new OpenApiRepository() + .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + @CitrusTest public void shouldExecuteGetPetById() { @@ -78,11 +79,11 @@ public void shouldExecuteGetPetById() { .accept("application/json") .fork(true)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .server(httpServer) .receive("getPetById")); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .server(httpServer) .send("getPetById", HttpStatus.OK)); @@ -118,11 +119,11 @@ public void executeGetPetByIdShouldFailOnInvalidResponse() { .accept("application/json") .fork(true)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .server(httpServer) .receive("getPetById")); - HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") .server(httpServer) .send("getPetById", HttpStatus.OK) .message().body(""" @@ -153,11 +154,11 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable .accept("application/json") .fork(true)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .server(httpServer) .receive("getPetById")); - HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") .server(httpServer) .send("getPetById", HttpStatus.OK) .disableOasValidation(true) @@ -198,12 +199,12 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable @CitrusTest public void shouldExecuteAddPet() { - shouldExecuteAddPet(openapi(petstoreSpec), VALID_PET_PATH, true); + shouldExecuteAddPet(openapi("petstore-v3"), VALID_PET_PATH, true); } @CitrusTest public void shouldFailOnMissingNameInRequest() { - shouldExecuteAddPet(openapi(petstoreSpec), INVALID_PET_PATH, false); + shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false); } @CitrusTest @@ -218,11 +219,11 @@ public void shouldFailOnMissingNameInResponse() { .accept("application/json") .fork(true)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .server(httpServer) .receive("getPetById")); - OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi(petstoreSpec) + OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi("petstore-v3") .server(httpServer) .send("getPetById", HttpStatus.OK); sendMessageActionBuilder.message().body(Resources.create(INVALID_PET_PATH)); @@ -244,7 +245,7 @@ public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { .contentType("application/json") .fork(true)); - OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) + OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") .server(httpServer) .receive("addPet"); @@ -264,7 +265,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { .contentType("application/json") .fork(true)); - OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) + OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") .server(httpServer) .receive("addPet") .disableOasValidation(false); @@ -293,18 +294,21 @@ private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFil .receive("addPet"); if (valid) { then(receiveActionBuilder); - } else { - assertThrows(() -> then(receiveActionBuilder)); - } - then(openapi + then(openapi .server(httpServer) .send("addPet", HttpStatus.CREATED)); - then(http() + then(http() .client(httpClient) .receive() .response(HttpStatus.CREATED)); + + } else { + assertThrows(() -> then(receiveActionBuilder)); + } + + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java index d24101fb35..68c5da1786 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java @@ -31,7 +31,8 @@ public void shouldReturnFormattedStringWhenToStringIsCalled() { Oas30Operation oas30Operation = new Oas30Operation("get"); oas30Operation.operationId = "operationId"; - OperationPathAdapter adapter = new OperationPathAdapter("/api/path", "/context/path", "/full/path", oas30Operation); + OperationPathAdapter adapter = new OperationPathAdapter("/api/path", "/context/path", "/full/path", oas30Operation, + oas30Operation.operationId); // When String expectedString = format("%s (%s)", OpenApiUtils.getMethodPath("GET", "/api/path"), "operationId"); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java new file mode 100644 index 0000000000..34f82542a2 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java @@ -0,0 +1,59 @@ +package org.citrusframework.openapi.validation; + +import java.util.Optional; +import org.citrusframework.context.TestContext; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiMessageHeaders; +import org.citrusframework.openapi.OpenApiMessageType; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OperationPathAdapter; +import org.mockito.Mockito; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; + +public class OpenApiMessageProcessorTest { + + private OpenApiSpecification openApiSpecification; + private String operationId; + private OpenApiMessageType type; + private OpenApiMessageProcessor processor; + private Message message; + private TestContext context; + + @BeforeMethod + public void setUp() { + openApiSpecification = mock(OpenApiSpecification.class); + operationId = "testOperationId"; + type = mock(OpenApiMessageType.class); + processor = new OpenApiMessageProcessor(openApiSpecification, operationId, type); + + message = mock(Message.class); + context = mock(TestContext.class); + } + + @Test + public void testProcess() { + OperationPathAdapter operationPathAdapter = mock(OperationPathAdapter.class); + when(openApiSpecification.getOperation(operationId, context)) + .thenReturn(Optional.of(operationPathAdapter)); + when(operationPathAdapter.uniqueOperationId()).thenReturn("uniqueOperationId"); + when(type.toHeaderName()).thenReturn("headerName"); + + processor.process(message, context); + + verify(message).setHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID, "uniqueOperationId"); + verify(message).setHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE, "headerName"); + } + + @Test + public void testProcessOperationNotPresent() { + when(openApiSpecification.getOperation(operationId, context)) + .thenReturn(Optional.empty()); + + processor.process(message, context); + + verify(message, never()).setHeader(anyString(), anyString()); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java deleted file mode 100644 index 2058af2558..0000000000 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidationProcessorTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.validation; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertNotNull; - -import java.util.Optional; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.test.util.ReflectionTestUtils; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -public class OpenApiResponseValidationProcessorTest { - - @Mock - private OpenApiSpecification openApiSpecificationMock; - - @Mock - private OperationPathAdapter operationPathAdapterMock; - - private OpenApiResponseValidationProcessor processor; - - private AutoCloseable mockCloseable; - - @BeforeMethod - public void beforeMethod() { - mockCloseable = MockitoAnnotations.openMocks(this); - processor = new OpenApiResponseValidationProcessor(openApiSpecificationMock, "operationId"); - } - - @AfterMethod - public void afterMethod() throws Exception { - mockCloseable.close(); - } - - @Test - public void shouldNotValidateNonHttpMessage() { - Message messageMock = mock(); - - processor.validate(messageMock, mock()); - - verify(openApiSpecificationMock,times(2)).getSwaggerOpenApiValidationContext(); - verifyNoMoreInteractions(openApiSpecificationMock); - } - - @Test - public void shouldCallValidateResponse() { - HttpMessage httpMessageMock = mock(); - TestContext contextMock = mock(); - - OpenApiResponseValidator openApiResponseValidatorSpy = replaceValidatorWithSpy(httpMessageMock); - - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.of(operationPathAdapterMock)); - - processor.validate(httpMessageMock, contextMock); - - verify(openApiResponseValidatorSpy).validateResponse(operationPathAdapterMock, httpMessageMock); - } - - @Test - public void shouldNotValidateWhenNoOperation() { - HttpMessage httpMessageMock = mock(); - TestContext contextMock = mock(); - - OpenApiResponseValidator openApiResponseValidatorSpy = replaceValidatorWithSpy(httpMessageMock); - - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.empty()); - - processor.validate(httpMessageMock, contextMock); - - verify(openApiSpecificationMock).getOperation(anyString(), - any(TestContext.class)); - verify(openApiResponseValidatorSpy, times(0)).validateResponse(operationPathAdapterMock, httpMessageMock); - } - - private OpenApiResponseValidator replaceValidatorWithSpy(HttpMessage httpMessage) { - OpenApiResponseValidator openApiResponseValidator = (OpenApiResponseValidator) ReflectionTestUtils.getField( - processor, - "openApiResponseValidator"); - - assertNotNull(openApiResponseValidator); - OpenApiResponseValidator openApiResponseValidatorSpy = spy(openApiResponseValidator); - ReflectionTestUtils.setField(processor, "openApiResponseValidator", openApiResponseValidatorSpy); - - doAnswer((invocation) -> null - // do nothing - ).when(openApiResponseValidatorSpy).validateResponse(operationPathAdapterMock, httpMessage); - - return openApiResponseValidatorSpy; - } -} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index ca2d7e8732..2fc0bb33bf 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -184,7 +184,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { validator.validateMessage(request, controlMessage, context, new DefaultValidationContext()); ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); @@ -203,7 +203,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); - Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 0); + Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); @@ -224,7 +224,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index b5b152d559..e81a89e63b 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -179,7 +179,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { validator.validateMessage(request, controlMessage, context, new DefaultValidationContext()); ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); @@ -198,7 +198,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); - Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 0); + Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); @@ -219,7 +219,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java index 7ba3d3abd4..bbeecbcab6 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java @@ -112,7 +112,11 @@ public List> findMessageValidators if (isEmptyOrDefault(matchingValidators)) { if (mustFindValidator) { - logger.warn(String.format("Unable to find proper message validator. Message type is '%s' and message payload is '%s'", messageType, message.getPayload(String.class))); + if (logger.isWarnEnabled()) { + logger.warn(String.format( + "Unable to find proper message validator. Message type is '%s' and message payload is '%s'", + messageType, message.getPayload(String.class))); + } throw new CitrusRuntimeException("Failed to find proper message validator for message"); } @@ -308,4 +312,11 @@ public Optional> findSchemaVa public void setSchemaValidators(Map> schemaValidators) { this.schemaValidators = schemaValidators; } + + /** + * Return all schema validators. + */ + public Map> getSchemaValidators() { + return schemaValidators; + } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java b/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java index ecc2b006df..3d6a8d11d0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java @@ -88,4 +88,16 @@ static Optional> lookup(Strin * @return true if the message/message type can be validated by this validator */ boolean supportsMessageType(String messageType, Message message); + + /** + * @param message the message which is subject of validation + * @param schemaValidationEnabled flag to indicate whether schema validation is explicitly enabled + * @return true, if the validator can validate the given message + */ + boolean canValidate(Message message, boolean schemaValidationEnabled); + + /** + * Validate the message against the given schemaRepository and schema. + */ + void validate(Message message, TestContext context, String schemaRepository, String schema); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java index 20fa11ccff..d91ae3d002 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java @@ -16,7 +16,6 @@ package org.citrusframework.actions; -import org.citrusframework.CitrusSettings; import org.citrusframework.Completable; import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.Endpoint; @@ -25,16 +24,9 @@ import org.citrusframework.message.MessageBuilder; import org.citrusframework.message.MessageDirection; import org.citrusframework.message.MessageProcessor; -import org.citrusframework.message.MessageType; import org.citrusframework.message.builder.MessageBuilderSupport; import org.citrusframework.message.builder.SendMessageBuilderSupport; -import org.citrusframework.util.IsJsonPredicate; -import org.citrusframework.util.IsXmlPredicate; import org.citrusframework.util.StringUtils; -import org.citrusframework.validation.SchemaValidator; -import org.citrusframework.validation.context.SchemaValidationContext; -import org.citrusframework.validation.json.JsonMessageValidationContext; -import org.citrusframework.validation.xml.XmlMessageValidationContext; import org.citrusframework.variable.VariableExtractor; import org.citrusframework.variable.dictionary.DataDictionary; import org.slf4j.Logger; @@ -128,7 +120,9 @@ public void doExecute(final TestContext context) { finished.whenComplete((ctx, ex) -> { if (ex != null) { - logger.warn("Failure in forked send action: " + ex.getMessage()); + if (logger.isWarnEnabled()) { + logger.warn("Failure in forked send action: %s".formatted(ex.getMessage())); + } } else { for (Exception ctxEx : ctx.getExceptions()) { logger.warn(ctxEx.getMessage()); @@ -146,7 +140,9 @@ public void doExecute(final TestContext context) { if (StringUtils.hasText(message.getName())) { context.getMessageStore().storeMessage(message.getName(), message); } else { - context.getMessageStore().storeMessage(context.getMessageStore().constructMessageName(this, messageEndpoint), message); + context.getMessageStore() + .storeMessage(context.getMessageStore().constructMessageName(this, messageEndpoint), + message); } if (forkMode) { @@ -179,59 +175,14 @@ public void doExecute(final TestContext context) { } /** - * Validate the message against registered schemas. - * @param message + * Validate the message against registered schema validators. */ protected void validateMessage(Message message, TestContext context) { - List> schemaValidators = null; - SchemaValidationContext validationContext = null; - String payload = message.getPayload(String.class); - - if ((isSchemaValidation() || isJsonSchemaValidationEnabled()) && IsJsonPredicate.getInstance().test(payload)) { - schemaValidators = context.getMessageValidatorRegistry() - .findSchemaValidators(MessageType.JSON.name(), message); - validationContext = JsonMessageValidationContext.Builder.json() - .schemaValidation(this.schemaValidation) - .schema(this.schema) - .schemaRepository(this.schemaRepository).build(); - } else if ((isSchemaValidation() || isXmlSchemaValidationEnabled()) && IsXmlPredicate.getInstance().test(payload)) { - schemaValidators = context.getMessageValidatorRegistry() - .findSchemaValidators(MessageType.XML.name(), message); - validationContext = XmlMessageValidationContext.Builder.xml() - .schemaValidation(this.schemaValidation) - .schema(this.schema) - .schemaRepository(this.schemaRepository).build(); - } - - if (schemaValidators != null) { - for (SchemaValidator validator : schemaValidators) { - validator.validate(message, context, validationContext); - } - } - + context.getMessageValidatorRegistry().getSchemaValidators().values().stream() + .filter(validator -> validator.canValidate(message, isSchemaValidation())).forEach(validator -> + validator.validate(message, context, this.schemaRepository, this.schema)); } - /** - * Get setting to determine if json schema validation is enabled by default. - * @return - */ - private static boolean isJsonSchemaValidationEnabled() { - return Boolean.getBoolean(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_PROPERTY) - || Boolean.getBoolean(CitrusSettings.OUTBOUND_JSON_SCHEMA_VALIDATION_ENABLED_PROPERTY) - || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_ENV)) - || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_JSON_SCHEMA_VALIDATION_ENABLED_ENV)); - } - - /** - * Get setting to determine if xml schema validation is enabled by default. - * @return - */ - private static boolean isXmlSchemaValidationEnabled() { - return Boolean.getBoolean(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_PROPERTY) - || Boolean.getBoolean(CitrusSettings.OUTBOUND_XML_SCHEMA_VALIDATION_ENABLED_PROPERTY) - || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_ENV)) - || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_XML_SCHEMA_VALIDATION_ENABLED_ENV)); - } /** * {@inheritDoc} @@ -249,12 +200,13 @@ public boolean isDisabled(TestContext context) { @Override public boolean isDone(TestContext context) { return Optional.ofNullable(finished) - .map(future -> future.isDone() || isDisabled(context)) - .orElseGet(() -> isDisabled(context)); + .map(future -> future.isDone() || isDisabled(context)) + .orElseGet(() -> isDisabled(context)); } /** * Create message to be sent. + * * @param context * @param messageType * @return @@ -264,7 +216,7 @@ protected Message createMessage(TestContext context, String messageType) { if (message.getPayload() != null) { context.getMessageProcessors(MessageDirection.OUTBOUND) - .forEach(processor -> processor.process(message, context)); + .forEach(processor -> processor.process(message, context)); if (dataDictionary != null) { dataDictionary.process(message, context); @@ -278,6 +230,7 @@ protected Message createMessage(TestContext context, String messageType) { /** * Creates or gets the message endpoint instance. + * * @return the message endpoint */ public Endpoint getOrCreateEndpoint(TestContext context) { @@ -292,6 +245,7 @@ public Endpoint getOrCreateEndpoint(TestContext context) { /** * Gets the message endpoint. + * * @return */ public Endpoint getEndpoint() { @@ -300,6 +254,7 @@ public Endpoint getEndpoint() { /** * Get + * * @return true if schema validation is active for this message */ public boolean isSchemaValidation() { @@ -308,6 +263,7 @@ public boolean isSchemaValidation() { /** * Get the name of the schema repository used for validation + * * @return the schema repository name */ public String getSchemaRepository() { @@ -316,6 +272,7 @@ public String getSchemaRepository() { /** * Get the name of the schema used for validation + * * @return the schema */ public String getSchema() { @@ -324,6 +281,7 @@ public String getSchema() { /** * Get the variable extractors. + * * @return the variableExtractors */ public List getVariableExtractors() { @@ -332,6 +290,7 @@ public List getVariableExtractors() { /** * Obtains the message processors. + * * @return */ public List getMessageProcessors() { @@ -340,6 +299,7 @@ public List getMessageProcessors() { /** * Gets the messageBuilder. + * * @return the messageBuilder */ public MessageBuilder getMessageBuilder() { @@ -348,6 +308,7 @@ public MessageBuilder getMessageBuilder() { /** * Gets the forkMode. + * * @return the forkMode the forkMode to get. */ public boolean isForkMode() { @@ -356,6 +317,7 @@ public boolean isForkMode() { /** * Gets the message type for this receive action. + * * @return the messageType */ public String getMessageType() { @@ -364,6 +326,7 @@ public String getMessageType() { /** * Gets the data dictionary. + * * @return */ public DataDictionary getDataDictionary() { @@ -372,6 +335,7 @@ public DataDictionary getDataDictionary() { /** * Gets the endpoint uri. + * * @return */ public String getEndpointUri() { @@ -381,10 +345,12 @@ public String getEndpointUri() { /** * Action builder. */ - public static class Builder extends SendMessageActionBuilder { + public static final class Builder extends + SendMessageActionBuilder { /** * Fluent API action building entry method used in Java DSL. + * * @return */ public static Builder send() { @@ -393,6 +359,7 @@ public static Builder send() { /** * Fluent API action building entry method used in Java DSL. + * * @param messageEndpoint * @return */ @@ -404,6 +371,7 @@ public static Builder send(Endpoint messageEndpoint) { /** * Fluent API action building entry method used in Java DSL. + * * @param messageEndpointUri * @return */ @@ -428,7 +396,8 @@ public SendMessageAction doBuild() { } - public static class SendMessageActionBuilderSupport extends SendMessageBuilderSupport { + public static class SendMessageActionBuilderSupport extends + SendMessageBuilderSupport { public SendMessageActionBuilderSupport(SendMessageAction.Builder delegate) { super(delegate); @@ -438,14 +407,15 @@ public SendMessageActionBuilderSupport(SendMessageAction.Builder delegate) { /** * Base send message action builder also used by subclasses of base send message action. */ - public static abstract class SendMessageActionBuilder, B extends SendMessageActionBuilder> - extends MessageBuilderSupport.MessageActionBuilder { + public abstract static class SendMessageActionBuilder, B extends SendMessageActionBuilder> + extends MessageBuilderSupport.MessageActionBuilder { protected boolean forkMode = false; protected CompletableFuture finished; /** * Sets the fork mode for this send action builder. + * * @param forkMode * @return */ @@ -463,7 +433,8 @@ public final T build() { if (referenceResolver != null) { if (messageBuilderSupport.getDataDictionaryName() != null) { this.messageBuilderSupport.dictionary( - referenceResolver.resolve(messageBuilderSupport.getDataDictionaryName(), DataDictionary.class)); + referenceResolver.resolve(messageBuilderSupport.getDataDictionaryName(), + DataDictionary.class)); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientRequestActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientRequestActionBuilder.java index cced421b22..479c6da50d 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientRequestActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientRequestActionBuilder.java @@ -17,7 +17,6 @@ package org.citrusframework.http.actions; import jakarta.servlet.http.Cookie; - import org.citrusframework.actions.SendMessageAction; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; @@ -57,11 +56,15 @@ protected HttpClientRequestActionBuilder(MessageBuilder messageBuilder, HttpMess @Override public HttpMessageBuilderSupport getMessageBuilderSupport() { if (messageBuilderSupport == null) { - messageBuilderSupport = new HttpMessageBuilderSupport(httpMessage, this); + messageBuilderSupport = createHttpMessageBuilderSupport(); } return super.getMessageBuilderSupport(); } + protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { + return new HttpMessageBuilderSupport(httpMessage, this); + } + /** * Sets the request path. * @param path diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java index 292caf3016..3929df439c 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java @@ -17,6 +17,7 @@ package org.citrusframework.http.actions; import jakarta.servlet.http.Cookie; +import java.util.Optional; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; @@ -26,8 +27,6 @@ import org.citrusframework.message.builder.ReceiveMessageBuilderSupport; import org.springframework.http.HttpStatusCode; -import java.util.Optional; - /** * @since 2.4 */ @@ -59,11 +58,15 @@ public HttpClientResponseActionBuilder(MessageBuilder messageBuilder, HttpMessag @Override public HttpMessageBuilderSupport getMessageBuilderSupport() { if (messageBuilderSupport == null) { - messageBuilderSupport = new HttpMessageBuilderSupport(httpMessage, this); + messageBuilderSupport = createHttpMessageBuilderSupport(); } return super.getMessageBuilderSupport(); } + protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { + return new HttpMessageBuilderSupport(httpMessage, this); + } + public static class HttpMessageBuilderSupport extends ReceiveMessageBuilderSupport { private final HttpMessage httpMessage; diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerRequestActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerRequestActionBuilder.java index 39f22cc090..148af48b6a 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerRequestActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerRequestActionBuilder.java @@ -16,9 +16,8 @@ package org.citrusframework.http.actions; -import java.util.Optional; - import jakarta.servlet.http.Cookie; +import java.util.Optional; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; @@ -61,11 +60,15 @@ public HttpServerRequestActionBuilder(MessageBuilder messageBuilder, HttpMessage @Override public HttpMessageBuilderSupport getMessageBuilderSupport() { if (messageBuilderSupport == null) { - messageBuilderSupport = new HttpMessageBuilderSupport(httpMessage, this); + messageBuilderSupport = createMessageBuilderSupport(); } return super.getMessageBuilderSupport(); } + protected HttpMessageBuilderSupport createMessageBuilderSupport() { + return new HttpMessageBuilderSupport(httpMessage, this); + } + /** * Sets the request path. * @param path diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java index e0610ce5d0..8a0ed55d59 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java @@ -57,11 +57,15 @@ public HttpServerResponseActionBuilder(MessageBuilder messageBuilder, HttpMessag @Override public HttpMessageBuilderSupport getMessageBuilderSupport() { if (messageBuilderSupport == null) { - messageBuilderSupport = new HttpMessageBuilderSupport(httpMessage, this); + messageBuilderSupport = createMessageBuilderSupport(); } return super.getMessageBuilderSupport(); } + protected HttpMessageBuilderSupport createMessageBuilderSupport() { + return new HttpMessageBuilderSupport(httpMessage, this); + } + public static class HttpMessageBuilderSupport extends SendMessageBuilderSupport { private final HttpMessage httpMessage; diff --git a/pom.xml b/pom.xml index 736501e357..9eb6b5f59b 100644 --- a/pom.xml +++ b/pom.xml @@ -195,7 +195,7 @@ 1.10.15 4.9.0 1.1.27 - com.atlassian.oai + 2.41.0 1.8.0 3.27.2 4.2.2 diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index b33d0f717e..c3776c4931 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -38,6 +38,7 @@ ${junit.jupiter.version} test + diff --git a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java index 8cdfc89673..f2e8eaeed5 100644 --- a/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java +++ b/validation/citrus-validation-json/src/main/java/org/citrusframework/validation/json/schema/JsonSchemaValidation.java @@ -16,11 +16,10 @@ package org.citrusframework.validation.json.schema; -import static java.util.Collections.emptySet; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.networknt.schema.ValidationMessage; +import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -31,6 +30,7 @@ import org.citrusframework.util.IsJsonPredicate; import org.citrusframework.validation.SchemaValidator; import org.citrusframework.validation.json.JsonMessageValidationContext; +import org.citrusframework.validation.json.JsonMessageValidationContext.Builder; import org.citrusframework.validation.json.report.GraciousProcessingReport; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,6 +40,8 @@ import java.util.List; import java.util.Set; +import static java.util.Collections.emptySet; + /** * This class is responsible for the validation of json messages against json schemas / json schema repositories. * @@ -71,7 +73,10 @@ public void validate(Message message, TestContext context, JsonMessageValidation context.getReferenceResolver()); if (!report.isSuccess()) { - logger.error("Failed to validate Json schema for message:\n{}", message.getPayload(String.class)); + if (logger.isErrorEnabled()) { + logger.error("Failed to validate Json schema for message:\n{}", + message.getPayload(String.class)); + } throw new ValidationException(constructErrorMessage(report)); } @@ -167,4 +172,31 @@ public boolean supportsMessageType(String messageType, Message message) { return "JSON".equals(messageType) || (message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class))); } + + @Override + public boolean canValidate(Message message, boolean schemaValidationEnabled) { + return (isJsonSchemaValidationEnabled() || schemaValidationEnabled) + && IsJsonPredicate.getInstance().test(message.getPayload(String.class)); + } + + /** + * Get setting to determine if json schema validation is enabled by default. + * @return + */ + private static boolean isJsonSchemaValidationEnabled() { + return Boolean.getBoolean(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_PROPERTY) + || Boolean.getBoolean(CitrusSettings.OUTBOUND_JSON_SCHEMA_VALIDATION_ENABLED_PROPERTY) + || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_ENV)) + || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_JSON_SCHEMA_VALIDATION_ENABLED_ENV)); + } + + @Override + public void validate(Message message, TestContext context, String schemaRepository, String schema) { + + JsonMessageValidationContext validationContext = Builder.json() + .schemaValidation(true) + .schema(schema) + .schemaRepository(schemaRepository).build(); + validate(message, context, validationContext); + } } diff --git a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/SendMessageActionTest.java b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/SendMessageActionTest.java index c4850d40c1..4183e3e2d2 100644 --- a/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/SendMessageActionTest.java +++ b/validation/citrus-validation-json/src/test/java/org/citrusframework/validation/json/SendMessageActionTest.java @@ -16,10 +16,6 @@ package org.citrusframework.validation.json; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; - import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; @@ -30,6 +26,7 @@ import org.citrusframework.message.MessageType; import org.citrusframework.message.builder.DefaultPayloadBuilder; import org.citrusframework.messaging.Producer; +import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.testng.AbstractTestNGUnitTest; import org.citrusframework.validation.DefaultMessageHeaderValidator; import org.citrusframework.validation.MessageValidatorRegistry; @@ -40,11 +37,18 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; public class SendMessageActionTest extends AbstractTestNGUnitTest { @@ -64,16 +68,18 @@ protected TestContextFactory createTestContextFactory() { @SuppressWarnings("rawtypes") public void testSendMessageOverwriteMessageElementsJsonPath() { DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder(); - messageBuilder.setPayloadBuilder(new DefaultPayloadBuilder("{ \"TestRequest\": { \"Message\": \"?\" }}")); + messageBuilder.setPayloadBuilder( + new DefaultPayloadBuilder("{ \"TestRequest\": { \"Message\": \"?\" }}")); Map overwriteElements = new HashMap<>(); overwriteElements.put("$.TestRequest.Message", "Hello World!"); JsonPathMessageProcessor processor = new JsonPathMessageProcessor.Builder() - .expressions(overwriteElements) - .build(); + .expressions(overwriteElements) + .build(); - final Message controlMessage = new DefaultMessage("{\"TestRequest\":{\"Message\":\"Hello World!\"}}"); + final Message controlMessage = new DefaultMessage( + "{\"TestRequest\":{\"Message\":\"Hello World!\"}}"); reset(endpoint, producer, endpointConfiguration); when(endpoint.createProducer()).thenReturn(producer); @@ -87,11 +93,11 @@ public void testSendMessageOverwriteMessageElementsJsonPath() { when(endpoint.getActor()).thenReturn(null); SendMessageAction sendAction = new SendMessageAction.Builder() - .endpoint(endpoint) - .message(messageBuilder) - .type(MessageType.JSON) - .process(processor) - .build(); + .endpoint(endpoint) + .message(messageBuilder) + .type(MessageType.JSON) + .process(processor) + .build(); sendAction.execute(context); } @@ -99,24 +105,32 @@ public void testSendMessageOverwriteMessageElementsJsonPath() { @Test public void testSendJsonMessageWithValidation() { - AtomicBoolean validated = new AtomicBoolean(false); + AtomicBoolean validated = new AtomicBoolean(false); SchemaValidator schemaValidator = mock(SchemaValidator.class); when(schemaValidator.supportsMessageType(eq("JSON"), any())).thenReturn(true); - doAnswer(invocation-> { - JsonMessageValidationContext argument = invocation.getArgument(2, JsonMessageValidationContext.class); + doAnswer(invocation -> { - Assert.assertEquals(argument.getSchema(), "fooSchema"); - Assert.assertEquals(argument.getSchemaRepository(), "fooRepository"); + Assert.assertEquals(invocation.getArgument(3, String.class), "fooSchema"); + Assert.assertEquals(invocation.getArgument(2, String.class), "fooRepository"); validated.set(true); return null; - }).when(schemaValidator).validate(any(), any(), any()); + }).when(schemaValidator) + .validate(isA(Message.class), isA(TestContext.class), isA(String.class), + isA(String.class)); + doReturn(true).when(schemaValidator).canValidate(isA(Message.class), isA(Boolean.class)); + + ReferenceResolver referenceResolverSpy = spy(context.getReferenceResolver()); + context.setReferenceResolver(referenceResolverSpy); + + doReturn(Map.of("jsonSchemaValidator", schemaValidator)).when(referenceResolverSpy).resolveAll(SchemaValidator.class); context.getMessageValidatorRegistry().addSchemaValidator("JSON", schemaValidator); DefaultMessageBuilder messageBuilder = new DefaultMessageBuilder(); - messageBuilder.setPayloadBuilder(new DefaultPayloadBuilder("{ \"TestRequest\": { \"Message\": \"?\" }}")); + messageBuilder.setPayloadBuilder( + new DefaultPayloadBuilder("{ \"TestRequest\": { \"Message\": \"?\" }}")); reset(endpoint, producer, endpointConfiguration); when(endpoint.createProducer()).thenReturn(producer); @@ -125,20 +139,21 @@ public void testSendJsonMessageWithValidation() { when(endpoint.getActor()).thenReturn(null); SendMessageAction sendAction = new SendMessageAction.Builder() - .endpoint(endpoint) - .message(messageBuilder) - .schemaValidation(true) - .schema("fooSchema") - .schemaRepository("fooRepository") - .type(MessageType.JSON) - .build(); + .endpoint(endpoint) + .message(messageBuilder) + .schemaValidation(true) + .schema("fooSchema") + .schemaRepository("fooRepository") + .type(MessageType.JSON) + .build(); sendAction.execute(context); Assert.assertTrue(validated.get()); } private void validateMessageToSend(Message toSend, Message controlMessage) { - Assert.assertEquals(toSend.getPayload(String.class).trim(), controlMessage.getPayload(String.class).trim()); + Assert.assertEquals(toSend.getPayload(String.class).trim(), + controlMessage.getPayload(String.class).trim()); DefaultMessageHeaderValidator validator = new DefaultMessageHeaderValidator(); validator.validateMessage(toSend, controlMessage, context, new HeaderValidationContext()); } diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java index 75d9a67bc4..6423365b1a 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java @@ -16,6 +16,19 @@ package org.citrusframework.validation.xml.schema; +import static java.lang.String.format; +import static org.citrusframework.validation.xml.schema.ValidationStrategy.FAIL; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.citrusframework.CitrusSettings; import org.citrusframework.XmlValidationHelper; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -29,6 +42,7 @@ import org.citrusframework.util.XMLUtils; import org.citrusframework.validation.SchemaValidator; import org.citrusframework.validation.xml.XmlMessageValidationContext; +import org.citrusframework.validation.xml.XmlMessageValidationContext.Builder; import org.citrusframework.xml.XsdSchemaRepository; import org.citrusframework.xml.schema.AbstractSchemaCollection; import org.citrusframework.xml.schema.WsdlXsdSchema; @@ -41,19 +55,6 @@ import org.w3c.dom.Document; import org.xml.sax.SAXParseException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static java.lang.String.format; -import static org.citrusframework.validation.xml.schema.ValidationStrategy.FAIL; - public class XmlSchemaValidation implements SchemaValidator { public static final String NO_SCHEMA_FOUND_STRATEGY_PROPERTY_NAME = "citrus.xml.no.schema.found.strategy"; @@ -222,4 +223,31 @@ private static Optional extractEnvOrProperty(SystemProvider systemProvid return systemProvider.getEnv(envVarName) .or(() -> systemProvider.getProperty(fallbackPropertyName)); } + + @Override + public boolean canValidate(Message message, boolean schemaValidationEnabled) { + return (isXmlSchemaValidationEnabled() || schemaValidationEnabled) + && IsXmlPredicate.getInstance().test(message.getPayload(String.class)); + } + + /** + * Get setting to determine if xml schema validation is enabled by default. + * @return + */ + private static boolean isXmlSchemaValidationEnabled() { + return Boolean.getBoolean(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_PROPERTY) + || Boolean.getBoolean(CitrusSettings.OUTBOUND_XML_SCHEMA_VALIDATION_ENABLED_PROPERTY) + || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_ENV)) + || Boolean.parseBoolean(System.getenv(CitrusSettings.OUTBOUND_XML_SCHEMA_VALIDATION_ENABLED_ENV)); + } + + @Override + public void validate(Message message, TestContext context, String schemaRepository, String schema) { + + XmlMessageValidationContext validationContext = Builder.xml() + .schemaValidation(true) + .schema(schema) + .schemaRepository(schemaRepository).build(); + validate(message, context, validationContext); + } } diff --git a/validation/citrus-validation-xml/src/test/java/org/citrusframework/validation/xml/SendMessageActionTest.java b/validation/citrus-validation-xml/src/test/java/org/citrusframework/validation/xml/SendMessageActionTest.java index a5da64c31b..871c37301c 100644 --- a/validation/citrus-validation-xml/src/test/java/org/citrusframework/validation/xml/SendMessageActionTest.java +++ b/validation/citrus-validation-xml/src/test/java/org/citrusframework/validation/xml/SendMessageActionTest.java @@ -234,15 +234,14 @@ public void testSendXmlMessageWithValidation() { when(schemaValidator.supportsMessageType(eq("XML"), any())).thenReturn(true); doAnswer(invocation-> { - Object argument = invocation.getArgument(2); - - Assert.assertTrue(argument instanceof XmlMessageValidationContext); - Assert.assertEquals(((XmlMessageValidationContext)argument).getSchema(), "fooSchema"); - Assert.assertEquals(((XmlMessageValidationContext)argument).getSchemaRepository(), "fooRepository"); + Assert.assertEquals(invocation.getArgument(3, String.class), "fooSchema"); + Assert.assertEquals(invocation.getArgument(2, String.class), "fooRepository"); validated.set(true); return null; - }).when(schemaValidator).validate(any(), any(), any()); + }).when(schemaValidator) + .validate(isA(Message.class), isA(TestContext.class), isA(String.class), isA(String.class)); + doReturn(true).when(schemaValidator).canValidate(isA(Message.class), isA(Boolean.class)); context.getMessageValidatorRegistry().addSchemaValidator("XML", schemaValidator); From df206719532705d9f3f94a3d084cf951a2364670 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Sun, 29 Sep 2024 14:54:06 +0200 Subject: [PATCH 17/47] feat: improve open api generator - support java dsl - streamline implementation with standard citrus builder pattern - support open api parameter serialization --- catalog/citrus-bom/pom.xml | 15 + connectors/citrus-openapi/README.md | 6 + .../openapi/OpenApiPathRegistry.java | 191 - .../openapi/OpenApiResourceLoader.java | 33 +- .../openapi/OpenApiSpecification.java | 46 +- .../OpenApiClientRequestActionBuilder.java | 138 +- .../OpenApiClientResponseActionBuilder.java | 118 +- .../actions/OpenApiPayloadBuilder.java | 56 + .../OpenApiServerRequestActionBuilder.java | 84 +- .../OpenApiServerResponseActionBuilder.java | 20 +- .../openapi/model/OperationPathAdapter.java | 8 +- .../openapi/util/OpenApiUtils.java | 25 +- .../OpenApiMessageValidationContext.java | 5 +- .../OpenApiRequestValidationProcessor.java | 60 - .../validation/OpenApiRequestValidator.java | 46 +- .../validation/OpenApiResponseValidator.java | 5 +- .../validation/OpenApiSchemaValidation.java | 51 +- ...ext.java => OpenApiValidationContext.java} | 9 +- ...va => OpenApiValidationContextLoader.java} | 32 +- .../openapi/validation/OpenApiValidator.java | 16 +- .../openapi/OpenApiMessageTypeTest.java | 2 +- .../openapi/OpenApiPathRegistryTest.java | 172 - .../openapi/OpenApiSpecificationTest.java | 14 +- .../openapi/OpenApiTestDataGeneratorTest.java | 4 +- ...penApiTestValidationDataGeneratorTest.java | 86 + .../openapi/OpenApiUtilsTest.java | 59 +- .../OpenApiClientActionBuilderTest.java | 12 +- .../actions/OpenApiPayloadBuilderTest.java | 65 + .../OpenApiServerActionBuilderTest.java | 9 +- .../openapi/groovy/OpenApiClientTest.java | 4 +- .../openapi/groovy/OpenApiServerTest.java | 7 +- .../openapi/integration/OpenApiClientIT.java | 86 +- .../openapi/integration/OpenApiServerIT.java | 118 +- .../random/RandomCompositeGeneratorTest.java | 10 +- ...OpenApiRequestValidationProcessorTest.java | 123 - .../OpenApiRequestValidatorTest.java | 51 +- .../OpenApiResponseValidatorTest.java | 20 +- .../openapi/xml/OpenApiClientTest.java | 2 - .../openapi/xml/OpenApiServerTest.java | 7 +- .../openapi/yaml/OpenApiClientTest.java | 4 +- .../openapi/yaml/OpenApiServerTest.java | 7 +- .../org/citrusframework/CitrusSettings.java | 2 +- .../util/ReflectionHelper.java | 32 + .../util/ReflectionHelperTest.java | 47 + .../actions/ReceiveMessageAction.java | 2 +- .../actions/SendMessageAction.java | 1 + .../org/citrusframework/util/StringUtils.java | 37 + .../validation/DefaultHeaderValidator.java | 106 +- .../endpoint/AbstractEndpointBuilderTest.java | 23 +- .../DirectEndpointConfigParserTest.java | 4 +- .../citrusframework/util/StringUtilsTest.java | 131 + .../xml/ReceiveMessageActionParser.java | 24 +- .../config/xml/SendMessageActionParser.java | 33 +- .../client/HttpEndpointConfiguration.java | 29 +- .../xml/HttpReceiveResponseActionParser.java | 38 +- .../xml/HttpSendRequestActionParser.java | 55 +- .../controller/HttpMessageController.java | 1 + .../HttpQueryParamHeaderValidator.java | 55 +- .../server/AbstractHttpServerBuilder.java | 11 + .../http/server/HttpServer.java | 24 + .../http/servlet/CitrusDispatcherServlet.java | 1 + .../schema/citrus-http-testcase.xsd | 546 +-- .../HttpQueryParamHeaderValidatorTest.java | 11 +- .../SyncJmsTopicCommunicationIT.java | 1 + .../rmi/integration/RmiDynamicEndpointIT.java | 2 +- .../rmi/integration/RmiEndpointIT.java | 1 + .../rmi/integration/RmiEndpointJavaIT.java | 1 + .../rmi/server/RmiServerTest.java | 11 +- .../ws/actions/ReceiveSoapMessageAction.java | 2 +- .../ws/actions/SendSoapMessageAction.java | 2 +- .../xml/ReceiveSoapMessageActionParser.java | 18 +- .../config/xml/SendSoapFaultActionParser.java | 2 +- .../xml/SendSoapMessageActionParser.java | 13 +- pom.xml | 1 + .../citrus-test-api-core/pom.xml | 81 + .../testapi/ApiActionBuilderCustomizer.java | 15 +- .../openapi}/testapi/GeneratedApi.java | 13 +- .../openapi}/testapi/GeneratedApiRequest.java | 2 +- .../testapi/OpenApiParameterFormatter.java | 226 + .../openapi/testapi/ParameterStyle.java | 25 + .../RestApiReceiveMessageActionBuilder.java | 72 + .../RestApiSendMessageActionBuilder.java | 332 ++ .../SoapApiReceiveMessageActionBuilder.java | 54 + .../SoapApiSendMessageActionBuilder.java | 49 + .../openapi/testapi/TestApiUtils.java | 51 + .../OpenApiParameterFormatterTest.java | 73 + .../openapi/testapi/TestApiUtilsTest.java | 68 + .../citrus-test-api-generator-core/README.md | 102 + .../citrus-test-api-generator-core/pom.xml | 76 +- .../openapi/generator/CitrusJavaCodegen.java | 595 +++ .../openapi/generator/JavaCitrusCodegen.java | 294 -- .../TestApiClientRequestActionBuilder.java | 69 - ...mer.java => WsdlToOpenApiTransformer.java} | 98 +- .../org.openapitools.codegen.CodegenConfig | 2 +- .../resources/java-citrus/api-model.mustache | 2 - .../main/resources/java-citrus/api.mustache | 605 ++- .../java-citrus/api_locator.mustache | 28 + .../resources/java-citrus/api_old.mustache | 259 -- .../resources/java-citrus/api_soap.mustache | 224 +- .../java-citrus/bean_configuration.mustache | 53 +- .../bean_definition_parser.mustache | 205 - .../java-citrus/namespace_handler.mustache | 68 +- .../namespace_handler_soap.mustache | 78 + .../resources/java-citrus/openApi.mustache | 83 - .../resources/java-citrus/schema.mustache | 397 +- .../java-citrus/schema_soap.mustache | 175 +- .../resources/java-citrus/test_base.mustache | 239 - .../java-citrus/test_base_soap.mustache | 182 - .../generator/CitrusJavaCodegenTest.java | 177 + ...sCodegenIT.java => ExpectedCodeGenIT.java} | 44 +- .../openapi/generator/GeneratedApiIT.java | 628 --- .../openapi/generator/GeneratedRestApiIT.java | 3510 ++++++++++++++ .../openapi/generator/GeneratedSoapApiIT.java | 117 + .../GeneratedSpringBeanConfigurationIT.java | 73 + .../openapi/generator/GetPetByIdIT.java | 404 -- .../generator/JavaCitrusCodegenTest.java | 219 - .../generator/OpenApiPetStoreTest.java | 181 - .../openapi/generator/ServiceLoaderTest.java | 24 - .../generator/SpringBeanConfigurationIT.java | 55 - ...java => WsdlToOpenApiTransformerTest.java} | 4 +- .../generator/sample/OpenApiPetStore.java | 306 -- .../generator/sample/OpenApiPetStore_.java | 304 -- .../openapi/generator/sample/PetApi.java | 273 -- .../PetStoreAbstractReceiveActionBuilder.java | 250 - .../PetStoreAbstractSendActionBuilder.java | 234 - .../generator/util/MultipartConverter.java | 76 + .../util/TestApiActionBuilderCustomizer.java | 21 - ....testapi.ApiActionBuilderCustomizerService | 1 - .../test/resources/META-INF/spring.handlers | 6 +- .../test/resources/META-INF/spring.schemas | 5 +- .../resources/apis/BookService-generated.yaml | 43 + .../apis/multiparttest-rest-resource.yaml | 249 - .../resources/apis/petstore-extended-v3.yaml | 1230 +++++ .../src/test/resources/apis/petstore-v3.yaml | 803 ++++ .../src/test/resources/apis/petstore.yaml | 700 --- .../apis/petstore_reservedWords.yaml | 120 - .../rest/extpetstore/ExtPetStore.java | 11 + .../rest/extpetstore/model/Category.java | 119 + .../extpetstore/model/HistoricalData.java | 120 + .../rest/extpetstore/model/Pet.java | 279 ++ .../rest/extpetstore/model/Tag.java | 119 + .../model/VaccinationDocumentResult.java | 93 + .../rest/extpetstore/request/ExtPetApi.java | 4081 +++++++++++++++++ .../spring/ExtPetStoreBeanConfiguration.java | 33 + .../spring/ExtPetStoreNamespaceHandler.java | 242 + .../expectedgen/rest/petstore/PetStore.java | 11 + .../rest/petstore/model/Address.java | 171 + .../rest/petstore/model/Category.java | 4 +- .../rest/petstore/model/Customer.java | 157 + .../rest/petstore/model/ModelApiResponse.java | 46 +- .../rest/petstore/model/Order.java | 6 +- .../expectedgen/rest/petstore/model/Pet.java | 50 +- .../expectedgen/rest/petstore/model/Tag.java | 4 +- .../expectedgen/rest/petstore/model/User.java | 4 +- .../rest/petstore/request/PetApi.java | 914 ++++ .../rest/petstore/request/StoreApi.java | 497 ++ .../rest/petstore/request/UserApi.java | 714 +++ .../spring/PetStoreBeanConfiguration.java | 45 + .../spring/PetStoreNamespaceHandler.java | 160 + .../request/BookServiceSoapApi.java | 209 + .../defaultOas3SchemaValidationTest.xml | 25 - .../failOnReasonPhraseTest.xml | 25 - .../GeneratedApiTest/failOnStatusTest.xml | 25 - .../GeneratedApiTest/failOnVersionTest.xml | 25 - .../getPetByIdRequestTest.xml | 24 - .../jsonDeactivatedSchemaValidationTest.xml | 26 - .../GeneratedApiTest/jsonPathExtractTest.xml | 25 - .../jsonPathExtractionTest.xml | 25 - .../jsonPathValidationFailureTest.xml | 25 - .../jsonPathValidationTest.xml | 25 - .../jsonSchemaValidationFailureTest.xml | 25 - .../jsonSchemaValidationTest.xml | 25 - .../multipartWithFileAttributesTest.xml | 22 - .../multipartWithMultipleDatatypesTest.xml | 24 - .../multipartWithPlainTextTest.xml | 32 - .../payloads/findPetsByStatus_response.json | 38 + .../payloads/getPetById_response.json | 18 + .../getPetById_response_validation.json | 18 + .../payloads/invalidGetPetById_response.json | 14 + .../GeneratedApiTest/payloads/pet.json | 16 + .../payloads/thisAintNoPed.json | 1 + .../payloads/vaccinationAdditionalData.json | 1 + .../payloads/vaccinationReport.pdf | Bin 0 -> 93378 bytes .../payloads/vaccinationTemplate.bin | 1 + .../GeneratedApiTest/postFileTest.xml | 22 - .../GeneratedApiTest/scriptValidationTest.xml | 25 - .../sendWithBodyLiteralTest.xml | 20 - .../sendWithBodyLiteralWithVariableTest.xml | 23 - .../GeneratedApiTest/sendWithBodyTest.xml | 20 - .../sendWithExtraHeaderTest.xml | 22 - .../GeneratedApiTest/withActorTest.xml | 34 + .../GeneratedApiTest/withApiCookieTest.xml | 49 + .../withApiKeysFromPropertiesTest.xml | 55 + .../withApiKeysOverridingPropertiesTest.xml | 63 + .../withArrayQueryDataTest.xml | 72 + ...hBasicAuthenticationFromPropertiesTest.xml | 76 + ...AuthenticationOverridingPropertiesTest.xml | 51 + ...BearerAuthenticationFromPropertiesTest.xml | 50 + ...AuthenticationOverridingPropertiesTest.xml | 56 + .../withBodyAsPlainTextTest.xml | 69 + .../withBodyFromResourceTest.xml | 48 + .../withFailOnBodyDataValidationTest.xml | 48 + .../withFailOnBodyResourceValidationTest.xml | 46 + .../withFailOnInvalidResponseTest.xml | 42 + .../withFailOnJsonPathInvalidTest.xml | 51 + .../withFailOnReasonPhraseTest.xml | 45 + .../GeneratedApiTest/withFailOnStatusTest.xml | 44 + .../withFailOnVersionTest.xml | 44 + .../GeneratedApiTest/withFileUploadTest.xml | 64 + .../GeneratedApiTest/withFormDataTest.xml | 40 + .../withFormUrlEncodedTest.xml | 66 + .../withJsonPathExtractionTest.xml | 57 + .../withJsonPathValidationTest.xml | 46 + .../GeneratedApiTest/withMultipartTest.xml | 76 + .../withNestedReceiveInXmlTest.xml | 41 + .../withNonApiQueryParamTest.xml | 58 + .../withReceiveBodyFromPlainTextTest.xml | 68 + .../withReceiveBodyFromResourceTest.xml | 48 + .../withReceiveNonApiCookieTest.xml | 45 + .../withResponseValidationDisabledTest.xml | 40 + .../GeneratedApiTest/withSoapTest.xml | 75 + .../withSpecificEndpointTest.xml | 46 + .../GeneratedApiTest/withSpecificUriTest.xml | 46 + .../MultipartTestAbstractTestRequest.java | 253 - .../MultipartTestBeanDefinitionParser.java | 219 - .../MultipartTestNamespaceHandler.java | 36 - .../rest/multiparttest/model/Metadata.java | 294 -- .../multiparttest/model/PutObjectResult.java | 251 - .../request/MultiparttestControllerApi.java | 758 --- .../MultipartTestBeanConfiguration.java | 65 - .../citrus/PetStoreAbstractTestRequest.java | 253 - .../citrus/PetStoreBeanDefinitionParser.java | 219 - .../extension/PetStoreNamespaceHandler.java | 52 - .../rest/petstore/request/PetApi.java | 870 ---- .../rest/petstore/request/StoreApi.java | 441 -- .../rest/petstore/request/UserApi.java | 827 ---- .../spring/PetStoreBeanConfiguration.java | 151 - .../OpenApiFromWsdlAbstractTestRequest.java | 196 - .../OpenApiFromWsdlBeanDefinitionParser.java | 219 - .../OpenApiFromWsdlNamespaceHandler.java | 33 - .../request/BookServiceSoapApi.java | 339 -- .../OpenApiFromWsdlBeanConfiguration.java | 47 - .../BookDatatypes.xsd | 4 +- .../BookService-generated.yaml | 18 +- .../BookService.wsdl | 6 +- .../pom.xml | 2 +- .../maven/plugin/CodeGenMojoWrapper.java | 10 +- .../maven/plugin/TestApiGeneratorMojo.java | 8 +- .../TestApiGeneratorMojoIntegrationTest.java | 25 +- .../citrus-test-api-spring/pom.xml | 37 + .../RestApiReceiveMessageActionParser.java | 194 + .../RestApiSendMessageActionParser.java | 350 ++ .../SoapApiReceiveMessageActionParser.java | 96 + .../SoapApiSendMessageActionParser.java | 147 + test-api-generator/pom.xml | 4 +- 255 files changed, 21711 insertions(+), 13223 deletions(-) create mode 100644 connectors/citrus-openapi/README.md delete mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java delete mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/{SwaggerOpenApiValidationContext.java => OpenApiValidationContext.java} (86%) rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/{SwaggerOpenApiValidationContextLoader.java => OpenApiValidationContextLoader.java} (67%) delete mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java delete mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java create mode 100644 core/citrus-api/src/test/java/org/citrusframework/util/ReflectionHelperTest.java create mode 100644 test-api-generator/citrus-test-api-core/pom.xml rename core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java => test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java (65%) rename {core/citrus-api/src/main/java/org/citrusframework => test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi}/testapi/GeneratedApi.java (88%) rename {core/citrus-api/src/main/java/org/citrusframework => test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi}/testapi/GeneratedApiRequest.java (96%) create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java create mode 100644 test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java create mode 100644 test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java create mode 100644 test-api-generator/citrus-test-api-generator-core/README.md create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java rename test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/{SimpleWsdlToOpenApiTransformer.java => WsdlToOpenApiTransformer.java} (60%) delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java rename test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT.java => ExpectedCodeGenIT.java} (80%) delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java rename test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/{SimpleWsdlToOpenApiTransformerTest.java => WsdlToOpenApiTransformerTest.java} (87%) delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/BookService-generated.yaml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/Category.java (94%) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/ModelApiResponse.java (71%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/Order.java (96%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/Pet.java (96%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/Tag.java (94%) rename test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/{JavaCitrusCodegenIT => ExpectedCodeGenIT}/expectedgen/rest/petstore/model/User.java (96%) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/findPetsByStatus_response.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/pet.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withActorTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiCookieTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysFromPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysOverridingPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withArrayQueryDataTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationFromPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationOverridingPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationFromPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationOverridingPropertiesTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyAsPlainTextTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyFromResourceTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyDataValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyResourceValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnInvalidResponseTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnJsonPathInvalidTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnReasonPhraseTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnStatusTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnVersionTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFileUploadTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormDataTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathExtractionTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathValidationTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveInXmlTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNonApiQueryParamTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromPlainTextTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromResourceTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveNonApiCookieTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withResponseValidationDisabledTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSoapTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificEndpointTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificUriTest.xml delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java delete mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-spring/pom.xml create mode 100644 test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java create mode 100644 test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java create mode 100644 test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java create mode 100644 test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java diff --git a/catalog/citrus-bom/pom.xml b/catalog/citrus-bom/pom.xml index 16c218700d..050c95bd33 100644 --- a/catalog/citrus-bom/pom.xml +++ b/catalog/citrus-bom/pom.xml @@ -238,6 +238,21 @@ citrus-openapi 4.6.0-SNAPSHOT + + org.citrusframework + citrus-test-api-core + 4.4.0-SNAPSHOT + + + org.citrusframework + citrus-test-api-generator-core + 4.4.0-SNAPSHOT + + + org.citrusframework + citrus-test-api-spring + 4.4.0-SNAPSHOT + org.citrusframework citrus-jms diff --git a/connectors/citrus-openapi/README.md b/connectors/citrus-openapi/README.md new file mode 100644 index 0000000000..7669d15a9e --- /dev/null +++ b/connectors/citrus-openapi/README.md @@ -0,0 +1,6 @@ +// TODO +OpenApiServerRequest +- SchemaValidation is active by default (also in other scenarios) + +Oas Validation now by ValidationFramework +- no control response message is created any more \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java deleted file mode 100644 index 6218baaceb..0000000000 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiPathRegistry.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi; - -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; - -import static java.lang.String.format; - -/** - * A registry to store objects by OpenApi paths. The registry uses a digital tree data structure - * that performs path matching with variable placeholders. Variable - * placeholders must be enclosed in curly braces '{}', e.g., '/api/v1/pet/{id}'. This data structure - * is optimized for matching paths efficiently, handling both static and dynamic segments. - *

    - * This class is currently not in use but may serve scenarios where a path needs to be mapped to an - * OasOperation without explicit knowledge of the API to which the path belongs. - * It could be utilized, for instance, in implementing an OAS message validator based on - * {@link org.citrusframework.validation.AbstractMessageValidator}. - */ -public class OpenApiPathRegistry { - - private static final Logger logger = LoggerFactory.getLogger(OpenApiPathRegistry.class); - - private final RegistryNode root = new RegistryNode(); - - private final Map allPaths = new ConcurrentHashMap<>(); - - public T search(String path) { - RegistryNode trieNode = internalSearch(path); - return trieNode != null ? trieNode.value : null; - } - - RegistryNode internalSearch(String path) { - String[] segments = path.split("/"); - return searchHelper(root, segments, 0); - } - - public boolean insert(String path, T value) { - return insertInternal(path, value) != null; - } - - RegistryNode insertInternal(String path, T value) { - - if (path == null || value == null) { - return null; - } - - String[] segments = path.split("/"); - RegistryNode node = root; - - if (!allPaths.isEmpty() && (isPathAlreadyContainedWithDifferentValue(path, value) - || isPathMatchedByOtherPath(path, value))) { - return null; - } - - allPaths.put(path, value); - StringBuilder builder = new StringBuilder(); - for (String segment : segments) { - if (builder.isEmpty() || builder.charAt(builder.length() - 1) != '/') { - builder.append("/"); - } - builder.append(segment); - - if (!node.children.containsKey(segment)) { - RegistryNode trieNode = new RegistryNode(); - trieNode.path = builder.toString(); - node.children.put(segment, trieNode); - } - node = node.children.get(segment); - } - - // Sanity check to disallow overwrite of existing values - if (node.value != null && !node.value.equals(value)) { - throw new CitrusRuntimeException(format( - "Illegal attempt to overwrite an existing node value. This is probably a bug. path=%s value=%s", - node.path, node.value)); - } - node.value = value; - - return node; - } - - /** - * Tests if the path is either matching an existing path or any existing path matches the given - * patch. - *

    - * For example '/a/b' does not match '/{a}/{b}', but '/{a}/{b}' matches '/a/b'. - */ - private boolean isPathMatchedByOtherPath(String path, T value) { - - // Does the given path match any existing - RegistryNode currentValue = internalSearch(path); - if (currentValue != null && !Objects.equals(path, currentValue.path)) { - logger.error( - "Attempt to insert an equivalent path potentially overwriting an existing value. Value for path is ignored: path={}, value={} currentValue={} ", - path, currentValue, value); - return true; - } - - // Does any existing match the path. - OpenApiPathRegistry tmpTrie = new OpenApiPathRegistry<>(); - tmpTrie.insert(path, value); - - List allMatching = allPaths.keySet().stream() - .filter(existingPath -> { - RegistryNode trieNode = tmpTrie.internalSearch(existingPath); - return trieNode != null && !existingPath.equals(trieNode.path); - }).map(existingPath -> "'" + existingPath + "'").toList(); - if (!allMatching.isEmpty() && logger.isErrorEnabled()) { - logger.error( - "Attempt to insert an equivalent path overwritten by existing paths. Value for path is ignored: path={}, value={} existingPaths=[{}]", - path, currentValue, String.join(",", allMatching)); - - } - - return !allMatching.isEmpty(); - } - - private boolean isPathAlreadyContainedWithDifferentValue(String path, T value) { - T currentValue = allPaths.get(path); - if (currentValue != null) { - if (value.equals(currentValue)) { - return false; - } - logger.error( - "Attempt to overwrite value for path is ignored: path={}, value={} currentValue={} ", - path, currentValue, value); - return true; - } - return false; - } - - private RegistryNode searchHelper(RegistryNode node, String[] segments, int index) { - if (node == null) { - return null; - } - if (index == segments.length) { - return node; - } - - String segment = segments[index]; - - // Exact match - if (node.children.containsKey(segment)) { - RegistryNode foundNode = searchHelper(node.children.get(segment), segments, index + 1); - if (foundNode != null && foundNode.value != null) { - return foundNode; - } - } - - // Variable match - for (String key : node.children.keySet()) { - if (key.startsWith("{") && key.endsWith("}")) { - RegistryNode foundNode = searchHelper(node.children.get(key), segments, index + 1); - if (foundNode != null && foundNode.value != null) { - return foundNode; - } - } - } - - return null; - } - - class RegistryNode { - Map children = new HashMap<>(); - String path; - T value = null; - } -} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java index df39c8a2f5..7f4e31efa3 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.apicurio.datamodels.Library; import io.apicurio.datamodels.openapi.models.OasDocument; +import java.io.InputStream; +import java.net.URLConnection; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.TrustAllStrategy; import org.apache.hc.core5.http.HttpHeaders; @@ -109,24 +111,31 @@ public static String rawFromWebResource(URL url) { } private static T fromWebResource(URL url, Resolver resolver) { - HttpURLConnection con = null; + URLConnection con = null; try { - con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod(HttpMethod.GET.name()); - con.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + con = url.openConnection(); + + if (con instanceof HttpURLConnection httpURLConnection) { + httpURLConnection.setRequestMethod(HttpMethod.GET.name()); + con.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + + int status = httpURLConnection.getResponseCode(); + if (status > 299) { + throw new IllegalStateException( + "Failed to retrieve Open API specification: " + url, + new IOException(FileUtils.readToString(httpURLConnection.getErrorStream()))); + } + } - int status = con.getResponseCode(); - if (status > 299) { - throw new IllegalStateException("Failed to retrieve Open API specification: " + url, - new IOException(FileUtils.readToString(con.getErrorStream()))); - } else { - return resolve(FileUtils.readToString(con.getInputStream()), resolver); + try (InputStream inputStream = con.getInputStream()) { + return resolve(FileUtils.readToString(inputStream), resolver); } + } catch (IOException e) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url, e); } finally { - if (con != null) { - con.disconnect(); + if (con instanceof HttpURLConnection httpURLConnection) { + httpURLConnection.disconnect(); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index b344e7d9cd..a31d84019f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -41,8 +41,8 @@ import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.util.OpenApiUtils; -import org.citrusframework.openapi.validation.SwaggerOpenApiValidationContext; -import org.citrusframework.openapi.validation.SwaggerOpenApiValidationContextLoader; +import org.citrusframework.openapi.validation.OpenApiValidationContext; +import org.citrusframework.openapi.validation.OpenApiValidationContextLoader; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; import org.citrusframework.util.StringUtils; @@ -95,7 +95,7 @@ public class OpenApiSpecification { private OasDocument openApiDoc; - private SwaggerOpenApiValidationContext swaggerOpenApiValidationContext; + private OpenApiValidationContext openApiValidationContext; private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); @@ -140,19 +140,19 @@ public static OpenApiSpecification from(String specUrl) { public static OpenApiSpecification from(URL specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); OasDocument openApiDoc; - SwaggerOpenApiValidationContext swaggerOpenApiValidationContext; + OpenApiValidationContext openApiValidationContext; if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); - swaggerOpenApiValidationContext = SwaggerOpenApiValidationContextLoader.fromSecuredWebResource(specUrl); + openApiValidationContext = OpenApiValidationContextLoader.fromSecuredWebResource(specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); - swaggerOpenApiValidationContext = SwaggerOpenApiValidationContextLoader.fromWebResource(specUrl); + openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl); } specification.setSpecUrl(specUrl.toString()); specification.initPathLookups(); specification.setOpenApiDoc(openApiDoc); - specification.setSwaggerOpenApiValidationContext(swaggerOpenApiValidationContext); + specification.setOpenApiValidationContext(openApiValidationContext); specification.setRequestUrl( String.format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", @@ -166,7 +166,7 @@ public static OpenApiSpecification from(Resource resource) { OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); specification.setOpenApiDoc(openApiDoc); - specification.setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromFile(resource)); + specification.setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource)); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) .orElse(Collections.singletonList(HTTP)) @@ -218,10 +218,10 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { initApiDoc( () -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); - setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromSecuredWebResource(specWebResource)); + setOpenApiValidationContext(OpenApiValidationContextLoader.fromSecuredWebResource(specWebResource)); } else { initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); - setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromWebResource(specWebResource)); + setOpenApiValidationContext(OpenApiValidationContextLoader.fromWebResource(specWebResource)); } if (requestUrl == null) { @@ -235,7 +235,7 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { Resource resource = Resources.create(resolvedSpecUrl); initApiDoc( () -> OpenApiResourceLoader.fromFile(resource)); - setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContextLoader.fromFile(resource)); + setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource)); if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -255,8 +255,8 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { return openApiDoc; } - public SwaggerOpenApiValidationContext getSwaggerOpenApiValidationContext() { - return swaggerOpenApiValidationContext; + public OpenApiValidationContext getOpenApiValidationContext() { + return openApiValidationContext; } @@ -274,10 +274,11 @@ void setOpenApiDoc(OasDocument openApiDoc) { initApiDoc(() -> openApiDoc); } - private void setSwaggerOpenApiValidationContext(SwaggerOpenApiValidationContext swaggerOpenApiValidationContext) { - this.swaggerOpenApiValidationContext = swaggerOpenApiValidationContext; - this.swaggerOpenApiValidationContext.setResponseValidationEnabled(apiResponseValidationEnabled); - this.swaggerOpenApiValidationContext.setRequestValidationEnabled(apiRequestValidationEnabled); + private void setOpenApiValidationContext( + OpenApiValidationContext openApiValidationContext) { + this.openApiValidationContext = openApiValidationContext; + this.openApiValidationContext.setResponseValidationEnabled(apiResponseValidationEnabled); + this.openApiValidationContext.setRequestValidationEnabled(apiRequestValidationEnabled); } private void initApiDoc(Supplier openApiDocSupplier) { @@ -323,8 +324,7 @@ private void storeOperationPathAdapter(OasOperation operation, String path) { String basePath = OasModelHelper.getBasePath(openApiDoc); String fullOperationPath = StringUtils.appendSegmentToUrlPath(basePath, path); - String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(fullOperationPath, - operation); + String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(operation, fullOperationPath); operationToUniqueId.put(operation, uniqueOperationId); OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, @@ -370,8 +370,8 @@ public boolean isApiRequestValidationEnabled() { public void setApiRequestValidationEnabled(boolean enabled) { this.apiRequestValidationEnabled = enabled; - if (this.swaggerOpenApiValidationContext != null) { - this.swaggerOpenApiValidationContext.setRequestValidationEnabled(enabled); + if (this.openApiValidationContext != null) { + this.openApiValidationContext.setRequestValidationEnabled(enabled); } } @@ -381,8 +381,8 @@ public boolean isApiResponseValidationEnabled() { public void setApiResponseValidationEnabled(boolean enabled) { this.apiResponseValidationEnabled = enabled; - if (this.swaggerOpenApiValidationContext != null) { - this.swaggerOpenApiValidationContext.setResponseValidationEnabled(enabled); + if (this.openApiValidationContext != null) { + this.openApiValidationContext.setResponseValidationEnabled(enabled); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index ee009fe5aa..3bd3e484cb 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -16,13 +16,15 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; import java.util.List; import java.util.Locale; import java.util.Optional; -import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; @@ -37,6 +39,7 @@ import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; @@ -51,7 +54,7 @@ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBu private final String operationId; - private boolean oasValidationEnabled = true; + private boolean schemaValidation = true; /** * Default constructor initializes http request message builder. @@ -64,9 +67,14 @@ public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, OpenApiSpecificationSource openApiSpec, String operationId) { - super(new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), - httpMessage); + this(openApiSpec, new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), + httpMessage, operationId); + } + public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, + OpenApiClientRequestMessageBuilder messageBuilder, HttpMessage message, + String operationId) { + super(messageBuilder, message); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; } @@ -75,8 +83,14 @@ public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, public SendMessageAction doBuild() { OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( referenceResolver); - if (oasValidationEnabled && !messageProcessors.contains( - openApiMessageProcessor)) { + + // Honor default enablement of schema validation + OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); + if (openApiValidationContext != null && schemaValidation) { + schemaValidation = openApiValidationContext.isRequestValidationEnabled(); + } + + if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { openApiMessageProcessor = new OpenApiMessageProcessor(openApiSpecification, operationId, OpenApiMessageType.REQUEST); process(openApiMessageProcessor); @@ -95,26 +109,23 @@ protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { return httpMessageBuilderSupport; } - public OpenApiClientRequestActionBuilder disableOasValidation(boolean disabled) { - oasValidationEnabled = !disabled; + public OpenApiClientRequestActionBuilder schemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; return this; } - private static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilder { + public static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilder { private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; - private final HttpMessage httpMessage; - public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecificationSource openApiSpec, String operationId) { super(httpMessage); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; - this.httpMessage = httpMessage; } @Override @@ -133,6 +144,14 @@ public Message build(TestContext context, String messageType) { return super.build(context, messageType); } + @Override + public Object buildMessagePayload(TestContext context, String messageType) { + if (getPayloadBuilder() == null) { + this.setPayloadBuilder(new OpenApiPayloadBuilder(getMessage().getPayload())); + } + return super.buildMessagePayload(context, messageType); + } + private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { OasOperation operation = operationPathAdapter.operation(); @@ -141,69 +160,88 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); if (operation.parameters != null) { - setSpecifiedHeaders(openApiSpecification, context, operation); - setSpecifiedQueryParameters(context, operation); + setMissingRequiredHeadersToRandomValues(openApiSpecification, context, operation); + setMissingRequiredQueryParametersToRandomValues(context, operation); } - if (httpMessage.getPayload() == null || (httpMessage.getPayload() instanceof String p - && p.isEmpty())) { - setSpecifiedBody(openApiSpecification, context, operation); - } - - String randomizedPath = path; + setMissingRequiredBodyToRandomValue(openApiSpecification, context, operation); + String randomizedPath = getMessage().getPath() != null ? getMessage().getPath() : path; if (operation.parameters != null) { List pathParams = operation.parameters.stream() .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; - if (context.getVariables().containsKey(parameter.getName())) { - parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() - + CitrusSettings.VARIABLE_SUFFIX; + String pathParameterValue = getDefinedPathParameter(context, parameter.getName()); + if (isNotEmpty(pathParameterValue)) { + parameterValue = "\\" + pathParameterValue; } else { - parameterValue = OpenApiTestDataGenerator.createRandomValueExpression( + parameterValue = createRandomValueExpression( (OasSchema) parameter.schema); } - randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") - .matcher(randomizedPath) - .replaceAll(parameterValue); + + randomizedPath = randomizedPath.replaceAll("\\{"+parameter.getName()+"}", parameterValue); } } OasModelHelper.getRequestContentType(operation) .ifPresent( - contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + contentType -> getMessage().setHeader(HttpHeaders.CONTENT_TYPE, contentType)); - httpMessage.path(randomizedPath); - httpMessage.method(method); + getMessage().path(randomizedPath); + getMessage().method(method); } - private void setSpecifiedBody(OpenApiSpecification openApiSpecification, - TestContext context, OasOperation operation) { - Optional body = OasModelHelper.getRequestBodySchema( - openApiSpecification.getOpenApiDoc(context), operation); - body.ifPresent(oasSchema -> httpMessage.setPayload( - OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - openApiSpecification))); + protected String getDefinedPathParameter(TestContext context, String name) { + if (context.getVariables().containsKey(name)) { + return CitrusSettings.VARIABLE_PREFIX + name + + CitrusSettings.VARIABLE_SUFFIX; + } + return null; + } + + private void setMissingRequiredBodyToRandomValue(OpenApiSpecification openApiSpecification, TestContext context, OasOperation operation) { + if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String p + && p.isEmpty())) { + Optional body = OasModelHelper.getRequestBodySchema( + openApiSpecification.getOpenApiDoc(context), operation); + body.ifPresent(oasSchema -> getMessage().setPayload( + OpenApiTestDataGenerator.createOutboundPayload(oasSchema, + openApiSpecification))); + } } - private void setSpecifiedQueryParameters(TestContext context, OasOperation operation) { + /** + * Creates all required query parameters, if they have not already been specified. + */ + private void setMissingRequiredQueryParametersToRandomValues(TestContext context, OasOperation operation) { operation.parameters.stream() .filter(param -> "query".equals(param.in)) .filter( - param -> (param.required != null && param.required) || context.getVariables() + param -> Boolean.TRUE.equals(param.required) || context.getVariables() .containsKey(param.getName())) .forEach(param -> { - if (!httpMessage.getQueryParams().containsKey(param.getName())) { - httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), - (OasSchema) param.schema, - context)); + // If not already configured explicitly, create a random value + if (!getMessage().getQueryParams().containsKey(param.getName())) { + try { + getMessage().queryParam(param.getName(), + createRandomValueExpression(param.getName(), + (OasSchema) param.schema, + context)); + } catch (Exception e) { + // Note that exploded object query parameter representation for example, cannot properly + // be randomized. + logger.warn("Unable to set missing required query parameter to random value: {}", param); + } } }); } - private void setSpecifiedHeaders(OpenApiSpecification openApiSpecification, TestContext context, OasOperation operation) { + /** + * Creates all required headers, if they have not already been specified. + */ + private void setMissingRequiredHeadersToRandomValues(OpenApiSpecification openApiSpecification, + TestContext context, OasOperation operation) { List configuredHeaders = getHeaderBuilders() .stream() .flatMap(b -> b.builderHeaders(context).keySet().stream()) @@ -211,18 +249,18 @@ private void setSpecifiedHeaders(OpenApiSpecification openApiSpecification, Test operation.parameters.stream() .filter(param -> "header".equals(param.in)) .filter( - param -> (param.required != null && param.required) || context.getVariables() + param -> Boolean.TRUE.equals(param.required) || context.getVariables() .containsKey(param.getName())) .forEach(param -> { - if (httpMessage.getHeader(param.getName()) == null + // If not already configured explicitly, create a random value + if (getMessage().getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { - httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), + getMessage().setHeader(param.getName(), + createRandomValueExpression(param.getName(), (OasSchema) param.schema, openApiSpecification, context)); } }); } } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index adf514cc0d..2cb4f16f1b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -24,6 +24,7 @@ import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.regex.Pattern; @@ -37,10 +38,11 @@ import org.citrusframework.message.Message; import org.citrusframework.message.MessageType; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; +import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -56,7 +58,7 @@ public class OpenApiClientResponseActionBuilder extends HttpClientResponseAction private final String operationId; - private boolean oasValidationEnabled = true; + private boolean schemaValidation = true; /** * Default constructor initializes http response message builder. @@ -69,51 +71,72 @@ public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode) { - super(new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, - statusCode), httpMessage); - this.openApiSpecificationSource = openApiSpecificationSource; + this(openApiSpecificationSource, new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, + statusCode), httpMessage, operationId); + } + + public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage message, + String operationId) { + super(messageBuilder, message); + this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; } + /** + * Overridden to change the default message type to JSON, as Json is more common in OpenAPI context. + */ + @Override + protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { + HttpMessageBuilderSupport support = super.createHttpMessageBuilderSupport(); + support.type(CitrusSettings.getPropertyEnvOrDefault( + CitrusSettings.DEFAULT_MESSAGE_TYPE_PROPERTY, + CitrusSettings.DEFAULT_MESSAGE_TYPE_ENV, + MessageType.JSON.toString())); + return support; + } + @Override public ReceiveMessageAction doBuild() { OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); - validate(openApi(openApiSpecification)); - if (oasValidationEnabled && !messageProcessors.contains(openApiMessageProcessor)) { + + // Honor default enablement of schema validation + OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); + if (openApiValidationContext != null && schemaValidation) { + schemaValidation = openApiValidationContext.isResponseValidationEnabled(); + } + + if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { openApiMessageProcessor = new OpenApiMessageProcessor( openApiSpecification, operationId, RESPONSE); process(openApiMessageProcessor); } + if (schemaValidation && getValidationContexts().stream().noneMatch(OpenApiMessageValidationContext.class::isInstance)) { + validate(openApi(openApiSpecification) + .schemaValidation(schemaValidation) + .build()); + } + return super.doBuild(); } - public OpenApiClientResponseActionBuilder disableOasValidation(boolean disable) { - oasValidationEnabled = !disable; - ((OpenApiClientResponseMessageBuilder)getMessageBuilderSupport().getMessageBuilder()).setOasValidationEnabled(oasValidationEnabled); + public OpenApiClientResponseActionBuilder schemaValidation(boolean enabled) { + schemaValidation = enabled; return this; } - public static void fillMessageFromResponse(OpenApiSpecification openApiSpecification, - TestContext context, HttpMessage httpMessage, @Nullable OasOperation operation, + public static void fillMessageTypeFromResponse(OpenApiSpecification openApiSpecification, + HttpMessage httpMessage, @Nullable OasOperation operation, @Nullable OasResponse response) { if (operation == null || response == null) { return; } - fillRequiredHeaders( - openApiSpecification, context, httpMessage, response); - Optional responseSchema = OasModelHelper.getSchema(response); responseSchema.ifPresent(oasSchema -> { - httpMessage.setPayload( - OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(context)), openApiSpecification)); - OasSchema resolvedSchema = OasModelHelper.resolveSchema( openApiSpecification.getOpenApiDoc(null), oasSchema); if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType( @@ -130,56 +153,34 @@ public static void fillMessageFromResponse(OpenApiSpecification openApiSpecifica ); } - private static void fillRequiredHeaders( - OpenApiSpecification openApiSpecification, TestContext context, HttpMessage httpMessage, - OasResponse response) { - - Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); - for (Map.Entry header : requiredHeaders.entrySet()) { - httpMessage.setHeader(header.getKey(), - OpenApiTestValidationDataGenerator.createValidationExpression(header.getKey(), - header.getValue(), - OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(context)), false, - openApiSpecification, - context)); - } - - Map headers = OasModelHelper.getHeaders(response); - for (Map.Entry header : headers.entrySet()) { - if (!requiredHeaders.containsKey(header.getKey()) && context.getVariables() - .containsKey(header.getKey())) { - httpMessage.setHeader(header.getKey(), - CitrusSettings.VARIABLE_PREFIX + header.getKey() - + CitrusSettings.VARIABLE_SUFFIX); - } - } - } - - private static class OpenApiClientResponseMessageBuilder extends HttpMessageBuilder { + public static class OpenApiClientResponseMessageBuilder extends HttpMessageBuilder { private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; - private final String statusCode; + private String statusCode; private final HttpMessage httpMessage; - private boolean oasValidationEnabled = true; - public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource oopenApiSpecificationSourceenApiSpec, + OpenApiSpecificationSource openApiSpecificationSource, String operationId, String statusCode) { super(httpMessage); - this.openApiSpecificationSource = oopenApiSpecificationSourceenApiSpec; + this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; this.statusCode = statusCode; this.httpMessage = httpMessage; } + public OpenApiClientResponseMessageBuilder statusCode(String statusCode) { + this.statusCode =statusCode; + return this; + } + @Override public Message build(TestContext context, String messageType) { OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); + openApiSpecification.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); @@ -191,12 +192,16 @@ public Message build(TestContext context, String messageType) { private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { OasOperation operation = operationPathAdapter.operation(); - if (oasValidationEnabled && operation.responses != null) { + // Headers already present in httpMessage should not be overwritten by open api. + // E.g. if a reasonPhrase was explicitly set in the builder, it must not be overwritten. + Map currentHeaders = new HashMap<>(httpMessage.getHeaders()); + + if (operation.responses != null) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); responseForRandomGeneration.ifPresent( - oasResponse -> fillMessageFromResponse(openApiSpecification, context, httpMessage, + oasResponse -> fillMessageTypeFromResponse(openApiSpecification, httpMessage, operation, oasResponse)); } @@ -205,10 +210,9 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification } else { httpMessage.status(HttpStatus.OK); } - } - public void setOasValidationEnabled(boolean oasValidationEnabled) { - this.oasValidationEnabled = oasValidationEnabled; + httpMessage.getHeaders().putAll(currentHeaders); } + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java new file mode 100644 index 0000000000..a08759d4ea --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java @@ -0,0 +1,56 @@ +package org.citrusframework.openapi.actions; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import org.citrusframework.context.TestContext; +import org.citrusframework.message.builder.DefaultPayloadBuilder; +import org.springframework.util.MultiValueMap; + +public class OpenApiPayloadBuilder extends DefaultPayloadBuilder { + + public OpenApiPayloadBuilder(Object payload) { + super(payload); + } + + @Override + public Object buildPayload(TestContext context) { + + if (getPayload() instanceof MultiValueMap multiValueMap) { + replaceDynamicContentInMultiValueMap(context, + (MultiValueMap) multiValueMap); + } + + return super.buildPayload(context); + } + + private static void replaceDynamicContentInMultiValueMap(TestContext context, MultiValueMap multiValueMap) { + Set cache = new HashSet<>(multiValueMap.entrySet()); + multiValueMap.clear(); + for (Object value : cache) { + if (value instanceof Map.Entry entry) { + replaceDynamicContentInEntry(context, multiValueMap, entry); + } + } + } + + private static void replaceDynamicContentInEntry(TestContext context, MultiValueMap multiValueMap, + Entry entry) { + Object key = entry.getKey(); + + List list = (List) entry.getValue(); + if (list != null) { + for (int i=0;i - buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); - }); + openApiSpecification.getOperation(operationId, context) + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), + () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); return super.build(context, messageType); } - private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { + private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter, TestContext context) { setSpecifiedMessageType(operationPathAdapter); setSpecifiedHeaders(context, openApiSpecification, operationPathAdapter); @@ -142,12 +171,15 @@ private void setSpecifiedRequestContentType(OperationPathAdapter operationPathAd String.format("@startsWith(%s)@", contentType))); } - private void setSpecifiedPath(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { - String randomizedPath = OasModelHelper.getBasePath(openApiSpecification.getOpenApiDoc(context)) - + operationPathAdapter.apiPath(); + private void setSpecifiedPath(TestContext context, + OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { + String randomizedPath = + OasModelHelper.getBasePath(openApiSpecification.getOpenApiDoc(context)) + + operationPathAdapter.apiPath(); randomizedPath = randomizedPath.replace("//", "/"); - randomizedPath = appendSegmentToUrlPath(openApiSpecification.getRootContextPath(), randomizedPath); + randomizedPath = appendSegmentToUrlPath(openApiSpecification.getRootContextPath(), + randomizedPath); if (operationPathAdapter.operation().parameters != null) { randomizedPath = determinePath(context, operationPathAdapter.operation(), @@ -157,7 +189,8 @@ private void setSpecifiedPath(TestContext context, OpenApiSpecification openApiS httpMessage.path(randomizedPath); } - private void setSpecifiedBody(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { + private void setSpecifiedBody(TestContext context, + OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { Optional body = OasModelHelper.getRequestBodySchema( openApiSpecification.getOpenApiDoc(context), operationPathAdapter.operation()); body.ifPresent(oasSchema -> httpMessage.setPayload( @@ -195,7 +228,8 @@ private String determinePath(TestContext context, OasOperation operation, return randomizedPath; } - private void setSpecifiedQueryParameters(TestContext context, OpenApiSpecification openApiSpecification, + private void setSpecifiedQueryParameters(TestContext context, + OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { @@ -210,13 +244,15 @@ private void setSpecifiedQueryParameters(TestContext context, OpenApiSpecificati .forEach(param -> httpMessage.queryParam(param.getName(), OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), false, + OasModelHelper.getSchemaDefinitions( + openApiSpecification.getOpenApiDoc(context)), false, openApiSpecification, context))); } - private void setSpecifiedHeaders(TestContext context, OpenApiSpecification openApiSpecification, + private void setSpecifiedHeaders(TestContext context, + OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { @@ -231,7 +267,8 @@ private void setSpecifiedHeaders(TestContext context, OpenApiSpecification openA .forEach(param -> httpMessage.setHeader(param.getName(), OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), false, + OasModelHelper.getSchemaDefinitions( + openApiSpecification.getOpenApiDoc(context)), false, openApiSpecification, context))); } @@ -251,7 +288,8 @@ private void setSpecifiedMessageType(OperationPathAdapter operationPathAdapter) } private void setSpecifiedMethod(OperationPathAdapter operationPathAdapter) { - httpMessage.method(HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase())); + httpMessage.method( + HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase())); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index 4518f1e6b3..dee3ccb155 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -53,6 +53,7 @@ import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpStatus; /** @@ -66,7 +67,7 @@ public class OpenApiServerResponseActionBuilder extends HttpServerResponseAction private final String operationId; - private boolean oasValidationEnabled = true; + private boolean schemaValidation = true; /** * Default constructor initializes http response message builder. @@ -88,17 +89,24 @@ public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, @Override public SendMessageAction doBuild() { OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); - if (oasValidationEnabled && !messageProcessors.contains(openApiMessageProcessor)) { - openApiMessageProcessor = new OpenApiMessageProcessor( - openApiSpecification, operationId, OpenApiMessageType.RESPONSE); + + // Honor default enablement of schema validation + OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); + if (openApiValidationContext != null && schemaValidation) { + schemaValidation = openApiValidationContext.isResponseValidationEnabled(); + } + + if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { + openApiMessageProcessor = new OpenApiMessageProcessor(openApiSpecification, operationId, + OpenApiMessageType.RESPONSE); process(openApiMessageProcessor); } return super.doBuild(); } - public OpenApiServerResponseActionBuilder disableOasValidation(boolean disable) { - oasValidationEnabled = !disable; + public OpenApiServerResponseActionBuilder schemaValidation(boolean schemaValidation) { + this.schemaValidation = schemaValidation; return this; } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java index e5aebaea7e..4d63466c58 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -16,10 +16,10 @@ package org.citrusframework.openapi.model; -import io.apicurio.datamodels.openapi.models.OasOperation; -import org.citrusframework.openapi.util.OpenApiUtils; - import static java.lang.String.format; +import static org.citrusframework.openapi.util.OpenApiUtils.getMethodPath; + +import io.apicurio.datamodels.openapi.models.OasOperation; /** * Adapts the different paths associated with an OpenAPI operation to the {@link OasOperation}. @@ -34,6 +34,6 @@ public record OperationPathAdapter(String apiPath, String contextPath, String fu @Override public String toString() { - return format("%s (%s)",OpenApiUtils.getMethodPath(operation.getMethod(), apiPath), operation.operationId); + return format("%s (%s)", getMethodPath(operation.getMethod(), apiPath), operation.operationId); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java index 3e9ea0951e..1e0916a40f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java @@ -17,17 +17,15 @@ package org.citrusframework.openapi.util; import static java.lang.String.format; +import static org.citrusframework.util.StringUtils.hasText; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nonnull; import java.util.stream.Collectors; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.OpenApiConstants; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.spi.ReferenceResolver; -import org.citrusframework.util.StringUtils; public class OpenApiUtils { @@ -35,28 +33,27 @@ private OpenApiUtils() { // Static access only } - public static String getMethodPath(@Nonnull HttpMessage httpMessage) { - Object methodHeader = httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD); - Object path = httpMessage.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI); - - return getMethodPath(methodHeader != null ? methodHeader.toString().toLowerCase() : "null", - path != null ? path.toString() : "null"); - } - public static String getMethodPath(@Nonnull String method, @Nonnull String path) { - if (StringUtils.hasText(path) && path.startsWith("/")) { + if (hasText(path) && path.startsWith("/")) { path = path.substring(1); } - return format("/%s/%s", method.toLowerCase(), path); + return format("%s_/%s", method.toUpperCase(), path); } /** * @return a unique scenario id for the {@link OasOperation} */ - public static String createFullPathOperationIdentifier(String path, OasOperation oasOperation) { + public static String createFullPathOperationIdentifier(OasOperation oasOperation, String path) { return format("%s_%s", oasOperation.getMethod().toUpperCase(), path); } + /** + * @return a unique scenario id for the {@link OasOperation} + */ + public static String createFullPathOperationIdentifier(String method, String path) { + return format("%s_%s", method.toUpperCase(), path); + } + public static boolean isAnyNumberScheme(OasSchema schema) { return ( schema != null && diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java index cc79a4a5a4..6a3a18a76c 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java @@ -14,7 +14,7 @@ public class OpenApiMessageValidationContext extends DefaultValidationContext implements SchemaValidationContext { - /** + /** * Should message be validated with its schema definition. This is enabled with respect to * global settings, which are true by default. as only messages processed by open api actions * will be processed and validation information will be derived from open api spec. @@ -22,8 +22,7 @@ public class OpenApiMessageValidationContext extends DefaultValidationContext im *

    Note that the default registered validation context is used for received messages. This is * why the schema validation is initialized with response validation enabled globally. */ - private boolean schemaValidation = OpenApiSettings.isResponseValidationEnabledGlobally(); - + private final boolean schemaValidation; public OpenApiMessageValidationContext(Builder builder) { super(); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java deleted file mode 100644 index e8c49cb2b6..0000000000 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.validation; - -import org.citrusframework.context.TestContext; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiMessageHeaders; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.validation.ValidationProcessor; - -/** - * {@code ValidationProcessor} that facilitates the use of Atlassian's Swagger Request Validator, - * and delegates validation of OpenApi requests to instances of {@link OpenApiRequestValidator}. - */ -public class OpenApiRequestValidationProcessor implements - ValidationProcessor { - - private final OpenApiSpecification openApiSpecification; - - private final String operationId; - - private final OpenApiRequestValidator openApiRequestValidator; - - public OpenApiRequestValidationProcessor(OpenApiSpecification openApiSpecification, - String operationId) { - this.openApiSpecification = openApiSpecification; - this.operationId = operationId; - this.openApiRequestValidator = new OpenApiRequestValidator(openApiSpecification); - } - - @Override - public void validate(Message message, TestContext context) { - - if (!(message instanceof HttpMessage httpMessage)) { - return; - } - - message.setHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID, operationId); - - openApiSpecification.getOperation( - operationId, context).ifPresent(operationPathAdapter -> - openApiRequestValidator.validateRequest(operationPathAdapter, httpMessage)); - } - -} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java index b37e53f660..a3809f1858 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -19,6 +19,10 @@ import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.SimpleRequest; import com.atlassian.oai.validator.report.ValidationReport; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import org.citrusframework.exceptions.ValidationException; @@ -27,6 +31,8 @@ import org.citrusframework.http.message.HttpMessageUtils; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; +import org.citrusframework.util.FileUtils; +import org.springframework.util.MultiValueMap; /** * Specific validator that uses atlassian and is responsible for validating HTTP requests @@ -36,7 +42,6 @@ public class OpenApiRequestValidator extends OpenApiValidator { public OpenApiRequestValidator(OpenApiSpecification openApiSpecification) { super(openApiSpecification); - setEnabled(openApiSpecification.getSwaggerOpenApiValidationContext() != null && openApiSpecification.getSwaggerOpenApiValidationContext().isRequestValidationEnabled()); } @Override @@ -47,7 +52,7 @@ protected String getType() { public void validateRequest(OperationPathAdapter operationPathAdapter, HttpMessage requestMessage) { - if (enabled && openApiInteractionValidator != null) { + if (openApiInteractionValidator != null) { ValidationReport validationReport = openApiInteractionValidator.validateRequest( createRequestFromMessage(operationPathAdapter, requestMessage)); if (validationReport.hasErrors()) { @@ -60,7 +65,7 @@ public void validateRequest(OperationPathAdapter operationPathAdapter, public ValidationReport validateRequestToReport(OperationPathAdapter operationPathAdapter, HttpMessage requestMessage) { - if (enabled && openApiInteractionValidator != null) { + if (openApiInteractionValidator != null) { return openApiInteractionValidator.validateRequest( createRequestFromMessage(operationPathAdapter, requestMessage)); } @@ -83,7 +88,7 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, ); if (payload != null) { - requestBuilder = requestBuilder.withBody(payload.toString()); + requestBuilder = requestBuilder.withBody(convertPayload(payload)); } SimpleRequest.Builder finalRequestBuilder = requestBuilder; @@ -102,7 +107,40 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, } }); + httpMessage.getCookies().forEach(cookie -> finalRequestBuilder.withHeader("Cookie", URLDecoder.decode(cookie.getName()+"="+cookie.getValue(), + FileUtils.getDefaultCharset()))); + return requestBuilder.build(); } + private String convertPayload(Object payload) { + + if (payload instanceof MultiValueMap multiValueMap) { + return serializeForm(multiValueMap, StandardCharsets.UTF_8); + } + + return payload != null ? payload.toString() : null; + } + + /** + * We cannot validate a MultiValueMap. The map will later on be converted to a string representation + * by Spring. For validation, we need to mimic this transformation here. + + * @see org.springframework.http.converter.FormHttpMessageConverter + */ + private String serializeForm(MultiValueMap formData, Charset charset) { + StringBuilder builder = new StringBuilder(); + formData.forEach((name, values) -> values.forEach(value -> { + if (!builder.isEmpty()) { + builder.append('&'); + } + builder.append(URLEncoder.encode(name.toString(), charset)); + if (value != null) { + builder.append('='); + builder.append(URLEncoder.encode(String.valueOf(value), charset)); + } + })); + + return builder.toString(); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java index 8a08242617..c7af584c62 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -34,7 +34,6 @@ public class OpenApiResponseValidator extends OpenApiValidator { public OpenApiResponseValidator(OpenApiSpecification openApiSpecification) { super(openApiSpecification); - setEnabled(openApiSpecification.getSwaggerOpenApiValidationContext() != null && openApiSpecification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); } @Override @@ -44,7 +43,7 @@ protected String getType() { public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { - if (enabled && openApiInteractionValidator != null) { + if (openApiInteractionValidator != null) { HttpStatusCode statusCode = httpMessage.getStatusCode(); Response response = createResponseFromMessage(httpMessage, statusCode != null ? statusCode.value() : null); @@ -61,7 +60,7 @@ public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMess public ValidationReport validateResponseToReport(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { - if (enabled && openApiInteractionValidator != null) { + if (openApiInteractionValidator != null) { HttpStatusCode statusCode = httpMessage.getStatusCode(); Response response = createResponseFromMessage(httpMessage, statusCode != null ? statusCode.value() : null); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index 74b5a55046..9bfe3affbd 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -4,6 +4,7 @@ import jakarta.annotation.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Set; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -15,20 +16,32 @@ import org.citrusframework.openapi.model.OperationPathAdapter; import org.citrusframework.openapi.util.OpenApiUtils; import org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder; -import org.citrusframework.validation.MessageValidator; +import org.citrusframework.validation.AbstractMessageValidator; import org.citrusframework.validation.SchemaValidator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpenApiSchemaValidation implements MessageValidator, +public class OpenApiSchemaValidation extends AbstractMessageValidator implements SchemaValidator { - private Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); + private static final Set FILTERED_ERROR_MESSAGE_KEYS = Set.of( + // Filtered because in general OpenAPI is not required to specify all response codes. + // So this should not be considered as validation error. + "validation.response.status.unknown" + ); + + private static final Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); + + @Override + protected Class getRequiredValidationContextType() { + return OpenApiMessageValidationContext.class; + } @Override - public void validateMessage(Message receivedMessage, Message controlMessage, - TestContext context, List list) throws ValidationException { - validate(receivedMessage, context, new Builder().schemaValidation(true).build()); + public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, + OpenApiMessageValidationContext validationContext) { + // No control message validation, only schema validation + validate(receivedMessage, context, validationContext); } @Override @@ -43,17 +56,33 @@ public void validate( ValidationReportData validationReportData = validate(context, httpMessage, findSchemaRepositories(context), validationContext); - if (validationReportData != null && validationReportData.report.hasErrors()) { - if (logger.isErrorEnabled()) { - logger.error("Failed to validate Json schema for message:\n{}", - message.getPayload(String.class)); + + if (validationReportData != null && validationReportData.report != null) { + + ValidationReport filteredReport = filterIrrelevantMessages( + validationReportData); + if (filteredReport.hasErrors()) { + if (logger.isErrorEnabled()) { + logger.error("Failed to validate Json schema for message:\n{}", + message.getPayload(String.class)); + } + throw new ValidationException(constructErrorMessage(validationReportData)); } - throw new ValidationException(constructErrorMessage(validationReportData)); } logger.debug("Json schema validation successful: All values OK"); } + /** + * Filter specific messages from the report which are considered irrelevant. + * See {@link OpenApiSchemaValidation#FILTERED_ERROR_MESSAGE_KEYS} for more details. + */ + private static ValidationReport filterIrrelevantMessages(ValidationReportData validationReportData) { + return ValidationReport.from( + validationReportData.report.getMessages().stream() + .filter(msg -> !FILTERED_ERROR_MESSAGE_KEYS.contains(msg.getKey())).toList()); + } + @Override public boolean supportsMessageType(String messageType, Message message) { return message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java similarity index 86% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java index ad9dbcf23e..832f063b6f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContext.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java @@ -25,7 +25,12 @@ import com.atlassian.oai.validator.schema.SwaggerV20Library; import io.swagger.v3.oas.models.OpenAPI; -public class SwaggerOpenApiValidationContext { +/** + * Represents the context for OpenAPI validation, providing configuration and validators for request and response validation. + * This context maintains settings for both request and response validation, which can be controlled at an instance level. + * By default, these settings are initialized based on a global configuration. + */ +public class OpenApiValidationContext { private final OpenAPI openApi; @@ -37,7 +42,7 @@ public class SwaggerOpenApiValidationContext { private boolean requestValidationEnabled = isRequestValidationEnabledGlobally(); - public SwaggerOpenApiValidationContext(OpenAPI openApi) { + public OpenApiValidationContext(OpenAPI openApi) { this.openApi = openApi; } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java similarity index 67% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java index 51d0ba4412..a541c3948f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/SwaggerOpenApiValidationContextLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java @@ -27,45 +27,45 @@ import org.citrusframework.spi.Resource; /** - * Utility class for loading Swagger OpenAPI specifications from various resources. + * Utility class for creation of {@link OpenApiValidationContext}. */ -public abstract class SwaggerOpenApiValidationContextLoader { +public abstract class OpenApiValidationContextLoader { - private SwaggerOpenApiValidationContextLoader() { + private OpenApiValidationContextLoader() { // Static access only } /** - * Loads an OpenAPI specification from a secured web resource. + * Creates an OpenApiValidationContext from a secured OpenAPI web resource. * - * @param url the URL of the secured web resource - * @return the loaded OpenAPI specification + * @param url the URL of the secured OpenAPI web resource + * @return the OpenApiValidationContext */ - public static SwaggerOpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { + public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), Collections.emptyList(), defaultParseOptions())); } /** - * Loads an OpenAPI specification from a web resource. + * Creates an OpenApiValidationContext from an OpenAPI web resource. * - * @param url the URL of the web resource - * @return the loaded OpenAPI specification + * @param url the URL of the OpenAPI web resource + * @return the OpenApiValidationContext */ - public static SwaggerOpenApiValidationContext fromWebResource(@Nonnull URL url) { + public static OpenApiValidationContext fromWebResource(@Nonnull URL url) { return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), Collections.emptyList(), defaultParseOptions())); } /** - * Loads an OpenAPI specification from a file. + * Creates an OpenApiValidationContext from an OpenAPI file. * * @param resource the file resource containing the OpenAPI specification - * @return the loaded OpenAPI specification + * @return the OpenApiValidationContext */ - public static SwaggerOpenApiValidationContext fromFile(@Nonnull Resource resource) { + public static OpenApiValidationContext fromFile(@Nonnull Resource resource) { return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), Collections.emptyList(), defaultParseOptions())); } - private static SwaggerOpenApiValidationContext createValidationContext(OpenAPI openApi) { - return new SwaggerOpenApiValidationContext(openApi); + private static OpenApiValidationContext createValidationContext(OpenAPI openApi) { + return new OpenApiValidationContext(openApi); } private static ParseOptions defaultParseOptions() { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java index c5393f8051..61766421db 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java @@ -25,26 +25,16 @@ public abstract class OpenApiValidator { protected final OpenApiInteractionValidator openApiInteractionValidator; - protected boolean enabled; - protected OpenApiValidator(OpenApiSpecification openApiSpecification) { - SwaggerOpenApiValidationContext swaggerOpenApiValidationContext = openApiSpecification.getSwaggerOpenApiValidationContext(); - if (swaggerOpenApiValidationContext != null) { - openApiInteractionValidator = openApiSpecification.getSwaggerOpenApiValidationContext() + OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); + if (openApiValidationContext != null) { + openApiInteractionValidator = openApiSpecification.getOpenApiValidationContext() .getOpenApiInteractionValidator(); } else { openApiInteractionValidator = null; } } - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public boolean isEnabled() { - return enabled; - } - protected abstract String getType(); /** diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java index 39486d14f8..2c15ea89c3 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java @@ -13,6 +13,6 @@ public void testToHeaderNameRequest() { @Test public void testToHeaderNameResponse() { - assertEquals(OpenApiMessageHeaders.REQUEST_TYPE, OpenApiMessageHeaders.RESPONSE_TYPE); + assertEquals(OpenApiMessageType.RESPONSE.toHeaderName(), OpenApiMessageHeaders.RESPONSE_TYPE); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java deleted file mode 100644 index d837f1f0ee..0000000000 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiPathRegistryTest.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - -public class OpenApiPathRegistryTest { - - private static final String[] SEGMENTS = {"api", "v1", "pet", "user", "order", "product", - "category", "service", "data"}; - private static final String VARIABLE_TEMPLATE = "{%s}"; - private static final String[] VARIABLES = {"id", "userId", "orderId", "productId", - "categoryId"}; - - public static List generatePaths(int numberOfPaths) { - List paths = new ArrayList<>(); - Random random = new Random(); - - Set allGenerated = new HashSet<>(); - while (allGenerated.size() < numberOfPaths) { - int numberOfSegments = 1 + random.nextInt(7); // 1 to 7 segments - StringBuilder pathBuilder = new StringBuilder("/api/v1"); - - int nids = 0; - for (int j = 0; j < numberOfSegments; j++) { - if (nids < 2 && nids < numberOfSegments - 1 && random.nextBoolean()) { - nids++; - // Add a segment with a variable - pathBuilder.append("/").append(String.format(VARIABLE_TEMPLATE, - VARIABLES[random.nextInt(VARIABLES.length)])); - } else { - // Add a fixed segment - pathBuilder.append("/").append(SEGMENTS[random.nextInt(SEGMENTS.length)]); - } - } - - String path = pathBuilder.toString(); - if (!allGenerated.contains(path)) { - paths.add(path); - allGenerated.add(path); - } - } - return paths; - } - - @Test - public void insertShouldSucceedOnSameValue() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2", "root")); - assertTrue(openApiPathRegistry.insert("/s1/s2", "root")); - assertEquals(openApiPathRegistry.search("/s1/s2"), "root"); - } - - @Test - public void insertShouldFailOnSamePathWithDifferentValue() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2", "root1")); - assertFalse(openApiPathRegistry.insert("/s1/s2", "root2")); - assertEquals(openApiPathRegistry.search("/s1/s2"), "root1"); - } - - @Test - public void searchShouldSucceedOnPartialPathMatchWithDifferentVariables() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id2}/s4/{id1}", "root2")); - assertEquals(openApiPathRegistry.search("/s1/s2/1111"), "root1"); - assertEquals(openApiPathRegistry.search("/s1/s2/123/s4/222"), "root2"); - - openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id2}", "root1")); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s4/{id2}", "root2")); - assertEquals(openApiPathRegistry.search("/s1/s2/1111"), "root1"); - assertEquals(openApiPathRegistry.search("/s1/s2/123/s4/222"), "root2"); - } - - @Test - public void insertShouldFailOnMatchingPathWithDifferentValue() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2", "root1")); - assertFalse(openApiPathRegistry.insert("/s1/{id1}", "root2")); - assertEquals(openApiPathRegistry.search("/s1/s2"), "root1"); - assertNull(openApiPathRegistry.search("/s1/111")); - - assertTrue(openApiPathRegistry.insert("/s1/s2/s3/{id2}", "root3")); - assertFalse(openApiPathRegistry.insert("/s1/{id1}/s3/{id2}", "root4")); - assertEquals(openApiPathRegistry.search("/s1/s2/s3/123"), "root3"); - assertEquals(openApiPathRegistry.search("/s1/s2/s3/456"), "root3"); - assertNull(openApiPathRegistry.search("/s1/111/s3/111")); - - openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/{id1}", "root2")); - assertFalse(openApiPathRegistry.insert("/s1/s2", "root1")); - assertEquals(openApiPathRegistry.search("/s1/111"), "root2"); - assertEquals(openApiPathRegistry.search("/s1/s2"), "root2"); - - assertTrue(openApiPathRegistry.insert("/s1/{id1}/s3/{id2}", "root3")); - assertFalse(openApiPathRegistry.insert("/s1/s2/s3/{id2}", "root4")); - assertEquals(openApiPathRegistry.search("/s1/5678/s3/1234"), "root3"); - assertEquals(openApiPathRegistry.search("/s1/s2/s3/1234"), "root3"); - } - - @Test - public void insertShouldNotOverwriteNested() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s3/{id2}", "root2")); - assertEquals(openApiPathRegistry.search("/s1/s2/123"), "root1"); - assertEquals(openApiPathRegistry.search("/s1/s2/1233/s3/121"), "root2"); - - openApiPathRegistry = new OpenApiPathRegistry<>(); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}/s3/{id2}", "root2")); - assertTrue(openApiPathRegistry.insert("/s1/s2/{id1}", "root1")); - assertEquals(openApiPathRegistry.search("/s1/s2/123"), "root1"); - assertEquals(openApiPathRegistry.search("/s1/s2/1233/s3/121"), "root2"); - } - - @Test - public void randomAccess() { - OpenApiPathRegistry openApiPathRegistry = new OpenApiPathRegistry<>(); - - int numberOfPaths = 1000; // Specify the number of paths you want to generate - List paths = generatePaths(numberOfPaths); - - Map pathToValueMap = paths.stream() - .collect(Collectors.toMap(path -> path, k -> k.replaceAll("\\{[a-zA-Z]*}", "1111"))); - paths.removeIf(path -> !openApiPathRegistry.insert(path, pathToValueMap.get(path))); - - Random random = new Random(); - int[] indexes = new int[1000]; - for (int i = 0; i < 1000; i++) { - indexes[i] = random.nextInt(paths.size() - 1); - } - - for (int i = 0; i < 1000; i++) { - String path = paths.get(indexes[i]); - String realPath = pathToValueMap.get(path); - String result = openApiPathRegistry.search(realPath); - Assert.assertNotNull(result, - "No result for real path " + realPath + " expected a match by path " + path); - Assert.assertEquals(result, realPath); - } - } -} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index 668ecb9b64..bbe892c193 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -120,7 +120,7 @@ public void shouldInitializeFromUrl(String urlString) { private void assertPingApi(OpenApiSpecification specification) { assertNotNull(specification); - assertNotNull(specification.getSwaggerOpenApiValidationContext()); + assertNotNull(specification.getOpenApiValidationContext()); Optional pingOperationPathAdapter = specification.getOperation( PING_OPERATION_ID, testContextMock); @@ -244,21 +244,21 @@ URL toSpecUrl(String resolvedSpecUrl) { // Then (not yet initialized) assertFalse(specification.isApiRequestValidationEnabled()); - assertNull(specification.getSwaggerOpenApiValidationContext()); + assertNull(specification.getOpenApiValidationContext()); // When (initialize) specification.getOpenApiDoc(testContextMock); // Then assertFalse(specification.isApiRequestValidationEnabled()); - assertNotNull(specification.getSwaggerOpenApiValidationContext()); + assertNotNull(specification.getOpenApiValidationContext()); // When specification.setApiRequestValidationEnabled(true); // Then assertTrue(specification.isApiRequestValidationEnabled()); - assertTrue(specification.getSwaggerOpenApiValidationContext().isRequestValidationEnabled()); + assertTrue(specification.getOpenApiValidationContext().isRequestValidationEnabled()); } @@ -290,15 +290,15 @@ public void shouldDisableEnableResponseValidationWhenSet() { // Then assertFalse(specification.isApiResponseValidationEnabled()); - assertNotNull(specification.getSwaggerOpenApiValidationContext()); - assertFalse(specification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); + assertNotNull(specification.getOpenApiValidationContext()); + assertFalse(specification.getOpenApiValidationContext().isResponseValidationEnabled()); // When specification.setApiResponseValidationEnabled(true); // Then assertTrue(specification.isApiResponseValidationEnabled()); - assertTrue(specification.getSwaggerOpenApiValidationContext().isResponseValidationEnabled()); + assertTrue(specification.getOpenApiValidationContext().isResponseValidationEnabled()); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index 6ac0dd9d60..a0e89a4e6e 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -68,7 +68,7 @@ public static void beforeClass() { openApiSpecification = OpenApiSpecification.from( Resources.fromClasspath("org/citrusframework/openapi/ping/ping-api.yaml")); - schemaValidator = openApiSpecification.getSwaggerOpenApiValidationContext() + schemaValidator = openApiSpecification.getOpenApiValidationContext() .getSchemaValidator(); } @@ -289,7 +289,7 @@ void testPingApiSchemas(String schemaType) throws IOException { OasSchema schema = OasModelHelper.getSchemaDefinitions( openApiSpecification.getOpenApiDoc(null)).get(schemaType); - Schema swaggerValidationSchema = openApiSpecification.getSwaggerOpenApiValidationContext() + Schema swaggerValidationSchema = openApiSpecification.getOpenApiValidationContext() .getSwaggerOpenApi().getComponents().getSchemas().get(schemaType); assertNotNull(schema); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java index 820a8cbbae..3461d46b60 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java @@ -16,15 +16,20 @@ package org.citrusframework.openapi; +import static org.assertj.core.api.Assertions.assertThat; import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationExpression; +import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationRegex; import static org.mockito.Mockito.mock; import static org.testng.Assert.assertEquals; +import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import java.util.HashMap; import java.util.List; +import java.util.regex.Pattern; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class OpenApiTestValidationDataGeneratorTest { @@ -68,4 +73,85 @@ public void allOfIsIgnoredForOas2() { assertEquals(createValidationExpression( allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); } + + @DataProvider(name = "createValidationRegexDataProvider") + public static Object[][] createValidationRegexDataProvider() { + + Oas30Schema stringSchema = new Oas30Schema(); + stringSchema.type = OpenApiConstants.TYPE_STRING; + + Oas30Schema uuidSchema = new Oas30Schema(); + uuidSchema.type = OpenApiConstants.TYPE_STRING; + uuidSchema.format = OpenApiConstants.FORMAT_UUID; + + Oas30Schema dateSchema = new Oas30Schema(); + dateSchema.type = OpenApiConstants.TYPE_STRING; + dateSchema.format = OpenApiConstants.FORMAT_DATE; + + Oas30Schema dateTimeSchema = new Oas30Schema(); + dateTimeSchema.type = OpenApiConstants.TYPE_STRING; + dateTimeSchema.format = OpenApiConstants.FORMAT_DATE_TIME; + + Oas30Schema integerSchema = new Oas30Schema(); + integerSchema.type = OpenApiConstants.TYPE_INTEGER; + + Oas30Schema numberSchema = new Oas30Schema(); + numberSchema.type = OpenApiConstants.TYPE_NUMBER; + + Oas30Schema booleanSchema = new Oas30Schema(); + booleanSchema.type = OpenApiConstants.TYPE_BOOLEAN; + + Oas30Schema regexSchema = new Oas30Schema(); + regexSchema.type = OpenApiConstants.TYPE_STRING; + regexSchema.pattern = "[1234]5[6789]"; + + Oas30Schema enumSchema = new Oas30Schema(); + enumSchema.type = OpenApiConstants.TYPE_STRING; + enumSchema.enum_ = List.of("A","B","C"); + + return new Object[][]{ + {stringSchema, "xyz", true}, + {uuidSchema, "123e4567-e89b-12d3-a456-426614174000", true}, + {uuidSchema, "123e4567-e89b-12d3-a456-42661417400", false}, + {dateSchema, "2023-05-15", true}, + {dateSchema, "2023-15-15", false}, + {dateTimeSchema, "2023-05-15T10:15:30Z", true}, + {dateTimeSchema, "2023-05-15T25:15:30Z", false}, + {integerSchema, "2023", true}, + {integerSchema, "2023.05", false}, + {numberSchema, "2023", true}, + {numberSchema, "2023.xx", false}, + {booleanSchema, "true", true}, + {booleanSchema, "false", true}, + {booleanSchema, "yes", false}, + {booleanSchema, "no", false}, + {booleanSchema, "yes", false}, + {booleanSchema, "no", false}, + {regexSchema, "156", true}, + {regexSchema, "651", false}, + {enumSchema, "A", true}, + {enumSchema, "B", true}, + {enumSchema, "C", true}, + {enumSchema, "a", false}, + {enumSchema, "D", false}, + }; + } + + @Test(dataProvider = "createValidationRegexDataProvider") + void createValidationRegex_shouldValidateRealDataCorrectly(OasSchema schema, String toValidate, boolean result) { + String regex = createValidationRegex(schema); + assertThat(Pattern.matches(regex, toValidate)).isEqualTo(result); + } + + @Test + void validationRegexOfNullIsEmpty() { + assertThat(createValidationRegex(null)).isEmpty(); + } + + @Test + void defaultvalidationRegexIsEmpty() { + Oas30Schema oas30Schema = new Oas30Schema(); + oas30Schema.type = "xxxx"; + assertThat(createValidationRegex(oas30Schema)).isEmpty(); + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java index 533ccb5211..cc222f3f67 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java @@ -16,31 +16,24 @@ package org.citrusframework.openapi; +import static org.citrusframework.openapi.util.OpenApiUtils.getKnownOpenApiAliases; +import static org.citrusframework.openapi.util.OpenApiUtils.getMethodPath; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + import java.util.List; import java.util.Map; import java.util.Set; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.http.message.HttpMessageHeaders; -import org.citrusframework.openapi.util.OpenApiUtils; -import org.citrusframework.openapi.validation.OpenApiMessageProcessor; import org.citrusframework.spi.ReferenceResolver; -import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.citrusframework.openapi.util.OpenApiUtils.getKnownOpenApiAliases; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - public class OpenApiUtilsTest { - @Mock - private HttpMessage httpMessageMock; - private AutoCloseable mockCloseable; @BeforeMethod @@ -53,54 +46,28 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test - public void shouldReturnFormattedMethodPathWhenHttpMessageHasMethodAndPath() { - // Given - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD)).thenReturn("GET"); - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/path"); - - // When - String methodPath = OpenApiUtils.getMethodPath(httpMessageMock); - - // Then - assertEquals(methodPath, "/get/api/path"); - } - - @Test - public void shouldReturnDefaultMethodPathWhenHttpMessageHasNoMethodAndPath() { - // Given - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_METHOD)).thenReturn(null); - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn(null); - - // When - String methodPath = OpenApiUtils.getMethodPath(httpMessageMock); - - // Then - assertEquals(methodPath, "/null/null"); - } - @Test public void shouldReturnFormattedMethodPathWhenMethodAndPathAreProvided() { // When - String methodPath = OpenApiUtils.getMethodPath("POST", "/api/path"); + String methodPath = getMethodPath("POST", "/api/path"); // Then - assertEquals(methodPath, "/post/api/path"); + assertEquals(methodPath, "POST_/api/path"); } @Test public void shouldReturnFormattedMethodPathWhenMethodIsEmptyAndPathIsProvided() { // When - String methodPath = OpenApiUtils.getMethodPath("", "/api/path"); + String methodPath = getMethodPath("", "/api/path"); // Then - assertEquals(methodPath, "//api/path"); + assertEquals(methodPath, "_/api/path"); } @Test public void shouldReturnFormattedMethodPathWhenMethodAndPathAreEmpty() { // When - String methodPath = OpenApiUtils.getMethodPath("", ""); + String methodPath = getMethodPath("", ""); // Then - assertEquals(methodPath, "//"); + assertEquals(methodPath, "_/"); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java index 1095cba8e2..1cf06d73a0 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java @@ -1,25 +1,23 @@ package org.citrusframework.openapi.actions; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertNotNull; + import org.citrusframework.endpoint.Endpoint; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.spi.AbstractReferenceResolverAwareTestActionBuilder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertTrue; - public class OpenApiClientActionBuilderTest { private OpenApiClientActionBuilder fixture; @BeforeMethod public void beforeMethod() { - fixture = new OpenApiClientActionBuilder(mock(Endpoint.class), mock(OpenApiSpecification.class)); + fixture = new OpenApiClientActionBuilder(mock(Endpoint.class), mock(OpenApiSpecificationSource.class)); } @Test public void isReferenceResolverAwareTestActionBuilder() { - assertTrue(fixture instanceof AbstractReferenceResolverAwareTestActionBuilder, "Is instanceof AbstractReferenceResolverAwareTestActionBuilder"); + assertNotNull(fixture, "Is instanceof AbstractReferenceResolverAwareTestActionBuilder"); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java new file mode 100644 index 0000000000..856a39ce6f --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java @@ -0,0 +1,65 @@ +package org.citrusframework.openapi.actions; + +import org.citrusframework.context.TestContext; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class OpenApiPayloadBuilderTest { + + private TestContext context; + + @BeforeClass + public void setUp() { + context = new TestContext(); + } + + @Test + public void testBuildPayloadWithMultiValueMap() { + // Given + MultiValueMap multiValueMap = new LinkedMultiValueMap<>(); + multiValueMap.add("key1", "value1"); + multiValueMap.add("key2", "Hello ${user}, welcome!"); + multiValueMap.add("key2", "Another ${user} message"); + multiValueMap.add("${k3}", "a"); + multiValueMap.add("${k3}", "b"); + multiValueMap.add("${k3}", "${user}"); + + context.setVariable("user", "John"); + context.setVariable("k3", "key3"); + + OpenApiPayloadBuilder payloadBuilder = new OpenApiPayloadBuilder(multiValueMap); + + // When + Object payload = payloadBuilder.buildPayload(context); + + // Then + Assert.assertTrue(payload instanceof MultiValueMap); + MultiValueMap result = (MultiValueMap) payload; + + Assert.assertEquals(result.get("key1").get(0), "value1"); + Assert.assertEquals(result.get("key2").get(0), "Hello John, welcome!"); + Assert.assertEquals(result.get("key2").get(1), "Another John message"); + Assert.assertEquals(result.get("key3").get(0), "a"); + Assert.assertEquals(result.get("key3").get(1), "b"); + Assert.assertEquals(result.get("key3").get(2), "John"); + } + + @Test + public void testBuildPayloadWithPlainObject() { + // Given + String simplePayload = "This is a simple ${message}"; + context.setVariable("message", "test"); + + OpenApiPayloadBuilder payloadBuilder = new OpenApiPayloadBuilder(simplePayload); + + // When + Object payload = payloadBuilder.buildPayload(context); + + // Then + Assert.assertTrue(payload instanceof String); + Assert.assertEquals(payload, "This is a simple test"); + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java index dce3c9962f..86fcf00504 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java @@ -1,21 +1,20 @@ package org.citrusframework.openapi.actions; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertTrue; + import org.citrusframework.endpoint.Endpoint; -import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.spi.AbstractReferenceResolverAwareTestActionBuilder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertTrue; - public class OpenApiServerActionBuilderTest { private OpenApiServerActionBuilder fixture; @BeforeMethod public void beforeMethod() { - fixture = new OpenApiServerActionBuilder(mock(Endpoint.class), mock(OpenApiSpecification.class)); + fixture = new OpenApiServerActionBuilder(mock(Endpoint.class), mock(OpenApiSpecificationSource.class)); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index 33aad7e924..d9d06aabf3 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -113,7 +113,7 @@ public void cleanupEndpoints() { } @Test - public void shouldLoadOpenApiClientActions() throws IOException { + public void shouldLoadOpenApiClientActions() { GroovyTestLoader testLoader = createTestLoader("classpath:org/citrusframework/openapi/groovy/openapi-client.test.groovy"); context.setVariable("port", port); @@ -187,8 +187,6 @@ public void shouldLoadOpenApiClientActions() throws IOException { httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), - "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java index 61023c6dcd..d3a844c00a 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java @@ -33,6 +33,7 @@ import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -127,10 +128,11 @@ public void shouldLoadOpenApiServerActions() { int actionIndex = 0; ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + assertEquals(receiveMessageAction.getValidationContexts().size(), 4); assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); @@ -165,10 +167,11 @@ public void shouldLoadOpenApiServerActions() { assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + assertEquals(receiveMessageAction.getValidationContexts().size(), 4); assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index c210208820..14bfb26f55 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -27,11 +27,16 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; -import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.openapi.integration.OpenApiClientIT.Config; import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.citrusframework.util.SocketUtils; +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; +import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.DataProvider; import org.testng.annotations.Ignore; import org.testng.annotations.Test; @@ -44,29 +49,18 @@ import static org.testng.Assert.fail; @Test +@ContextConfiguration(classes = {Config.class}) public class OpenApiClientIT extends TestNGCitrusSpringSupport { public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; - public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; - - private final int port = SocketUtils.findAvailableTcpPort(8080); - @BindToRegistry - private final HttpServer httpServer = new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); + public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; - @BindToRegistry - private final HttpClient httpClient = new HttpClientBuilder() - .requestUrl("http://localhost:%d".formatted(port)) - .build(); + @Autowired + private HttpServer httpServer; - @BindToRegistry - private final OpenApiRepository openApiRepository = new OpenApiRepository() - .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + @Autowired + private HttpClient httpClient; private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); @@ -74,26 +68,30 @@ public class OpenApiClientIT extends TestNGCitrusSpringSupport { private final OpenApiSpecification pingSpec = OpenApiSpecification.from( Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + @BeforeEach + void beforeEach() { + } + @CitrusTest @Test - public void shouldExecuteGetPetByIdFromDirectSpec() { - shouldExecuteGetPetById(openapi(petstoreSpec), VALID_PET_PATH, true, false); + public void shouldExecuteGetPetById() { + shouldExecuteGetPetById(openapi(petstoreSpec), VALID_PET_PATH, true, true); } @CitrusTest @Test public void shouldFailOnMissingNameInResponse() { - shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, false, false); + shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, false, true); } @CitrusTest @Test public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { - shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, true, true); + shouldExecuteGetPetById(openapi(petstoreSpec), INVALID_PET_PATH, true, false); } private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String responseFile, - boolean valid, boolean disableValidation) { + boolean valid, boolean schemaValidation) { variable("petId", "1001"); @@ -118,7 +116,7 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String respon OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi .client(httpClient).receive("getPetById", HttpStatus.OK) - .disableOasValidation(disableValidation); + .schemaValidation(schemaValidation); if (valid) { then(clientResponseActionBuilder); @@ -127,12 +125,6 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String respon } } - @CitrusTest - @Test - public void shouldProperlyExecuteGetAndAddPetFromDirectSpec() { - shouldExecuteGetAndAddPet(openapi(petstoreSpec)); - } - @CitrusTest @Test public void shouldProperlyExecuteGetAndAddPetFromRepository() { @@ -170,7 +162,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) .client(httpClient) .send("addPet") - .disableOasValidation(true) + .schemaValidation(false) .message().body(Resources.create(VALID_PET_PATH)); try { @@ -226,7 +218,7 @@ public static Object[][] pingApiOperationDataprovider() { @Test(dataProvider = "pingApiOperationDataprovider") @CitrusTest - @Ignore // Solve issue with composite schemes + @Ignore public void shouldPerformRoundtripPingOperation(String pingApiOperation) { variable("id", 2001); @@ -251,4 +243,34 @@ public void shouldPerformRoundtripPingOperation(String pingApiOperation) { then(clientResponseActionBuilder); } + + @Configuration + public static class Config { + + private final int port = SocketUtils.findAvailableTcpPort(8080); + + @Bean + public HttpServer httpServer() { + + return new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + } + + @Bean + public HttpClient httpClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .build(); + } + + @Bean + public OpenApiRepository petstoreOpenApiRepository() { + return new OpenApiRepository() + .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + } + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 808c84cdc2..d87831c3f9 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -27,11 +27,15 @@ import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerResponseActionBuilder; -import org.citrusframework.spi.BindToRegistry; +import org.citrusframework.openapi.integration.OpenApiServerIT.Config; import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.citrusframework.util.SocketUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; +import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.Test; import java.util.List; @@ -42,30 +46,17 @@ import static org.testng.Assert.fail; @Test +@ContextConfiguration(classes = {Config.class}) public class OpenApiServerIT extends TestNGCitrusSpringSupport { public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; - private final int port = SocketUtils.findAvailableTcpPort(8080); - - @BindToRegistry - private final HttpServer httpServer = new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); - - @BindToRegistry - private final HttpClient httpClient = new HttpClientBuilder() - .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) - .build(); - - @BindToRegistry - private final OpenApiRepository openApiRepository = new OpenApiRepository() - .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + @Autowired + private HttpServer httpServer; + @Autowired + private HttpClient httpClient; @CitrusTest public void shouldExecuteGetPetById() { @@ -81,7 +72,9 @@ public void shouldExecuteGetPetById() { then(openapi("petstore-v3") .server(httpServer) - .receive("getPetById")); + .receive("getPetById") + .message() + ); then(openapi("petstore-v3") .server(httpServer) @@ -107,6 +100,47 @@ public void shouldExecuteGetPetById() { """)); } + @CitrusTest + public void shouldExecuteGetPetByIdWithRandomizedId() { + + when(http() + .client(httpClient) + .send() + .get("/pet/726354") + .message() + .accept("application/json") + .fork(true)); + + then(openapi("petstore-v3") + .server(httpServer) + .receive("getPetById") + .message() + ); + + then(openapi("petstore-v3") + .server(httpServer) + .send("getPetById", HttpStatus.OK)); + + then(http() + .client(httpClient) + .receive() + .response(HttpStatus.OK) + .message() + .body(""" + { + "id": "@isNumber()@", + "name": "@notEmpty()@", + "category": { + "id": "@isNumber()@", + "name": "@notEmpty()@" + }, + "photoUrls": "@notEmpty()@", + "tags": "@ignore@", + "status": "@matches(sold|pending|available)@" + } + """)); + } + @CitrusTest public void executeGetPetByIdShouldFailOnInvalidResponse() { variable("petId", "1001"); @@ -161,7 +195,7 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") .server(httpServer) .send("getPetById", HttpStatus.OK) - .disableOasValidation(true) + .schemaValidation(false) .message().body(""" { "id": "xxxx", @@ -199,12 +233,17 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable @CitrusTest public void shouldExecuteAddPet() { - shouldExecuteAddPet(openapi("petstore-v3"), VALID_PET_PATH, true); + shouldExecuteAddPet(openapi("petstore-v3"), VALID_PET_PATH, true, true); } @CitrusTest public void shouldFailOnMissingNameInRequest() { - shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false); + shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false, true); + } + + @CitrusTest + public void shouldPassOnMissingNameInRequestIfValidationIsDisabled() { + shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false, false); } @CitrusTest @@ -268,7 +307,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") .server(httpServer) .receive("addPet") - .disableOasValidation(false); + .schemaValidation(false); try { when(addPetBuilder); @@ -277,7 +316,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { } } - private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFile, boolean valid) { + private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFile, boolean valid, boolean validationEnabled) { variable("petId", "1001"); when(http() @@ -311,4 +350,33 @@ private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFil } + @Configuration + public static class Config { + + private final int port = SocketUtils.findAvailableTcpPort(8080); + + @Bean + public HttpServer httpServer() { + return new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + } + + @Bean + public HttpClient httpClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) + .build(); + } + + @Bean + public OpenApiRepository petstoreOpenApiRepository() { + return new OpenApiRepository() + .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + } + } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java index ab2da578e7..160c6d9f91 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java @@ -1,5 +1,6 @@ package org.citrusframework.openapi.random; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.assertArg; import static org.mockito.Mockito.atLeast; @@ -10,7 +11,6 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import static org.testng.Assert.assertTrue; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; @@ -39,7 +39,7 @@ public void testHandlesCompositeSchema() { Oas30Schema schema = new Oas30Schema(); schema.allOf = Collections.singletonList(new Oas30Schema()); - assertTrue(generator.handles(schema)); + assertThat(generator.handles(schema)).isTrue(); } @Test @@ -62,9 +62,9 @@ public void testGenerateAnyOf() { generator.generate(mockContext, schema); - verify(builderSpy).object(any()); - verify(mockContext, atLeast(1)).generate(assertArg(arg -> schema.anyOf.contains(arg))); - verify(mockContext, atMost(3)).generate(assertArg(arg -> schema.anyOf.contains(arg))); + verify(builderSpy, atMost(2)).object(any()); + verify(mockContext, atLeast(1)).generate(assertArg(arg -> assertThat(schema.anyOf).contains(arg))); + verify(mockContext, atMost(3)).generate(assertArg(arg -> assertThat(schema.anyOf).contains(arg))); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java deleted file mode 100644 index 04a0d47086..0000000000 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidationProcessorTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.validation; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertNotNull; - -import java.util.Optional; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.springframework.test.util.ReflectionTestUtils; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -public class OpenApiRequestValidationProcessorTest { - - @Mock - private OpenApiSpecification openApiSpecificationMock; - - @Mock - private OperationPathAdapter operationPathAdapterMock; - - private OpenApiRequestValidationProcessor processor; - - private AutoCloseable mockCloseable; - - @BeforeMethod - public void beforeMethod() { - mockCloseable = MockitoAnnotations.openMocks(this); - processor = new OpenApiRequestValidationProcessor(openApiSpecificationMock, "operationId"); - } - - @AfterMethod - public void afterMethod() throws Exception { - mockCloseable.close(); - } - - @Test - public void shouldNotValidateNonHttpMessage() { - Message messageMock = mock(); - - processor.validate(messageMock, mock()); - - verify(openApiSpecificationMock,times(2)).getSwaggerOpenApiValidationContext(); - verifyNoMoreInteractions(openApiSpecificationMock); - } - - @Test - public void shouldValidateHttpMessage() { - HttpMessage httpMessageMock = mock(); - TestContext contextMock = mock(); - - OpenApiRequestValidator openApiRequestValidatorSpy = replaceValidatorWithSpy(httpMessageMock); - - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.of(operationPathAdapterMock)); - - processor.validate(httpMessageMock, contextMock); - - verify(openApiRequestValidatorSpy).validateRequest(operationPathAdapterMock, httpMessageMock); - } - - @Test - public void shouldCallValidateRequest() { - HttpMessage httpMessageMock = mock(); - TestContext contextMock = mock(); - - OpenApiRequestValidator openApiRequestValidatorSpy = replaceValidatorWithSpy(httpMessageMock); - - when(openApiSpecificationMock.getOperation(anyString(), any(TestContext.class))) - .thenReturn(Optional.empty()); - - processor.validate(httpMessageMock, contextMock); - - verify(openApiSpecificationMock).getOperation(anyString(), - any(TestContext.class)); - verify(openApiRequestValidatorSpy, times(0)).validateRequest(operationPathAdapterMock, httpMessageMock); - } - - private OpenApiRequestValidator replaceValidatorWithSpy(HttpMessage httpMessage) { - OpenApiRequestValidator openApiRequestValidator = (OpenApiRequestValidator) ReflectionTestUtils.getField( - processor, - "openApiRequestValidator"); - - assertNotNull(openApiRequestValidator); - OpenApiRequestValidator openApiRequestValidatorSpy = spy(openApiRequestValidator); - ReflectionTestUtils.setField(processor, "openApiRequestValidator", openApiRequestValidatorSpy); - - doAnswer((invocation) -> null - // do nothing - ).when(openApiRequestValidatorSpy).validateRequest(operationPathAdapterMock, httpMessage); - - return openApiRequestValidatorSpy; - } -} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java index 3716b503c7..478480e9ba 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -16,9 +16,9 @@ package org.citrusframework.openapi.validation; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_REQUEST_URI; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -37,13 +37,13 @@ import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestMethod; -import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -54,7 +54,7 @@ public class OpenApiRequestValidatorTest { private OpenApiSpecification openApiSpecificationMock; @Mock - private SwaggerOpenApiValidationContext swaggerOpenApiValidationContextMock; + private OpenApiValidationContext openApiValidationContextMock; @Mock private OpenApiInteractionValidator openApiInteractionValidatorMock; @@ -76,8 +76,8 @@ public class OpenApiRequestValidatorTest { public void beforeMethod() { mockCloseable = MockitoAnnotations.openMocks(this); - doReturn(swaggerOpenApiValidationContextMock).when(openApiSpecificationMock).getSwaggerOpenApiValidationContext(); - doReturn(openApiInteractionValidatorMock).when(swaggerOpenApiValidationContextMock).getOpenApiInteractionValidator(); + doReturn(openApiValidationContextMock).when(openApiSpecificationMock).getOpenApiValidationContext(); + doReturn(openApiInteractionValidatorMock).when(openApiValidationContextMock).getOpenApiInteractionValidator(); openApiRequestValidator = new OpenApiRequestValidator(openApiSpecificationMock); } @@ -87,22 +87,10 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test - public void shouldNotValidateWhenDisabled() { - // Given - openApiRequestValidator.setEnabled(false); - // When - openApiRequestValidator.validateRequest(operationPathAdapterMock, httpMessageMock); - // Then - Assert.assertFalse(openApiRequestValidator.isEnabled()); - verify(openApiInteractionValidatorMock, never()).validateRequest(any(Request.class)); - } - @Test public void shouldValidateRequestWithNoErrors() { // Given - openApiRequestValidator.setEnabled(true); - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) .thenReturn(validationReportMock); @@ -119,8 +107,7 @@ public void shouldValidateRequestWithNoErrors() { @Test(expectedExceptions = ValidationException.class) public void shouldValidateRequestWithErrors() { // Given - openApiRequestValidator.setEnabled(true); - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) .thenReturn(validationReportMock); @@ -145,7 +132,7 @@ public void shouldCreateRequestFromMessage() throws IOException { headers.put("simple", "s1"); when(httpMessageMock.getHeaders()).thenReturn(headers); - when(httpMessageMock.getHeader(HttpMessageHeaders.HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); when(httpMessageMock.getAccept()).thenReturn("application/json"); when(operationPathAdapterMock.contextPath()).thenReturn("/api"); @@ -167,4 +154,24 @@ public void shouldCreateRequestFromMessage() throws IOException { assertEquals(request.getRequestBody().get().toString(StandardCharsets.UTF_8), "payload"); } + @Test + public void shouldCreateFormRequestFromMessage() throws IOException { + // Given + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("name", "John Doe"); + formData.add("age", 30); + formData.add("city", "New York"); + + when(httpMessageMock.getPayload()).thenReturn(formData); + + when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); + when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); + + // When + Request request = openApiRequestValidator.createRequestFromMessage(operationPathAdapterMock, httpMessageMock); + + // Then + assertEquals(request.getRequestBody().get().toString(StandardCharsets.UTF_8), "name=John+Doe&age=30&city=New+York"); + } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java index cfccf76d92..2246b0c00f 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -19,7 +19,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -42,7 +41,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.http.HttpStatusCode; -import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -53,7 +51,7 @@ public class OpenApiResponseValidatorTest { private OpenApiSpecification openApiSpecificationMock; @Mock - private SwaggerOpenApiValidationContext swaggerOpenApiValidationContextMock; + private OpenApiValidationContext openApiValidationContextMock; @Mock private OpenApiInteractionValidator openApiInteractionValidatorMock; @@ -79,8 +77,8 @@ public class OpenApiResponseValidatorTest { public void beforeMethod() { mockCloseable = MockitoAnnotations.openMocks(this); - doReturn(swaggerOpenApiValidationContextMock).when(openApiSpecificationMock).getSwaggerOpenApiValidationContext(); - doReturn(openApiInteractionValidatorMock).when(swaggerOpenApiValidationContextMock).getOpenApiInteractionValidator(); + doReturn(openApiValidationContextMock).when(openApiSpecificationMock).getOpenApiValidationContext(); + doReturn(openApiInteractionValidatorMock).when(openApiValidationContextMock).getOpenApiInteractionValidator(); openApiResponseValidator = new OpenApiResponseValidator(openApiSpecificationMock); } @@ -90,21 +88,10 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test - public void shouldNotValidateWhenDisabled() { - // Given - openApiResponseValidator.setEnabled(false); - // When - openApiResponseValidator.validateResponse(operationPathAdapterMock, httpMessageMock); - // Then - Assert.assertFalse(openApiResponseValidator.isEnabled()); - verify(openApiInteractionValidatorMock, never()).validateResponse(anyString(), any(Method.class), any(Response.class)); - } @Test public void shouldValidateWithNoErrors() { // Given - openApiResponseValidator.setEnabled(true); when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(false); @@ -125,7 +112,6 @@ public void shouldValidateWithNoErrors() { @Test(expectedExceptions = ValidationException.class) public void shouldValidateWithErrors() { // Given - openApiResponseValidator.setEnabled(true); when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(true); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index 2fc0bb33bf..c18d7509dc 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -193,8 +193,6 @@ public void shouldLoadOpenApiClientActions() throws IOException { httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), - "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java index b151699c66..bcfee0463f 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java @@ -32,6 +32,7 @@ import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -124,10 +125,11 @@ public void shouldLoadOpenApiServerActions() { int actionIndex = 0; ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); @@ -162,10 +164,11 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index e81a89e63b..24757fb060 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -114,7 +114,7 @@ public void cleanupEndpoints() { } @Test - public void shouldLoadOpenApiClientActions() throws IOException { + public void shouldLoadOpenApiClientActions() { YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/openapi/yaml/openapi-client-test.yaml"); context.setVariable("port", port); @@ -188,8 +188,6 @@ public void shouldLoadOpenApiClientActions() throws IOException { httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), - "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java index 723609e773..b0edf652dc 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java @@ -32,6 +32,7 @@ import org.citrusframework.message.DefaultMessageQueue; import org.citrusframework.message.MessageHeaders; import org.citrusframework.message.MessageQueue; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; import org.citrusframework.spi.BindToRegistry; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.json.JsonMessageValidationContext; @@ -124,10 +125,11 @@ public void shouldLoadOpenApiServerActions() { int actionIndex = 0; ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); @@ -162,10 +164,11 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(sendMessageAction.getMessageProcessors().size(), 1); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 3); + Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); diff --git a/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java b/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java index 00c32339ae..d8e13ed643 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java +++ b/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java @@ -429,7 +429,7 @@ public static Set getTestFileNamePattern(String type) { * @param def the default value * @return first value encountered, which is not null. May return null, if default value is null. */ - private static String getPropertyEnvOrDefault(String prop, String env, String def) { + public static String getPropertyEnvOrDefault(String prop, String env, String def) { return getProperty(prop, getenv(env) != null ? getenv(env) : def); } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java b/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java index aa9ca41871..aaaed98d12 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java +++ b/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java @@ -16,6 +16,9 @@ package org.citrusframework.util; +import static java.lang.String.format; + +import jakarta.annotation.Nonnull; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -224,6 +227,7 @@ public static Object invokeMethod(Method method, Object target, Object... args) } } + @SuppressWarnings("java:S3011") public static void setField(Field f, Object instance, Object value) { try { if (!Modifier.isPublic(f.getModifiers()) && !f.canAccess(instance)) { @@ -235,6 +239,7 @@ public static void setField(Field f, Object instance, Object value) { } } + @SuppressWarnings("java:S3011") public static Object getField(Field f, Object instance) { try { if ((!Modifier.isPublic(f.getModifiers()) || @@ -253,4 +258,31 @@ public static Object getField(Field f, Object instance) { return null; } } + + /** + * Copies the values of all declared fields from a source object to a target object for the specified class. + */ + @SuppressWarnings("java:S3011") + public static void copyFields(@Nonnull Class clazz, @Nonnull Object source, @Nonnull Object target) { + Class currentClass = clazz; + + while (currentClass != null) { + Field[] fields = currentClass.getDeclaredFields(); + + for (Field field : fields) { + try { + field.setAccessible(true); + field.set(target, field.get(source)); + } catch (IllegalAccessException e) { + throw new CitrusRuntimeException(format( + "Unable to reflectively copy fields from source to target. clazz=%s sourceClass=%s targetClass=%s", + clazz, source.getClass(), target.getClass())); + } + } + + currentClass = currentClass.getSuperclass(); + } + + } + } diff --git a/core/citrus-api/src/test/java/org/citrusframework/util/ReflectionHelperTest.java b/core/citrus-api/src/test/java/org/citrusframework/util/ReflectionHelperTest.java new file mode 100644 index 0000000000..b31387a0f1 --- /dev/null +++ b/core/citrus-api/src/test/java/org/citrusframework/util/ReflectionHelperTest.java @@ -0,0 +1,47 @@ +package org.citrusframework.util; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class ReflectionHelperTest { + + @Test + public void copyFields() { + SubClass source = new SubClass("John Doe", 30, "Super John", 60); + + SubClass target = new SubClass(null, 0, null, 0); + + ReflectionHelper.copyFields(SubClass.class, source, target); + + Assert.assertEquals(target.name, "John Doe"); + Assert.assertEquals(target.age, 30); + + Assert.assertEquals(target.superName, "Super John"); + Assert.assertEquals(target.superAge, 60); + + } + + private static class SuperClass { + + String superName; + int superAge; + + public SuperClass(String superName, int superAge) { + this.superName = superName; + this.superAge = superAge; + } + } + + private static class SubClass extends SuperClass { + + String name; + int age; + + public SubClass(String name, int age, String superName, int superAge) { + super(superName, superAge); + this.name = name; + this.age = age; + } + } + +} diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java index ea89780675..5f064dc168 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java @@ -428,7 +428,7 @@ public MessageBuilder getMessageBuilder() { /** * Action builder. */ - public static final class Builder extends ReceiveMessageActionBuilder { + public static class Builder extends ReceiveMessageActionBuilder { /** * Fluent API action building entry method used in Java DSL. diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java index d91ae3d002..6283ea0ee7 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java @@ -378,6 +378,7 @@ public static Builder send(Endpoint messageEndpoint) { public static Builder send(String messageEndpointUri) { Builder builder = new Builder(); builder.endpoint(messageEndpointUri); + return builder; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 21cf207378..7b68e39ddb 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -16,6 +16,8 @@ package org.citrusframework.util; +import java.util.Locale; + /** * Utility helper class for Strings. */ @@ -34,6 +36,15 @@ public static boolean hasText(String str) { return str != null && !str.isBlank(); } + /** + * Helper method checks for null or blank String. + * @param str + * @return + */ + public static boolean hasNoText(String str) { + return !hasText(str); + } + /** * String helper checking for isEmpty String and adds null check on given parameter. */ @@ -41,6 +52,15 @@ public static boolean isEmpty(String str) { return str == null || str.isEmpty(); } + /** + * String helper checking for isEmpty String and adds null check on given parameter. + * @param str + * @return + */ + public static boolean isNotEmpty(String str) { + return !isEmpty(str); + } + public static String appendSegmentToUrlPath(String path, String segment) { if (path == null) { @@ -88,4 +108,21 @@ public static void trimTrailingComma(StringBuilder builder) { length = builder.length(); } } + + /** + * Converts the first letter of the given input string to uppercase while leaving + * the rest of the string unchanged. If the input string is empty or null, + * an empty string is returned. + * + * @param input The string to be converted to title case. It can be null or empty. + * @return the strnig in title case + */ + public static String titleCase(String input) { + if (input != null && !"".equals(input)) { + String firstLetter = input.substring(0, 1).toUpperCase(Locale.ROOT); + return input.length() == 1 ? firstLetter : firstLetter + input.substring(1); + } else { + return ""; + } + } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java index 85e223f2fe..d62bce85db 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java @@ -16,10 +16,13 @@ package org.citrusframework.validation; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Optional; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.util.StringUtils; @@ -74,8 +77,101 @@ public void validateHeader(String headerName, Object receivedValue, Object contr } if (logger.isDebugEnabled()) { - logger.debug("Validating header element: " + headerName + "='" + expectedValue + "': OK"); + logger.debug("Validating header element: %s='%s' : OK".formatted(headerName, expectedValue)); + } + } + + public void validateHeaderArray(String headerName, Object receivedValue, Object controlValue, TestContext context, HeaderValidationContext validationContext) { + Optional validator = getHeaderValidator(headerName, controlValue, context); + if (validator.isPresent()) { + validator.get().validateHeader(headerName, receivedValue, controlValue, context, validationContext); + return; } + + List receivedValues = toList(receivedValue); + List controlValues = toList(controlValue); + + // Convert and replace dynamic content for controlValue + List expectedValues = controlValues.stream() + .map(value -> context.getTypeConverter().convertIfNecessary(value, String.class)) + .map(context::replaceDynamicContentInString) + .toList(); + + // Process received values + if (receivedValue != null) { + List receivedValueStrings = receivedValues.stream() + .map(value -> context.getTypeConverter().convertIfNecessary(value, String.class)) + .toList(); + + List expectedValuesCopy = new ArrayList<>(expectedValues); + + // Iterate over received values and try to match with expected values + for (String receivedValueString : receivedValueStrings) { + + Iterator expectedIterator = expectedValuesCopy.iterator(); + boolean validated = validateExpected(headerName, context, receivedValueString, expectedIterator); + + if (!validated) { + throw new ValidationException(String.format("Values not equal for header element '%s', expected '%s' but was '%s'", + headerName, String.join(", ", expectedValues), receivedValueString)); + } + } + + if (!expectedValuesCopy.isEmpty()) { + throw new ValidationException(String.format("Values not equal for header element '%s', expected '%s' but was '%s'", + headerName, String.join(", ", expectedValues), String.join(", ", receivedValues))); + } + + } else if (!expectedValues.isEmpty()) { + throw new ValidationException(String.format("Values not equal for header element '%s', expected '%s' but was 'null'", + headerName, String.join(", ", expectedValues))); + } + + if (logger.isDebugEnabled()) { + logger.debug("Validating header element: %s='%s' : OK".formatted(headerName, String.join(", ", expectedValues))); + } + } + + private static boolean validateExpected(String headerName, TestContext context, + String receivedValueString, Iterator expectedIterator) { + boolean validated = false; + while (expectedIterator.hasNext()) { + String expectedValue = expectedIterator.next(); + + if (ValidationMatcherUtils.isValidationMatcherExpression(expectedValue)) { + try { + ValidationMatcherUtils.resolveValidationMatcher(headerName, receivedValueString, expectedValue, + context); + validated = true; + expectedIterator.remove(); // Remove matched value + break; + } catch (ValidationException e) { + // Ignore this exception and try other expected values + } + } else { + if (receivedValueString.equals(expectedValue)) { + validated = true; + expectedIterator.remove(); // Remove matched value + break; + } + } + } + return validated; + } + + private static List toList(Object value) { + List receivedValuesList; + if (value == null) { + receivedValuesList = Collections.emptyList(); + } else if (!(value instanceof List)) { + receivedValuesList = new ArrayList<>(); + receivedValuesList.add(value.toString()); + } else { + //noinspection unchecked + receivedValuesList = (List) value; + } + + return receivedValuesList; } @Override @@ -87,11 +183,7 @@ public boolean supports(String headerName, Class type) { * Combines header validators from multiple sources. Includes validators coming from reference resolver * and resource path lookup are added. * - * Then pick validator that explicitly supports the given header name or control value and return as optional. - * @param headerName - * @param controlValue - * @param context - * @return + *

    Then pick validator that explicitly supports the given header name or control value and return as optional. */ private static Optional getHeaderValidator(String headerName, Object controlValue, TestContext context) { // add validators from resource path lookup diff --git a/core/citrus-base/src/test/java/org/citrusframework/endpoint/AbstractEndpointBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/endpoint/AbstractEndpointBuilderTest.java index 0296245da3..195083fe57 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/endpoint/AbstractEndpointBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/endpoint/AbstractEndpointBuilderTest.java @@ -22,18 +22,19 @@ import org.citrusframework.annotations.CitrusEndpointProperty; import org.citrusframework.context.TestContextFactory; import org.mockito.Mockito; -import org.testng.Assert; import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + public class AbstractEndpointBuilderTest extends UnitTestSupport { @CitrusEndpoint( - name = "fooEndpoint", - properties = { - @CitrusEndpointProperty(name = "message", value = "Hello from Citrus!"), - @CitrusEndpointProperty(name = "number", value = "1", type = int.class), - @CitrusEndpointProperty(name = "person", value = "testPerson", type = TestEndpointBuilder.Person.class) - } + name = "fooEndpoint", + properties = { + @CitrusEndpointProperty(name = "message", value = "Hello from Citrus!"), + @CitrusEndpointProperty(name = "number", value = "1", type = int.class), + @CitrusEndpointProperty(name = "person", value = "testPerson", type = TestEndpointBuilder.Person.class) + } ) private Endpoint injected; @@ -52,10 +53,10 @@ protected TestContextFactory createTestContextFactory() { public void buildFromEndpointProperties() { CitrusEndpointAnnotations.injectEndpoints(this, context); - Assert.assertEquals(injected, endpointBuilder.mockEndpoint); - Assert.assertEquals(endpointBuilder.message, "Hello from Citrus!"); - Assert.assertEquals(endpointBuilder.number, 1); - Assert.assertEquals(endpointBuilder.person, person); + assertEquals(injected, endpointBuilder.mockEndpoint); + assertEquals(endpointBuilder.message, "Hello from Citrus!"); + assertEquals(endpointBuilder.number, 1); + assertEquals(endpointBuilder.person, person); } public static final class TestEndpointBuilder extends AbstractEndpointBuilder { diff --git a/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/annotation/DirectEndpointConfigParserTest.java b/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/annotation/DirectEndpointConfigParserTest.java index eefc5fbb3b..dc309940b9 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/annotation/DirectEndpointConfigParserTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/annotation/DirectEndpointConfigParserTest.java @@ -16,8 +16,6 @@ package org.citrusframework.endpoint.direct.annotation; -import java.util.Map; - import org.citrusframework.TestActor; import org.citrusframework.annotations.CitrusEndpoint; import org.citrusframework.annotations.CitrusEndpointAnnotations; @@ -35,6 +33,8 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.Map; + import static org.mockito.Mockito.when; public class DirectEndpointConfigParserTest { diff --git a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java index dbed312239..4d0e99f494 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java @@ -2,7 +2,11 @@ import static org.citrusframework.util.StringUtils.hasText; import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.quote; +import static org.citrusframework.util.StringUtils.trimTrailingComma; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import org.testng.annotations.DataProvider; @@ -53,4 +57,131 @@ public void isEmpty_returnsFalse_forText(String str) { public void isEmpty_returnsFalse_forBlankText(String str) { assertFalse(isEmpty(str)); } + + @Test + public void appendSegmentToPath() { + assertEquals(StringUtils.appendSegmentToUrlPath("s1", "s2"), "s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("s1/", "s2"), "s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("s1/", "/s2"), "s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("/s1", "/s2"), "/s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("/s1/", "/s2"), "/s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("/s1/", "/s2/"), "/s1/s2/"); + assertEquals(StringUtils.appendSegmentToUrlPath("/s1/", null), "/s1/"); + assertEquals(StringUtils.appendSegmentToUrlPath(null, "/s2/"), "/s2/"); + assertNull(StringUtils.appendSegmentToUrlPath(null, null)); + } + + @Test + public void testQuoteTrue() { + String input = "Hello, World!"; + String expected = "\"Hello, World!\""; + String result = quote(input, true); + + assertEquals(result, expected, "The text should be quoted."); + } + + @Test + public void testQuoteFalse() { + String input = "Hello, World!"; + String expected = "Hello, World!"; + String result = quote(input, false); + + assertEquals(result, expected, "The text should not be quoted."); + } + + @Test + public void testQuoteEmptyStringTrue() { + String input = ""; + String expected = "\"\""; + String result = quote(input, true); + + assertEquals(result, expected, "The empty text should be quoted."); + } + + @Test + public void testQuoteEmptyStringFalse() { + String input = ""; + String expected = ""; + String result = quote(input, false); + + assertEquals(result, expected, "The empty text should not be quoted."); + } + + @Test + public void testQuoteNullStringTrue() { + String input = null; + String expected = "\"null\""; + String result = quote(input, true); + + assertEquals(result, expected, "The null text should be treated as a string 'null'."); + } + + @Test + public void testQuoteNullStringFalse() { + assertNull(quote(null, false)); + } + + @DataProvider(name = "trimTrailingCommaDataProvider") + public Object[][] trimTrailingCommaDataProvider() { + return new Object[][]{ + {new StringBuilder("Example text, "), "Example text"}, + {new StringBuilder("No trailing comma "), "No trailing comma"}, + {new StringBuilder("No trailing comma,\n\t\n "), "No trailing comma"}, + {new StringBuilder("Trailing comma,"), "Trailing comma"}, + {new StringBuilder("Multiple commas and spaces,,, "), "Multiple commas and spaces,,"}, + {new StringBuilder("No trim needed"), "No trim needed"}, + {new StringBuilder(), ""} + }; + } + + @Test(dataProvider = "trimTrailingCommaDataProvider") + public void testTrimTrailingComma(StringBuilder input, String expected) { + trimTrailingComma(input); + assertEquals(input.toString(), expected); + } + + @Test + public void testTrimTrailingCommaOnlySpaces() { + StringBuilder builder = new StringBuilder(" "); + trimTrailingComma(builder); + assertEquals(builder.toString(), ""); + + builder = new StringBuilder(","); + trimTrailingComma(builder); + assertEquals(builder.toString(), ""); + + builder = new StringBuilder(", , "); + trimTrailingComma(builder); + assertEquals(builder.toString(), ", "); + } + + @Test + public void testTrimTrailingCommaWithNull() { + StringBuilder builder = new StringBuilder(); + trimTrailingComma(builder); + assertEquals(builder.toString(), ""); + } + + @DataProvider(name = "titleCaseData") + public Object[][] titleCaseData() { + return new Object[][]{ + {"hello", "Hello"}, + {"h", "H"}, + {"Hello", "Hello"}, + {null, ""}, + {"", ""}, + {"hello world", "Hello world"}, + {" hello", " hello"}, + {"1test", "1test"}, + {"!special", "!special"} + }; + } + + @Test(dataProvider = "titleCaseData") + public void testTitleCase(String input, String expected) { + String actual = StringUtils.titleCase(input); + assertEquals(actual, expected, + "The titleCase method did not return the expected result."); + } + } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java index 5ee0feb42b..b07b732015 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java @@ -30,6 +30,7 @@ import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.config.util.ValidateMessageParserUtil; import org.citrusframework.config.util.VariableExtractorParserUtil; +import org.citrusframework.util.StringUtils; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.context.SchemaValidationContext; @@ -62,11 +63,7 @@ public class ReceiveMessageActionParser extends AbstractMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - String endpointUri = element.getAttribute("endpoint"); - - if (!hasText(endpointUri)) { - throw new BeanCreationException("Endpoint reference must not be empty"); - } + String endpointUri = parseEndpoint(element); BeanDefinitionBuilder builder = parseComponent(element, parserContext); builder.addPropertyValue("name", element.getLocalName()); @@ -101,6 +98,15 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { return builder.getBeanDefinition(); } + protected String parseEndpoint(Element element) { + String endpointUri = element.getAttribute("endpoint"); + + if (!StringUtils.hasText(endpointUri)) { + throw new BeanCreationException("Endpoint reference must not be empty"); + } + return endpointUri; + } + /** * Parse message validation contexts. * @param messageElement @@ -267,7 +273,7 @@ private XmlMessageValidationContext getXmlMessageValidationContext(Element messa * @param messageElement The message element to get the configuration from * @param context The context to set the schema validation configuration to */ - private void addSchemaInformationToValidationContext(Element messageElement, SchemaValidationContext.Builder context) { + protected void addSchemaInformationToValidationContext(Element messageElement, SchemaValidationContext.Builder context) { String schemaValidation = messageElement.getAttribute("schema-validation"); if (hasText(schemaValidation)) { context.schemaValidation(parseBoolean(schemaValidation)); @@ -479,7 +485,11 @@ private void extractJsonPathValidateExpressions( * @return */ protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { - return BeanDefinitionBuilder.genericBeanDefinition(ReceiveMessageActionFactoryBean.class); + return BeanDefinitionBuilder.genericBeanDefinition(getMessageFactoryClass()); + } + + protected Class getMessageFactoryClass() { + return ReceiveMessageActionFactoryBean.class; } /** diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java index ec3f5ee57f..6e05883f0f 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java @@ -23,6 +23,7 @@ import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.config.util.BeanDefinitionParserUtils; +import org.citrusframework.message.MessageBuilder; import org.citrusframework.util.StringUtils; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.variable.VariableExtractor; @@ -41,11 +42,7 @@ public class SendMessageActionParser extends AbstractMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - String endpointUri = element.getAttribute("endpoint"); - - if (!StringUtils.hasText(endpointUri)) { - throw new BeanCreationException("Endpoint reference must not be empty"); - } + String endpointUri = parseEndpoint(element); BeanDefinitionBuilder builder = parseComponent(element, parserContext); builder.addPropertyValue("name", element.getLocalName()); @@ -108,6 +105,15 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { return builder.getBeanDefinition(); } + protected String parseEndpoint(Element element) { + String endpointUri = element.getAttribute("endpoint"); + + if (!StringUtils.hasText(endpointUri)) { + throw new BeanCreationException("Endpoint reference must not be empty"); + } + return endpointUri; + } + /** * Parse component returning generic bean definition. * @param element @@ -115,14 +121,13 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { * @return */ protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { - return BeanDefinitionBuilder.genericBeanDefinition(getBeanDefinitionClass()); + return BeanDefinitionBuilder.genericBeanDefinition(getMessageFactoryClass()); } /** * Gets the bean definition builder class. - * @return */ - protected Class> getBeanDefinitionClass() { + protected Class> getMessageFactoryClass() { return SendMessageActionFactoryBean.class; } @@ -131,7 +136,17 @@ protected BeanDefinitionBuilder parseComponent(Element element, ParserContext pa */ public static class SendMessageActionFactoryBean extends AbstractSendMessageActionFactoryBean { - private final SendMessageAction.Builder builder = new SendMessageAction.Builder(); + private final SendMessageAction.Builder builder; + + + public SendMessageActionFactoryBean() { + builder = new SendMessageAction.Builder(); + } + + public SendMessageActionFactoryBean(MessageBuilder messageBuilder) { + builder = new SendMessageAction.Builder(); + builder.message(messageBuilder); + } @Override public SendMessageAction getObject() throws Exception { diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java index 4970fe7936..9d93c11db2 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/client/HttpEndpointConfiguration.java @@ -16,9 +16,6 @@ package org.citrusframework.http.client; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; import org.citrusframework.endpoint.AbstractPollableEndpointConfiguration; import org.citrusframework.endpoint.resolver.DynamicEndpointUriResolver; @@ -41,6 +38,10 @@ import org.springframework.web.client.ResponseErrorHandler; import org.springframework.web.client.RestTemplate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * @since 1.4 */ @@ -102,6 +103,10 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura */ private boolean disableRedirectHandling = false; + /** Should handle http semicolon uri content e.g. for matrix encoded path variables */ + // TODO: Christoph Deppisch advise whether this is a reasonable approach to support matrix encoded path parameters + private boolean handleSemicolonPathContent = false; + /** Default status code returned by http server */ private int defaultStatusCode = HttpStatus.OK.value(); @@ -422,6 +427,24 @@ public void setDisableRedirectHandling(boolean disableRedirectHandling) { this.disableRedirectHandling = disableRedirectHandling; } + /** + * Gets the handleSemicolonPathContent. + * + * @return + */ + public boolean isHandleSemicolonPathContent() { + return handleSemicolonPathContent; + } + + /** + * Sets the handleSemicolonPathContent. + * + * @param handleSemicolonPathContent + */ + public void setHandleSemicolonPathContent(boolean handleSemicolonPathContent) { + this.handleSemicolonPathContent = handleSemicolonPathContent; + } + /** * Gets the errorHandler. * diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java index 3d8ce1b216..830d55cde2 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java @@ -48,6 +48,13 @@ public class HttpReceiveResponseActionParser extends ReceiveMessageActionParser @Override public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = createBeanDefinitionBuilder( + element, parserContext); + return builder.getBeanDefinition(); + } + + protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, + ParserContext parserContext) { BeanDefinitionBuilder builder = parseComponent(element, parserContext); builder.addPropertyValue("name", "http:" + element.getLocalName()); @@ -59,9 +66,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { builder.addPropertyValue("receiveTimeout", Long.valueOf(receiveTimeout)); } - if (!element.hasAttribute("uri") && !element.hasAttribute("client")) { - throw new BeanCreationException("Neither http request uri nor http client endpoint reference is given - invalid test action definition"); - } + validateEndpointConfiguration(element); if (element.hasAttribute("client")) { builder.addPropertyReference("endpoint", element.getAttribute("client")); @@ -130,7 +135,8 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { doParse(element, builder); - HttpMessageBuilder httpMessageBuilder = new HttpMessageBuilder(httpMessage); + HttpMessageBuilder httpMessageBuilder = createMessageBuilder( + httpMessage); DefaultMessageBuilder messageContentBuilder = constructMessageBuilder(body, builder); httpMessageBuilder.setName(messageContentBuilder.getName()); @@ -141,6 +147,28 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { builder.addPropertyValue("validationContexts", validationContexts); builder.addPropertyValue("variableExtractors", getVariableExtractors(element)); - return builder.getBeanDefinition(); + return builder; + } + + protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { + HttpMessageBuilder httpMessageBuilder = new HttpMessageBuilder(httpMessage); + return httpMessageBuilder; + } + + /** + * Validates the endpoint configuration for the given XML element. + *

    + * This method is designed to be overridden by subclasses if custom validation logic is required. + * By default, it checks whether the 'uri' or 'client' attributes are present in the element. + * If neither is found, it throws a {@link BeanCreationException} indicating an invalid test action definition. + *

    + * + * @param element the XML element representing the endpoint configuration to validate + * @throws BeanCreationException if neither 'uri' nor 'client' attributes are present + */ + protected void validateEndpointConfiguration(Element element) { + if (!element.hasAttribute("uri") && !element.hasAttribute("client")) { + throw new BeanCreationException("Neither http request uri nor http client endpoint reference is given - invalid test action definition"); + } } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java index 028d3c17f9..7e20f95750 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java @@ -44,6 +44,13 @@ public class HttpSendRequestActionParser extends SendMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinitionBuilder builder = createBeanDefinitionBuilder( + element, parserContext); + return builder.getBeanDefinition(); + } + + protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, + ParserContext parserContext) { BeanDefinitionBuilder builder = parseComponent(element, parserContext); builder.addPropertyValue("name", "http:" + element.getLocalName()); @@ -53,9 +60,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { HttpMessage httpMessage = new HttpMessage(); - if (!element.hasAttribute("uri") && !element.hasAttribute("client")) { - throw new BeanCreationException("Neither http request uri nor http client endpoint reference is given - invalid test action definition"); - } + validateEndpointConfiguration(element); if (element.hasAttribute("client")) { builder.addPropertyReference("endpoint", element.getAttribute("client")); @@ -69,7 +74,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { } } - Element requestElement = DomUtils.getChildElements(element).get(0); + Element requestElement = getRequestElement(element); httpMessage.method(HttpMethod.valueOf(requestElement.getLocalName().toUpperCase())); if (requestElement.hasAttribute("path")) { httpMessage.path(requestElement.getAttribute("path")); @@ -81,7 +86,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { httpMessage.queryParam(param.getAttribute("name"), param.getAttribute("value")); } - Element headers = DomUtils.getChildElementByTagName(requestElement, "headers"); + Element headers = getHeadersElement(requestElement); if (headers != null) { List headerElements = DomUtils.getChildElementsByTagName(headers, "header"); for (Object headerElement : headerElements) { @@ -141,7 +146,8 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { } } - HttpMessageBuilder httpMessageBuilder = new HttpMessageBuilder(httpMessage); + HttpMessageBuilder httpMessageBuilder = createMessageBuilder( + httpMessage); DefaultMessageBuilder messageContentBuilder = constructMessageBuilder(body, builder); httpMessageBuilder.setName(messageContentBuilder.getName()); @@ -156,7 +162,42 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { if (!variableExtractors.isEmpty()) { builder.addPropertyValue("variableExtractors", variableExtractors); } + return builder; + } - return builder.getBeanDefinition(); + protected Element getRequestElement(Element element) { + if (element.hasChildNodes()) { + return DomUtils.getChildElements(element).get(0); + } + throw new BeanCreationException("No request element specified for http send - invalid test action definition"); + } + + protected Element getHeadersElement(Element requestElement) { + Element headers = DomUtils.getChildElementByTagName(requestElement, "headers"); + return headers; + } + + /** + * This method is designed to be overridden by subclasses if a custom message builder is required. + */ + protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { + return new HttpMessageBuilder(httpMessage); + } + + /** + * Validates the endpoint configuration for the given XML element. + *

    + * This method is designed to be overridden by subclasses if custom validation logic is required. + * By default, it checks whether the 'uri' or 'client' attributes are present in the element. + * If neither is found, it throws a {@link BeanCreationException} indicating an invalid test action definition. + *

    + * + * @param element the XML element representing the endpoint configuration to validate + * @throws BeanCreationException if neither 'uri' nor 'client' attributes are present + */ + protected void validateEndpointConfiguration(Element element) { + if (!element.hasAttribute("uri") && !element.hasAttribute("client")) { + throw new BeanCreationException("Neither http request uri nor http client endpoint reference is given - invalid test action definition"); + } } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java index 9e3bb54f1d..aa62ab4f47 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java @@ -130,6 +130,7 @@ private ResponseEntity handleRequestInternal(HttpMethod method, HttpEntity HttpServletRequest servletRequest = ((ServletRequestAttributes) attributes).getRequest(); UrlPathHelper pathHelper = new UrlPathHelper(); + pathHelper.setRemoveSemicolonContent(!endpointConfiguration.isHandleSemicolonPathContent()); Enumeration allHeaders = servletRequest.getHeaderNames(); for (String headerName : CollectionUtils.toArray(allHeaders, new String[] {})) { diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java index 2988291f2c..8b1545e5d5 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java @@ -16,11 +16,12 @@ package org.citrusframework.http.message; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.util.StringUtils; @@ -42,41 +43,57 @@ public void validateHeader(String name, Object received, Object control, TestCon return; } - Map receiveParams = convertToMap(received); - Map controlParams = convertToMap(control); + // TODO Christoph Deppisch: I changed this to support multi lists, e.q. required for array query parameters. + // Not sure about consequences though. Therefore, i call a new method super.validateHeaderArray below. + // Maybe we should fix this in general. + Map receiveParams = convertToMap(received); + Map controlParams = convertToMap(control); - for (Map.Entry param : controlParams.entrySet()) { + for (Map.Entry param : controlParams.entrySet()) { if (!receiveParams.containsKey(param.getKey())) { throw new ValidationException("Validation failed: Query param '" + param.getKey() + "' is missing"); } - super.validateHeader(HttpMessageHeaders.HTTP_QUERY_PARAMS + "(" + param.getKey() + ")", receiveParams.get(param.getKey()), param.getValue(), context, validationContext); + super.validateHeaderArray(HttpMessageHeaders.HTTP_QUERY_PARAMS + "(" + param.getKey() + ")", receiveParams.get(param.getKey()), param.getValue(), context, validationContext); } + } /** - * Convert query string key-value expression to map. - * @param expression - * @return + * Convert query string key-value expression to map. Note, that there could be hamcrest matchers + * encoded in the expression. */ - private Map convertToMap(Object expression) { - if (expression instanceof Map) { - return (Map) expression; + private Map convertToMap(Object expression) { + + if (expression instanceof Map) { + return (Map) expression; } return Stream.of(Optional.ofNullable(expression) .map(Object::toString) .orElse("") .split(",")) - .map(keyValue -> keyValue.split("=")) - .filter(keyValue -> StringUtils.hasText(keyValue[0])) - .map(keyValue -> { - if (keyValue.length < 2) { - return new String[]{keyValue[0], ""}; + .map(keyValue -> keyValue.split("=")) + .filter(keyValue -> StringUtils.hasText(keyValue[0])) + .collect(Collectors.toMap( + keyValue -> keyValue[0], // Key function + keyValue -> + // Value function: if no value is present, use an empty string + (keyValue.length < 2 ? "" : keyValue[1]) + , + (existingValue, newValue) -> { // Merge function to handle duplicate keys + if (existingValue instanceof List) { + ((List) existingValue).add(newValue.toString()); + return existingValue; + } else { + List list = new ArrayList<>(); + list.add((String) existingValue); + list.add(newValue.toString()); + return list; } - return keyValue; - }) - .collect(Collectors.toMap(keyValue -> keyValue[0], keyValue -> keyValue[1])); + } + )); + } @Override diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java index 2333db5517..0592b890e9 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java @@ -250,6 +250,17 @@ public B handleCookies(boolean flag) { return self; } + /** + * Sets the handleCookies property. + * + * @param flag + * @return + */ + public B handleHandleSemicolonPathContent(boolean flag) { + endpoint.setHandleSemicolonPathContent(flag); + return self; + } + /** * Sets the default status code property. * diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java index dc71774c66..7f8edfdb4c 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java @@ -149,6 +149,11 @@ public class HttpServer extends AbstractServer { */ private boolean handleCookies = false; + /** + * Should handle matrix encoded path parameters + */ + private boolean handleSemicolonPathContent = false; + /** * Default status code returned by http server */ @@ -645,6 +650,25 @@ public void setHandleCookies(boolean handleCookies) { this.handleCookies = handleCookies; } + /** + * Gets the handleSemicolonPathContent. + * + * @return + */ + public boolean isHandleSemicolonPathContent() { + return handleSemicolonPathContent; + } + + /** + * Sets the handleSemicolonPathContent. + * + * @param handleSemicolonPathContent + */ + public void setHandleSemicolonPathContent(boolean handleSemicolonPathContent) { + this.handleSemicolonPathContent = handleSemicolonPathContent; + } + + /** * Gets the response cache size. * diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CitrusDispatcherServlet.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CitrusDispatcherServlet.java index 2631ca1db3..e2dd9c6b8e 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CitrusDispatcherServlet.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CitrusDispatcherServlet.java @@ -111,6 +111,7 @@ protected void configureMessageController(ApplicationContext context) { endpointConfiguration.setHeaderMapper(DefaultHttpHeaderMapper.inboundMapper()); endpointConfiguration.setHandleAttributeHeaders(httpServer.isHandleAttributeHeaders()); endpointConfiguration.setHandleCookies(httpServer.isHandleCookies()); + endpointConfiguration.setHandleSemicolonPathContent(httpServer.isHandleSemicolonPathContent()); endpointConfiguration.setDefaultStatusCode(httpServer.getDefaultStatusCode()); messageController.setEndpointConfiguration(endpointConfiguration); diff --git a/endpoints/citrus-http/src/main/resources/org/citrusframework/schema/citrus-http-testcase.xsd b/endpoints/citrus-http/src/main/resources/org/citrusframework/schema/citrus-http-testcase.xsd index c42b48b394..68825b37b1 100644 --- a/endpoints/citrus-http/src/main/resources/org/citrusframework/schema/citrus-http-testcase.xsd +++ b/endpoints/citrus-http/src/main/resources/org/citrusframework/schema/citrus-http-testcase.xsd @@ -22,179 +22,116 @@ - + Sends Http request as client to server. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Received Http response as client from server. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -206,131 +143,198 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + Receives Http request as server. - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Sends Http response as server to calling client. + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + - + + - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - Sends Http response as server to calling client. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java index ab37efc1c5..71dd7d6907 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java @@ -32,13 +32,8 @@ */ public class HttpQueryParamHeaderValidatorTest extends AbstractTestNGUnitTest { - private HttpQueryParamHeaderValidator validator = new HttpQueryParamHeaderValidator(); - private HeaderValidationContext validationContext = new HeaderValidationContext(); - - @Override - protected TestContextFactory createTestContextFactory() { - return TestContextFactory.newInstance(); - } + private final HttpQueryParamHeaderValidator validator = new HttpQueryParamHeaderValidator(); + private final HeaderValidationContext validationContext = new HeaderValidationContext(); @Test(dataProvider = "successData") public void testValidateHeader(Object receivedValue, Object controlValue) { @@ -51,6 +46,8 @@ public Object[][] successData() { new Object[] { "foobar", "@contains(foo)@" }, new Object[] { "foo=fooValue,bar=barValue", "foo=fooValue,bar=barValue" }, new Object[] { "foo=,bar=barValue", "foo=,bar=barValue" }, + new Object[] { "foo=1,foo=2,foo=3,bar=barValue", "foo=1,foo=2,foo=3,bar=barValue" }, + new Object[] { "foo=1,foo=2,foo=3,bar=barValue", "foo=3,foo=2,foo=1,bar=barValue" }, new Object[] { null, null }, new Object[] { Collections.singletonMap("key", "value"), Collections.singletonMap("key", "value") }, new Object[] { Collections.singletonMap("key", "value"), Collections.singletonMap("key", is("value")) } diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java index ed19e85aec..f1ae835e1c 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java @@ -18,6 +18,7 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; import static org.citrusframework.common.TestLoader.SPRING; diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java index 8e55806ada..cac94f67a8 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java @@ -19,12 +19,12 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.common.TestLoader; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; /** * @since 2.0 */ -@Test public class RmiDynamicEndpointIT extends TestNGCitrusSpringSupport { @CitrusTestSource(type = TestLoader.SPRING, name = "RmiDynamicEndpointIT") diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java index 9175809993..a7ae49082a 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java @@ -19,6 +19,7 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.common.TestLoader; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; /** diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java index e4de083396..52b3e88b98 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java @@ -25,6 +25,7 @@ import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.testng.annotations.Ignore; import org.testng.annotations.Test; import static org.citrusframework.actions.ReceiveMessageAction.Builder.receive; diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java index 324f897192..b673bada04 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java @@ -16,11 +16,15 @@ package org.citrusframework.rmi.server; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.reset; + import java.io.IOException; import java.rmi.Remote; import java.rmi.registry.Registry; import java.util.List; - import org.citrusframework.endpoint.EndpointAdapter; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; @@ -37,11 +41,6 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.reset; - /** * @since 2.5 */ diff --git a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/ReceiveSoapMessageAction.java b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/ReceiveSoapMessageAction.java index 4957debb01..679f300879 100644 --- a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/ReceiveSoapMessageAction.java +++ b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/ReceiveSoapMessageAction.java @@ -98,7 +98,7 @@ public SoapAttachmentValidator getAttachmentValidator() { /** * Action builder. */ - public static final class Builder extends ReceiveMessageActionBuilder { + public static class Builder extends ReceiveMessageActionBuilder { /** Soap message to receive */ private final SoapMessage soapMessage = new SoapMessage(); diff --git a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/SendSoapMessageAction.java b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/SendSoapMessageAction.java index 9f4a591ac2..2216336fb1 100644 --- a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/SendSoapMessageAction.java +++ b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/actions/SendSoapMessageAction.java @@ -139,7 +139,7 @@ public boolean isMtomEnabled() { /** * Action builder. */ - public static final class Builder extends SendSoapMessageBuilder { + public static class Builder extends SendSoapMessageBuilder { public Builder() { message(new StaticMessageBuilder(soapMessage)); diff --git a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/ReceiveSoapMessageActionParser.java b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/ReceiveSoapMessageActionParser.java index 446afe7518..f959ca124c 100644 --- a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/ReceiveSoapMessageActionParser.java +++ b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/ReceiveSoapMessageActionParser.java @@ -28,6 +28,7 @@ import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.ValidationContext; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction.Builder; import org.citrusframework.ws.message.SoapAttachment; import org.citrusframework.ws.message.SoapMessageHeaders; import org.citrusframework.ws.validation.SoapAttachmentValidator; @@ -44,7 +45,7 @@ public class ReceiveSoapMessageActionParser extends ReceiveMessageActionParser { @Override protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ReceiveSoapMessageActionFactoryBean.class); + BeanDefinitionBuilder builder = super.parseComponent(element, parserContext); List attachmentElements = DomUtils.getChildElementsByTagName(element, "attachment"); List attachments = new ArrayList<>(); @@ -62,6 +63,11 @@ protected BeanDefinitionBuilder parseComponent(Element element, ParserContext pa return builder; } + @Override + protected Class getMessageFactoryClass() { + return ReceiveSoapMessageActionFactoryBean.class; + } + @Override protected void parseHeaderElements(Element actionElement, DefaultMessageBuilder messageBuilder, List validationContexts) { super.parseHeaderElements(actionElement, messageBuilder, validationContexts); @@ -89,7 +95,15 @@ protected void parseHeaderElements(Element actionElement, DefaultMessageBuilder */ public static class ReceiveSoapMessageActionFactoryBean extends AbstractReceiveMessageActionFactoryBean { - private final ReceiveSoapMessageAction.Builder builder = new ReceiveSoapMessageAction.Builder(); + private final Builder builder; + + public ReceiveSoapMessageActionFactoryBean() { + this(new Builder()); + } + + public ReceiveSoapMessageActionFactoryBean(Builder builder) { + this.builder = builder; + } /** * Sets the control attachments. diff --git a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapFaultActionParser.java b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapFaultActionParser.java index 877469e157..11e811362d 100644 --- a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapFaultActionParser.java +++ b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapFaultActionParser.java @@ -108,7 +108,7 @@ private void parseFaultDetail(BeanDefinitionBuilder builder, Element faultElemen } @Override - protected Class getBeanDefinitionClass() { + protected Class getMessageFactoryClass() { return SendSoapFaultActionFactoryBean.class; } diff --git a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapMessageActionParser.java b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapMessageActionParser.java index 1bb724f17f..c918b1b546 100644 --- a/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapMessageActionParser.java +++ b/endpoints/citrus-ws/src/main/java/org/citrusframework/ws/config/xml/SendSoapMessageActionParser.java @@ -27,6 +27,7 @@ import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.ValidationContext; import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction.Builder; import org.citrusframework.ws.message.SoapAttachment; import org.citrusframework.ws.message.SoapMessageHeaders; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -82,7 +83,7 @@ protected void parseHeaderElements(Element actionElement, DefaultMessageBuilder } @Override - protected Class> getBeanDefinitionClass() { + protected Class> getMessageFactoryClass() { return SendSoapMessageActionFactoryBean.class; } @@ -91,7 +92,15 @@ protected void parseHeaderElements(Element actionElement, DefaultMessageBuilder */ public static class SendSoapMessageActionFactoryBean extends AbstractSendMessageActionFactoryBean { - private final SendSoapMessageAction.Builder builder = new SendSoapMessageAction.Builder(); + private final SendSoapMessageAction.Builder builder; + + public SendSoapMessageActionFactoryBean() { + this(new Builder()); + } + + public SendSoapMessageActionFactoryBean(SendSoapMessageAction.Builder builder) { + this.builder = builder; + } /** * Sets the control attachments. diff --git a/pom.xml b/pom.xml index 9eb6b5f59b..86e72604de 100644 --- a/pom.xml +++ b/pom.xml @@ -263,6 +263,7 @@ 1.1.10.7 2.3 6.2.2 + 3.4.1 4.0.11 6.4.1 3.0.3 diff --git a/test-api-generator/citrus-test-api-core/pom.xml b/test-api-generator/citrus-test-api-core/pom.xml new file mode 100644 index 0000000000..d0a8b248de --- /dev/null +++ b/test-api-generator/citrus-test-api-core/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + + citrus-test-api-generator + org.citrusframework + 4.4.0-SNAPSHOT + ../pom.xml + + + citrus-test-api-core + Citrus :: Test API Core + Citrus Test API Core + jar + + + + org.citrusframework + citrus-api + ${project.version} + + + org.citrusframework + citrus-http + ${project.version} + + + org.citrusframework + citrus-openapi + ${project.version} + + + org.citrusframework + citrus-ws + ${project.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + + + org.openapitools + openapi-generator + ${org.openapitools.version} + + + wsdl4j + wsdl4j + + + + + org.assertj + assertj-core + ${assertj.version} + test + + + org.citrusframework + citrus-junit5 + ${project.version} + test + + + org.citrusframework + citrus-validation-json + ${project.version} + test + + + commons-fileupload + commons-fileupload + 1.5 + test + + + + \ No newline at end of file diff --git a/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java similarity index 65% rename from core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java rename to test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java index 3231b622af..5ba5731245 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/testapi/ApiActionBuilderCustomizerService.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java @@ -14,16 +14,21 @@ * limitations under the License. */ -package org.citrusframework.testapi; +package org.citrusframework.openapi.testapi; -import org.citrusframework.TestAction; +import org.citrusframework.actions.ReceiveMessageAction.ReceiveMessageActionBuilder; import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; -import org.citrusframework.context.TestContext; /** * Implementors of this interface are used to customize the SendMessageActionBuilder with application specific information. E.g. cookies * or transactionIds. */ -public interface ApiActionBuilderCustomizerService { - > T build(GeneratedApi generatedApi, TestAction action, TestContext context, T builder); +public interface ApiActionBuilderCustomizer { + + default > void customizeRequestBuilder(GeneratedApi generatedApi, T builder) { + } + + default > void customizeResponseBuilder(GeneratedApi generatedApi, T builder) { + } + } diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java similarity index 88% rename from core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java rename to test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java index a37867188c..07c7bad723 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApi.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java @@ -14,10 +14,13 @@ * limitations under the License. */ -package org.citrusframework.testapi; +package org.citrusframework.openapi.testapi; +import java.util.List; import java.util.Map; +import org.citrusframework.endpoint.Endpoint; + /** * Interface representing a generated API from an OpenAPI specification. * Provides methods to retrieve metadata about the API such as title, version, @@ -58,4 +61,12 @@ public interface GeneratedApi { * where keys are extension names and values are extension values */ Map getApiInfoExtensions(); + + List getCustomizers(); + + /** + * Returns the endpoint of the generated api. + */ + Endpoint getEndpoint(); + } \ No newline at end of file diff --git a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiRequest.java similarity index 96% rename from core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java rename to test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiRequest.java index 1b86cc29b0..80409c72c9 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/testapi/GeneratedApiRequest.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiRequest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.citrusframework.testapi; +package org.citrusframework.openapi.testapi; /** * Interface representing a generated API request corresponding to an operation in an OpenAPI specification. diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java new file mode 100644 index 0000000000..ea7bbe63cd --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java @@ -0,0 +1,226 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import static java.util.Collections.emptyList; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.citrusframework.exceptions.CitrusRuntimeException; + +class OpenApiParameterFormatter { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final FormatParameters DEFAULT_FORMAT_PARAMETERS = new FormatParameters("", ","); + private static final FormatParameters DEFAULT_LABEL_FORMAT_PARAMETERS = new FormatParameters(".", ","); + private static final FormatParameters DEFAULT_LABEL_EXPLODED_PARAMETERS = new FormatParameters(".", "."); + + private OpenApiParameterFormatter() { + // Static access only. + } + + /** + * Formats a list of values as a single String based on the separator and other settings. + */ + static String formatArray(String parameterName, Object parameterValue , ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + List values = toList(parameterValue, isObject); + if (parameterStyle == ParameterStyle.DEEPOBJECT) { + return formatDeepObject(parameterName, values); + } + + FormatParameters formatParameters = determineFormatParameters(parameterName, parameterStyle, explode, + isObject); + + + if (isObject && explode) { + return formatParameters.prefix + explode(values, formatParameters.separator); + } else { + return formatParameters.prefix + values.stream() + .collect(Collectors.joining(formatParameters.separator)); + } + + } + + private static String formatDeepObject(String parameterName, List values) { + StringBuilder builder = new StringBuilder(); + for (int i=0;i matrixFormatParameters(parameterName, explode, isObject); + case LABEL -> labelFormatParameters(explode); + case FORM -> formFormatParameters(parameterName, explode, isObject); + case SIMPLE, DEEPOBJECT -> DEFAULT_FORMAT_PARAMETERS; + }; + } + + private static FormatParameters formFormatParameters(String parameterName, boolean explode, boolean isObject) { + if (explode) { + if (isObject) { + return new FormatParameters("", "&"); + } + return new FormatParameters(parameterName+"=", "&"+parameterName+"="); + } else { + return new FormatParameters(parameterName+"=", ","); + } + } + + private static FormatParameters labelFormatParameters(boolean explode) { + return explode ? DEFAULT_LABEL_EXPLODED_PARAMETERS : DEFAULT_LABEL_FORMAT_PARAMETERS; + } + + private static FormatParameters matrixFormatParameters(String parameterName, boolean explode, boolean isObject) { + String prefix; + String separator = ","; + if (explode) { + if (isObject) { + prefix = ";"; + separator = prefix; + } else { + prefix = ";" + parameterName + "="; + separator = prefix; + } + } else { + prefix = ";" + parameterName + "="; + } + + return new FormatParameters(prefix, separator); + } + + private static String explode(List values, String delimiter) { + return IntStream.range(0, values.size() / 2) + .mapToObj(i -> values.get(2 * i) + "=" + values.get(2 * i + 1)) + .collect(Collectors.joining(delimiter)); + } + + private static List toList(Object value, boolean isObject) { + + if (value == null) { + return emptyList(); + } + + if (value.getClass().isArray()) { + List list = new ArrayList<>(); + int length = Array.getLength(value); + for (int i = 0; i < length; i++) { + Object singleValue = Array.get(value, i); + list.add(singleValue.toString()); + } + return list; + } else if (value instanceof List list) { + return list.stream().map(Object::toString).toList(); + } else if (value instanceof Map map) { + return map.entrySet().stream() + .flatMap(entry -> Stream.of(entry.getKey().toString(), entry.getValue().toString())) + .toList(); + } else if (isObject && value instanceof String jsonString) { + return toList(convertJsonToMap(jsonString), true); + } else if (isObject) { + return toList(convertBeanToMap(value), true); + } else { + return List.of(value.toString()); + } + } + + public static Map convertJsonToMap(String jsonString) { + JsonNode rootNode; + try { + rootNode = objectMapper.readTree(jsonString); + } catch (JsonProcessingException e) { + throw new IllegalArgumentException("Unable to convert jsonString to JSON object.", e); + } + + if (!rootNode.isObject()) { + throw new IllegalArgumentException("The provided JSON is not a valid JSON object."); + } + + return convertNodeToMap((ObjectNode) rootNode); + } + + private static Map convertNodeToMap(ObjectNode objectNode) { + Map resultMap = new TreeMap<>(); + + Iterator> fields = objectNode.fields(); + while (fields.hasNext()) { + Map.Entry field = fields.next(); + JsonNode valueNode = field.getValue(); + + if (valueNode.isObject() || valueNode.isArray()) { + throw new IllegalArgumentException( + "Nested objects or arrays are not allowed in the JSON."); + } + resultMap.put(field.getKey(), valueNode.asText()); + } + + return resultMap; + } + + protected static Map convertBeanToMap(Object bean) { + Map map = new TreeMap<>(); + try { + for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo( + bean.getClass(), Object.class).getPropertyDescriptors()) { + String propertyName = propertyDescriptor.getName(); + Object propertyValue = propertyDescriptor.getReadMethod().invoke(bean); + if (propertyValue != null) { + map.put(propertyName, propertyValue); + } + } + } catch (IntrospectionException | IllegalAccessException | + InvocationTargetException e) { + throw new CitrusRuntimeException("Error converting bean to map: " + e.getMessage(), e); + } + return map; + } + + private record FormatParameters(String prefix, String separator) { + } + +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java new file mode 100644 index 0000000000..c5dc997d73 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java @@ -0,0 +1,25 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +public enum ParameterStyle { + SIMPLE, + LABEL, + MATRIX, + FORM, + DEEPOBJECT +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java new file mode 100644 index 0000000000..a87cdb3525 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java @@ -0,0 +1,72 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import java.util.List; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiSpecificationSource; +import org.citrusframework.openapi.util.OpenApiUtils; + +public class RestApiReceiveMessageActionBuilder extends + org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder { + + private final GeneratedApi generatedApi; + + private final List customizers; + + + public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, + String method, String path, String operationName, String statusCode) { + + super(new OpenApiSpecificationSource(openApiSpec), + OpenApiUtils.createFullPathOperationIdentifier(method, path), statusCode); + + this.generatedApi = generatedApi; + this.customizers = generatedApi.getCustomizers(); + + name(String.format("receive-%s", operationName)); + + endpoint(generatedApi.getEndpoint()); + } + + public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, + OpenApiSpecification openApiSpec, + OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage httpMessage, String method, + String path, String operationName) { + + super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, + OpenApiUtils.createFullPathOperationIdentifier(method, path)); + + + this.generatedApi = generatedApi; + this.customizers = generatedApi.getCustomizers(); + + name(String.format("receive-%s", operationName)); + + endpoint(generatedApi.getEndpoint()); + + } + + public GeneratedApi getGeneratedApi() { + return generatedApi; + } + + public List getCustomizers() { + return customizers; + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java new file mode 100644 index 0000000000..02b9ba53cd --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java @@ -0,0 +1,332 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import static java.lang.String.format; + +import jakarta.servlet.http.Cookie; +import java.lang.reflect.Array; +import java.net.URLEncoder; +import java.util.Base64; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiSpecificationSource; +import org.citrusframework.openapi.util.OpenApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.StringUtils; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class RestApiSendMessageActionBuilder extends + org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder { + + private final GeneratedApi generatedApi; + + private final List customizers; + + private final MultiValueMap formParameters = new LinkedMultiValueMap<>(); + + public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, + OpenApiSpecification openApiSpec, + String method, String path, String operationName) { + this(generatedApi, openApiSpec, new HttpMessage(), method, path, operationName); + } + + public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, + OpenApiSpecification openApiSpec, + HttpMessage httpMessage, String method, + String path, String operationName) { + + this(generatedApi, openApiSpec, + new TestApiClientRequestMessageBuilder(httpMessage, + new OpenApiSpecificationSource(openApiSpec), + OpenApiUtils.createFullPathOperationIdentifier(method, path)), httpMessage, method, path, + operationName); + } + + public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, + OpenApiSpecification openApiSpec, + TestApiClientRequestMessageBuilder messageBuilder, HttpMessage httpMessage, String method, + String path, String operationName) { + + super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, + OpenApiUtils.createFullPathOperationIdentifier(method, path)); + + this.generatedApi = generatedApi; + this.customizers = generatedApi.getCustomizers(); + + endpoint(generatedApi.getEndpoint()); + + httpMessage.path(path); + name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), + operationName)); + getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); + getMessageBuilderSupport().header("citrus_open_api_method", method); + getMessageBuilderSupport().header("citrus_open_api_path", path); + + } + + public GeneratedApi getGeneratedApi() { + return generatedApi; + } + + public List getCustomizers() { + return customizers; + } + + @Override + public final HttpClientRequestActionBuilder name(String name) { + return super.name(name); + } + + protected void pathParameter(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + ((TestApiClientRequestMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).pathParameter( + name, value, parameterStyle, explode, isObject); + + } + + protected void formParameter(String name, Object value) { + setFormParameter(name, value); + } + + protected void setFormParameter(String name, Object value) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + setParameter(formParameters::add, name, value); + } + + protected void queryParameter(final String name, Object value) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + setParameter((paramName, paramValue) -> super.queryParam(paramName, + paramValue != null ? paramValue.toString() : null), name, value); + } + + protected void queryParameter(final String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + String formatted = OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject); + String[] queryParamValues = formatted.split("&"); + for (String queryParamValue : queryParamValues) { + String[] keyValue = queryParamValue.split("="); + queryParameter(keyValue[0], keyValue[1]); + } + } + + protected void headerParameter(String name, Object value) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + setParameter( + (paramName, paramValue) -> getMessageBuilderSupport().header(paramName, paramValue), + name, value); + } + + protected void headerParameter(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + headerParameter(name, OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject)); + } + + protected void cookieParameter(String name, Object value) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + setParameter((paramName, paramValue) -> getMessageBuilderSupport().cookie( + (new Cookie(paramName, paramValue != null ? paramValue.toString() : null))), name, + value); + } + + protected void cookieParameter(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + if (value == null || StringUtils.isEmpty(value.toString())) { + return; + } + + String formatted = OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject); + String[] keyValue = formatted.split("="); + + // URL Encoding is mandatory especially in the case of multiple values, as multiple values + // are separated by a comma and a comma is not a valid character in cookies. + cookieParameter(keyValue[0], keyValue[1]); + } + + private void setParameter(BiConsumer parameterConsumer, + final String parameterName, Object parameterValue) { + if (parameterValue != null) { + if (byte[].class.isAssignableFrom(parameterValue.getClass())) { + // Pass through byte array + parameterConsumer.accept(parameterName, parameterValue); + } else if (parameterValue.getClass().isArray()) { + int length = Array.getLength(parameterValue); + for (int i = 0; i < length; i++) { + Object singleValue = Array.get(parameterValue, i); + parameterConsumer.accept(parameterName, singleValue); + } + } else if (parameterValue instanceof Collection collection) { + collection.forEach( + singleValue -> parameterConsumer.accept(parameterName, singleValue)); + } else { + parameterConsumer.accept(parameterName, parameterValue); + } + } + } + + @Override + public SendMessageAction doBuild() { + + if (!formParameters.isEmpty()) { + getMessageBuilderSupport().body(formParameters); + } + + return super.doBuild(); + } + + public static final class TestApiClientRequestMessageBuilder extends + OpenApiClientRequestMessageBuilder { + + private final Map pathParameters = new HashMap<>(); + + public TestApiClientRequestMessageBuilder(HttpMessage httpMessage, + OpenApiSpecificationSource openApiSpec, + String operationId) { + super(httpMessage, openApiSpec, operationId); + } + + public void pathParameter(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + if (value == null) { + throw new CitrusRuntimeException( + "Mandatory path parameter '%s' must not be null".formatted(name)); + } + pathParameters.put(name, + new ParameterData(name, value, parameterStyle, explode, isObject)); + } + + @Override + protected String getDefinedPathParameter(TestContext context, String name) { + ParameterData parameterData = pathParameters.get(name); + String formatted = name; + if (parameterData != null) { + formatted = OpenApiParameterFormatter.formatArray(name, parameterData.value, parameterData.parameterStyle, + parameterData.explode, parameterData.isObject); + } + + return context.replaceDynamicContentInString(formatted); + } + + @Override + public Message build(TestContext context, String messageType) { + HttpMessage message = (HttpMessage) super.build(context, messageType); + encodeArrayStyleCookies(message); + return message; + } + + private static void encodeArrayStyleCookies(HttpMessage message) { + if (message.getCookies() != null && !message.getCookies().isEmpty()) { + for (Cookie cookie : message.getCookies()) { + if (cookie.getValue().contains(",")) { + cookie.setValue( + URLEncoder.encode(cookie.getValue(), FileUtils.getDefaultCharset())); + } + } + } + } + } + + protected byte[] toBinary(Object object) { + if (object instanceof byte[] bytes) { + return bytes; + } else if (object instanceof Resource resource) { + return FileUtils.copyToByteArray(resource.getInputStream()); + } else if (object instanceof String string) { + + Resource resource = Resources.create(string); + if (resource != null && resource.exists()) { + return toBinary(resource); + } + + try { + return Base64.getDecoder().decode(string); + } catch (IllegalArgumentException e) { + // Ignore decoding failure and treat as regular string + } + return string.getBytes(FileUtils.getDefaultCharset()); + } + + throw new IllegalArgumentException( + "Cannot convert object to byte array. Only byte[], Resource, and String are supported: " + + object.getClass()); + } + + protected String getOrDefault(String value, String defaultValue, boolean base64Encode) { + + if (StringUtils.isEmpty(value) && StringUtils.isEmpty(defaultValue)) { + return null; + } + + if (StringUtils.isEmpty(value)) { + value = defaultValue; + } + + if (base64Encode) { + value = "citrus:encodeBase64('" + value + "')"; + } + + return value; + } + + public record ParameterData(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + } + +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java new file mode 100644 index 0000000000..cabbd162c7 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java @@ -0,0 +1,54 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import java.util.List; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; + +public class SoapApiReceiveMessageActionBuilder extends ReceiveSoapMessageAction.Builder { + + private final GeneratedApi generatedApi; + + private final List customizers; + + public SoapApiReceiveMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { + + super(); + this.generatedApi = generatedApi; + this.customizers = generatedApi.getCustomizers(); + + endpoint(generatedApi.getEndpoint()); + + name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), + soapAction)); + } + + public GeneratedApi getGeneratedApi() { + return generatedApi; + } + + public List getCustomizers() { + return customizers; + } + + + @Override + public ReceiveSoapMessageAction doBuild() { + return new ReceiveSoapMessageAction(this); + } + +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java new file mode 100644 index 0000000000..cd69a5c7f7 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java @@ -0,0 +1,49 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import java.util.List; +import org.citrusframework.ws.actions.SendSoapMessageAction.Builder; + +public class SoapApiSendMessageActionBuilder extends Builder { + + private final GeneratedApi generatedApi; + + private final List customizers; + + public SoapApiSendMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { + + super(); + this.generatedApi = generatedApi; + this.customizers = generatedApi.getCustomizers(); + + endpoint(generatedApi.getEndpoint()); + + name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), + soapAction)); + } + + public GeneratedApi getGeneratedApi() { + return generatedApi; + } + + public List getCustomizers() { + return customizers; + } + + +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java new file mode 100644 index 0000000000..a726e23cad --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java @@ -0,0 +1,51 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi; + +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.util.StringUtils; + +public class TestApiUtils { + + private TestApiUtils() { + //prevent instantiation of utility class + } + + public static void addBasicAuthHeader(String username, String password, HttpMessageBuilderSupport messageBuilderSupport) { + if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) { + messageBuilderSupport.header("Authorization", + "Basic citrus:encodeBase64(" + username + ":" + password + ")"); + } + } + + public static String mapXmlAttributeNameToJavaPropertyName(String attributeName) { + + if (StringUtils.isEmpty(attributeName)) { + return attributeName; + } + + if ("basicUsername".equals(attributeName)) { + return "withBasicAuthUsername"; + } else if ("basicPassword".equals(attributeName)) { + return "withBasicAuthPassword"; + } + + return attributeName; + + } + +} diff --git a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java new file mode 100644 index 0000000000..ab19fbf7a4 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java @@ -0,0 +1,73 @@ +package org.citrusframework.openapi.testapi; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.openapi.testapi.OpenApiParameterFormatter.formatArray; +import static org.citrusframework.openapi.testapi.ParameterStyle.DEEPOBJECT; +import static org.citrusframework.openapi.testapi.ParameterStyle.FORM; +import static org.citrusframework.openapi.testapi.ParameterStyle.LABEL; +import static org.citrusframework.openapi.testapi.ParameterStyle.MATRIX; +import static org.citrusframework.openapi.testapi.ParameterStyle.SIMPLE; + +import java.util.List; +import java.util.stream.Stream; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder.ParameterData; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class OpenApiParameterFormatterTest { + + private static final User USER = User.user().role("admin").firstName("Alex").build(); + private static final List LIST = List.of(3,4,5); + private static final Integer SINGLE = 5; + + static Stream format() { + return Stream.of( + Arguments.arguments("Simple/non exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, false, false), "5"), + Arguments.arguments("Simple/non exploded/non object/array", new ParameterData("id", LIST, SIMPLE, false, false), "3,4,5"), + Arguments.arguments("Simple/non exploded/Object/single", new ParameterData("id", USER, SIMPLE, false, true) , "firstName,Alex,role,admin"), + Arguments.arguments("Simple/exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, true, false), "5"), + Arguments.arguments("Simple/exploded/non object/array", new ParameterData("id", LIST, SIMPLE, true, false), "3,4,5"), + Arguments.arguments("Simple/exploded/Object/single", new ParameterData("id", USER, SIMPLE, true, true) , "firstName=Alex,role=admin"), + Arguments.arguments("Label/non exploded/non object/single", new ParameterData("id", SINGLE, LABEL, false, false), ".5"), + Arguments.arguments("Label/non exploded/non object/array", new ParameterData("id", LIST, LABEL, false, false), ".3,4,5"), + Arguments.arguments("Label/non exploded/Object/single", new ParameterData("id", USER, LABEL, false, true) , ".firstName,Alex,role,admin"), + Arguments.arguments("Label/exploded/non object/single", new ParameterData("id", SINGLE, LABEL, true, false), ".5"), + Arguments.arguments("Label/exploded/non object/array", new ParameterData("id", LIST, LABEL, true, false), ".3.4.5"), + Arguments.arguments("Label/exploded/Object/single", new ParameterData("id", USER, LABEL, true, true) , ".firstName=Alex.role=admin"), + Arguments.arguments("Matrix/non exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, false, false), ";id=5"), + Arguments.arguments("Matrix/non exploded/non object/array", new ParameterData("id", LIST, MATRIX, false, false), ";id=3,4,5"), + Arguments.arguments("Matrix/non exploded/Object/single", new ParameterData("id", USER, MATRIX, false, true) , ";id=firstName,Alex,role,admin"), + Arguments.arguments("Matrix/exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, true, false), ";id=5"), + Arguments.arguments("Matrix/exploded/non object/array", new ParameterData("id", LIST, MATRIX, true, false), ";id=3;id=4;id=5"), + Arguments.arguments("Matrix/exploded/Object/single", new ParameterData("id", USER, MATRIX, true, true) , ";firstName=Alex;role=admin"), + Arguments.arguments("Form/non exploded/non object/single", new ParameterData("id", SINGLE, FORM, false, false) , "id=5"), + Arguments.arguments("Form/non exploded/non object/array", new ParameterData("id", LIST, FORM, false, false) , "id=3,4,5"), + Arguments.arguments("Form/non exploded/object/single", new ParameterData("id", USER, FORM, false, true) , "id=firstName,Alex,role,admin"), + Arguments.arguments("Form/exploded/non object/single", new ParameterData("id", SINGLE, FORM, true, false) , "id=5"), + Arguments.arguments("Form/exploded/non object/array", new ParameterData("id", LIST, FORM, true, false) , "id=3&id=4&id=5"), + Arguments.arguments("Form/exploded/object/single", new ParameterData("id", USER, FORM, true, true) , "firstName=Alex&role=admin"), + Arguments.arguments("DeepObject/exploded/object/single", new ParameterData("id", USER, DEEPOBJECT, true, true) , "id[firstName]=Alex&id[role]=admin") + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource + void format(String name, ParameterData parameterData, String expected) { + assertThat(formatArray(parameterData.name(), parameterData.value(), parameterData.parameterStyle(), parameterData.explode(), + parameterData.isObject())).isEqualTo(expected); + } + + @Getter + @Setter + @AllArgsConstructor + @Builder(builderMethodName = "user") + private static class User { + String role; + String firstName; + } +} diff --git a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java new file mode 100644 index 0000000000..660130ba12 --- /dev/null +++ b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java @@ -0,0 +1,68 @@ +package org.citrusframework.openapi.testapi; + +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.junit.jupiter.api.Test; + +class TestApiUtilsTest { + + @Test + void shouldAddBasicAuthHeaderWhenUsernameAndPasswordAreProvided() { + // Given + String username = "user"; + String password = "pass"; + HttpMessageBuilderSupport messageBuilderSupport = mock(HttpMessageBuilderSupport.class); + + // When + TestApiUtils.addBasicAuthHeader(username, password, messageBuilderSupport); + + // Then + verify(messageBuilderSupport).header("Authorization", "Basic citrus:encodeBase64(user:pass)"); + } + + @Test + void shouldNotAddBasicAuthHeaderWhenUsernameIsEmpty() { + // Given + String username = ""; + String password = "pass"; + HttpMessageBuilderSupport messageBuilderSupport = mock(HttpMessageBuilderSupport.class); + + // When + TestApiUtils.addBasicAuthHeader(username, password, messageBuilderSupport); + + // Then + verify(messageBuilderSupport, never()).header(anyString(), anyString()); + } + + @Test + void shouldNotAddBasicAuthHeaderWhenPasswordIsEmpty() { + // Given + String username = "user"; + String password = ""; + HttpMessageBuilderSupport messageBuilderSupport = mock(HttpMessageBuilderSupport.class); + + // When + TestApiUtils.addBasicAuthHeader(username, password, messageBuilderSupport); + + // Then + verify(messageBuilderSupport, never()).header(anyString(), anyString()); + } + + @Test + void shouldNotAddBasicAuthHeaderWhenBothUsernameAndPasswordAreEmpty() { + // Given + String username = ""; + String password = ""; + HttpMessageBuilderSupport messageBuilderSupport = mock(HttpMessageBuilderSupport.class); + + // When + TestApiUtils.addBasicAuthHeader(username, password, messageBuilderSupport); + + // Then + verify(messageBuilderSupport, never()).header(anyString(), anyString()); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/README.md b/test-api-generator/citrus-test-api-generator-core/README.md new file mode 100644 index 0000000000..a60957b2c7 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/README.md @@ -0,0 +1,102 @@ +TODO +TODO: document properties for security and others +TODO: document default properties for the endpoint -> prefix with lowercase + +## Generated Java Code for API Testing + +The code generator creates Java classes from an OpenAPI specification to facilitate API testing using the Citrus framework. +The Java classes represent Citrus Send and Receive ActionBuilders for each operation of the OpenAPI. Each builder provides +setter for the actual operation parameters. In general a type-safe method is provided, that reflects the correct operation type. +In addition a setter in string representation is provided to allow for citrus dynamic content setting using string expressions. +For each builder a specific operation is added to ... +A type-safe method providing the correct java type and a non type-safe method using a string type, allowing the usage of citrus expressions for the respective content. + +1. **Type-Safe Parameter Method**: This method accepts the required parameters directly. +2. **String-Based Parameter Method**: This method accepts parameters as strings to allow for dynamic content. + +Method names of non type-safe methods are prepended with a `$`. This is mainly to avoid conflicts for + +### Structure of the Generated API Class + +For each API operation, the generated class includes: + +1. **Builder with Type-Safe Required Parameters**: A method that takes the required parameters directly and returns a builder configured with these parameters. + +2. **Builder with Parameters as Strings**: A method that takes parameters as strings, allowing dynamic replacements via the Citrus framework. The method name is suffixed with `$` to distinguish it from the type-safe version. + +### Example + +Consider an operation to delete a pet with the following parameter: +- `petId` (required, type `Long`) + +The generated Java API class might look like this: + +```java +public class PetsApi { + + /** + * Builder with type safe required parameters. + */ + public DeletePetRequestActionBuilder sendDeletePet(Long petId) { + DeletePetRequestActionBuilder builder = new DeletePetRequestActionBuilder(openApiSpecification, petId); + builder.endpoint(httpClient); + return builder; + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public DeletePetRequestActionBuilder sendDeletePet$(String petIdExpression) { + DeletePetRequestActionBuilder builder = new DeletePetRequestActionBuilder(petIdExpression, openApiSpecification); + builder.endpoint(httpClient); + return builder; + } +} +``` + +## Known issues + +## Validation + +It is known, that the used OpenAPI validator is not able to validate certain situations. +E.g. certain array encoding situations related to object encoding + +## Variable processing + +Processing of variables in case of parameter serialization, in some cases causes problems. For example, it +is not possible to assign a json string to a variable and path it into an object into the current +parameter serialization mechanism. This expects a real json, which cannot be resolved. To solve this issue, +serialization of arrays must happen as late as possible. Maybe it is feasible to create an OpenApiEndpointConfiguration +with a respective message converter. + +## Handling of Array Parameters + +Currently, all array parameters are handled in explode mode, regardless of the `explode` setting specified +in the API definition. This means that each item in an array will be serialized as a separate query +parameter, even if the `explode` setting is set to `false` in the OpenAPI specification. + +### Example + +Suppose the OpenAPI specification defines an array parameter named `status` with the following attributes: + +```yaml +parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: false + explode: false + schema: + type: string + default: available + enum: + - available + - pending + - sold +``` + +Despite the explode: false setting, the request will be serialized as follows: + +``` +?status=available&status=pending&status=sold +``` \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index 3af2a0689e..bb9340ac74 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.3.0-SNAPSHOT + 4.4.0-SNAPSHOT ../pom.xml @@ -41,13 +41,35 @@ org.citrusframework citrus-spring ${project.version} - test org.citrusframework citrus-ws ${project.version} + + org.citrusframework + citrus-test-api-core + ${project.version} + + + org.citrusframework + citrus-groovy + ${project.version} + test + + + + org.citrusframework + citrus-validation-groovy + ${project.version} + test + + + org.citrusframework + citrus-test-api-spring + ${project.version} + org.assertj @@ -88,6 +110,12 @@ ${spring.boot.version} test + + commons-fileupload + commons-fileupload + 1.5 + test + @@ -98,7 +126,7 @@ ${maven.helper.plugin.version} - add-generated-specs + add-generated-test-resources generate-test-resources add-test-resource @@ -113,7 +141,7 @@ - add-generated-classes + add-generated-test-classes generate-test-sources add-test-source @@ -215,56 +243,54 @@ generate - ${project.basedir}/src/test/resources/apis/petstore.yaml + ${project.basedir}/src/test/resources/apis/petstore-v3.yaml org.citrusframework.openapi.generator.rest.petstore org.citrusframework.openapi.generator.rest.petstore.request org.citrusframework.openapi.generator.rest.petstore.model - PetStore - petStoreEndpoint + petStore + petstore.endpoint - generate-openapi-files-for-soap + generate-openapi-petstore-extended-files compile generate - ${project.basedir}/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml + ${project.basedir}/src/test/resources/apis/petstore-extended-v3.yaml - SOAP - org.citrusframework.openapi.generator.soap.bookservice - org.citrusframework.openapi.generator.soap.bookservice.request - org.citrusframework.openapi.generator.soap.bookservice.model - SoapSample - OpenApiFromWsdl - soapSampleEndpoint + org.citrusframework.openapi.generator.rest.extpetstore + org.citrusframework.openapi.generator.rest.extpetstore.request + org.citrusframework.openapi.generator.rest.extpetstore.model + ExtPetStore + extpetstore.endpoint - - - generate-openapi-multiparttest-files + generate-openapi-files-for-soap compile generate - ${project.basedir}/src/test/resources/apis/multiparttest-rest-resource.yaml + ${project.basedir}/src/test/resources/apis/BookService-generated.yaml - org.citrusframework.openapi.generator.rest.multiparttest - org.citrusframework.openapi.generator.rest.multiparttest.request - org.citrusframework.openapi.generator.rest.multiparttest.model - MultipartTest - multipartTestEndpoint + SOAP + org.citrusframework.openapi.generator.soap.bookservice + org.citrusframework.openapi.generator.soap.bookservice.request + org.citrusframework.openapi.generator.soap.bookservice.model + BookService + bookstore.endpoint + diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java new file mode 100644 index 0000000000..50ae1d21b9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java @@ -0,0 +1,595 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.generator; + +import static java.lang.Boolean.TRUE; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toMap; +import static org.citrusframework.util.ReflectionHelper.copyFields; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; +import static org.citrusframework.util.StringUtils.titleCase; +import static org.openapitools.codegen.CliOption.newString; +import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; +import static org.openapitools.codegen.utils.StringUtils.camelize; + +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.servers.Server; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import lombok.Getter; +import lombok.Setter; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenSecurity; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.languages.AbstractJavaCodegen; +import org.openapitools.codegen.model.ModelMap; +import org.openapitools.codegen.model.OperationMap; +import org.openapitools.codegen.model.OperationsMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Getter +@Setter +public class CitrusJavaCodegen extends AbstractJavaCodegen { + + private static final Logger logger = LoggerFactory.getLogger(CitrusJavaCodegen.class); + + public static final String CODEGEN_NAME = "java-citrus"; + + public static final String API_TYPE_REST = "REST"; + public static final String API_TYPE_SOAP = "SOAP"; + + public static final String API_ENDPOINT = "apiEndpoint"; + public static final String API_TYPE = "apiType"; + public static final String GENERATED_SCHEMA_FOLDER = "generatedSchemaFolder"; + public static final String PREFIX = "prefix"; + public static final String RESOURCE_FOLDER = "resourceFolder"; + public static final String SOURCE_FOLDER = "sourceFolder"; + public static final String TARGET_XMLNS_NAMESPACE = "targetXmlnsNamespace"; + public static final String REQUEST_BUILDER_CLASS = "requestBuilderClass"; + public static final String RESPONSE_BUILDER_CLASS = "responseBuilderClass"; + public static final String REQUEST_BUILDER_CLASS_NAME = "requestBuilderClassName"; + public static final String RESPONSE_BUILDER_CLASS_NAME = "responseBuilderClassName"; + + protected String apiPrefix = "Api"; + + protected String httpClient = API_ENDPOINT; + + protected String resourceFolder = + "src" + File.separator + "main" + File.separator + "resources"; + protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; + protected String targetXmlnsNamespace; + + protected String apiVersion = "1.0.0"; + private String invokerFolder; + private String springFolder; + private String schemaFolder; + + public CitrusJavaCodegen() { + super(); + + templateDir = CODEGEN_NAME; + + configureAdditionalProperties(); + configureReservedWords(); + configureCliOptions(); + configureTypeMappings(); + } + + private void configureAdditionalProperties() { + additionalProperties.put("apiVersion", apiVersion); + additionalProperties.put(API_TYPE, API_TYPE_REST); + additionalProperties.put("useJakartaEe", true); + } + + private void configureReservedWords() { + Set reservedWordsTemp = reservedWords(); + reservedWordsTemp.addAll( + asList( + "name", + "description", + "httpClient", + "message", + "endpoint", + "validate", + "validator", + "validators", + "process", + "selector", + "transform", + "build", + "actor", + "process") + ); + setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); + } + + private void configureCliOptions() { + cliOptions.add( + newString(API_ENDPOINT, + "Which http client should be used (default " + httpClient + ").")); + cliOptions.add( + newString(API_TYPE, + "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" + ) + ); + cliOptions.add( + newString(GENERATED_SCHEMA_FOLDER, + "The schema output directory (default " + generatedSchemaFolder + ").") + ); + cliOptions.add( + newString(PREFIX, + "Add a prefix before the name of the files. First character should be upper case (default " + + apiPrefix + ")." + ) + ); + cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); + cliOptions.add( + newString(RESOURCE_FOLDER, + "Where the resource files are emitted (default " + resourceFolder + ").")); + cliOptions.add( + newString(TARGET_XMLNS_NAMESPACE, + "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") + ); + } + + private void configureTypeMappings() { + this.typeMapping.put("binary", "Resource"); + this.typeMapping.put("file", "Resource"); + } + + /** + * Returns human-friendly help for the generator. Provide the consumer with help tips, + * parameters here + * + * @return A string value for the help message + */ + @Override + public String getHelp() { + return "Generates citrus api requests."; + } + + /** + * Configures a friendly name for the generator. This will be used by the generator to select + * the library with the -g flag. + * + * @return the friendly name for the generator + */ + @Override + public String getName() { + return CODEGEN_NAME; + } + + /** + * Configures the type of generator. + * + * @return the CodegenType for this generator + * @see org.openapitools.codegen.CodegenType + */ + @Override + public CodegenType getTag() { + return CodegenType.CLIENT; + } + + @Override + public void processOpts() { + super.processOpts(); + setupEndpoint(); + setupApiPrefix(); + setupNamespace(); + setupFolders(); + setupApiType(); + addDefaultSupportingFiles(); + writeApiToResourceFolder(); + } + + private void setupEndpoint() { + if (additionalProperties.containsKey(API_ENDPOINT)) { + this.setHttpClient(additionalProperties.get(API_ENDPOINT).toString()); + } + additionalProperties.put(API_ENDPOINT, httpClient); + } + + private void setupApiPrefix() { + if (additionalProperties.containsKey(PREFIX)) { + this.setApiPrefix(additionalProperties.get(PREFIX).toString()); + additionalProperties.put(PREFIX, apiPrefix); + additionalProperties.put(PREFIX + "LowerCase", apiPrefix.toLowerCase()); + } else { + logger.warn( + "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", + PREFIX); + apiPrefix = ""; + } + } + + private void setupNamespace() { + if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { + this.setTargetXmlnsNamespace( + additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); + } else { + this.targetXmlnsNamespace = format( + "http://www.citrusframework.org/citrus-test-schema/%s-api", + apiPrefix.toLowerCase()); + } + additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); + } + + private void setupFolders() { + if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { + this.setGeneratedSchemaFolder( + additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); + } + additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); + + if (additionalProperties.containsKey(RESOURCE_FOLDER)) { + this.setResourceFolder(additionalProperties.get(RESOURCE_FOLDER).toString()); + } + additionalProperties.put(RESOURCE_FOLDER, resourceFolder); + + invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", + File.separator); + springFolder = invokerFolder + File.separator + "spring"; + schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; + } + + private void setupApiType() { + Object apiType = additionalProperties.get(API_TYPE); + if (API_TYPE_REST.equals(apiType)) { + setupRestApiType(springFolder, schemaFolder); + } else if (API_TYPE_SOAP.equals(apiType)) { + setupSoapApiType(springFolder, schemaFolder); + } else { + throw new IllegalArgumentException(format("Unknown API_TYPE: '%s'", apiType)); + } + } + + private void setupSoapApiType(String springFolder, String schemaFolder) { + additionalProperties.put(REQUEST_BUILDER_CLASS, + SoapApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, + SoapApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, + SoapApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, + SoapApiReceiveMessageActionBuilder.class.getSimpleName()); + additionalProperties.put("isRest", false); + additionalProperties.put("isSoap", true); + addSoapSupportingFiles(springFolder, schemaFolder); + } + + private void setupRestApiType(String springFolder, String schemaFolder) { + additionalProperties.put(REQUEST_BUILDER_CLASS, + RestApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, + RestApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, + RestApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, + RestApiReceiveMessageActionBuilder.class.getSimpleName()); + additionalProperties.put("isRest", true); + additionalProperties.put("isSoap", false); + + addRestSupportingFiles(springFolder, schemaFolder); + } + + /** + * Store a copy of the source open api as resource. + */ + private void writeApiToResourceFolder() { + + String directoryPath = appendSegmentToUrlPath(getOutputDir(), getResourceFolder()); + directoryPath = appendSegmentToUrlPath(directoryPath, + invokerPackage.replace('.', File.separatorChar)); + + String filename = getApiPrefix() + "_openApi.yaml"; + + File directory = new File(directoryPath); + if (!directory.exists() && !directory.mkdirs()) { + throw new CitrusRuntimeException("Unable to create directory for api resource!"); + } + + File file = new File(directory, filename); + + try (FileWriter writer = new FileWriter(file)) { + String yamlContent = Yaml.pretty(openAPI); + writer.write(yamlContent); + } catch (IOException e) { + throw new CitrusRuntimeException( + "Unable to write OpenAPI to resource folder: " + file.getAbsolutePath()); + } + } + + @Override + public void preprocessOpenAPI(OpenAPI openAPI) { + super.preprocessOpenAPI(openAPI); + + Info info = openAPI.getInfo(); + Map extensions = info.getExtensions(); + if (extensions != null) { + additionalProperties.putAll(extensions); + + Map infoExtensions = extensions.entrySet().stream() + .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) + .collect(toMap(Entry::getKey, Entry::getValue)); + additionalProperties.put("infoExtensions", infoExtensions); + } + } + + private void addRestSupportingFiles(String springFolder, + String schemaFolder) { + + supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder, + titleCase(apiPrefix) + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, + apiPrefix.toLowerCase() + "-api.xsd")); + } + + private void addSoapSupportingFiles(String springFolder, String schemaFolder) { + // Remove the default api template file + apiTemplateFiles().remove("api.mustache"); + apiTemplateFiles().put("api_soap.mustache", ".java"); + + supportingFiles.add(new SupportingFile("namespace_handler_soap.mustache", springFolder, + titleCase(apiPrefix) + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, + apiPrefix.toLowerCase() + "-api.xsd")); + } + + private void addDefaultSupportingFiles() { + supportingFiles.add(new SupportingFile("api_locator.mustache", invokerFolder, + titleCase(apiPrefix) + ".java")); + supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, + titleCase(apiPrefix) + "BeanConfiguration.java")); + } + + @Override + public CodegenParameter fromRequestBody(RequestBody body, Set imports, + String bodyParameterName) { + CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); + return convertToCustomCodegenParameter(codegenParameter); + } + + @Override + public CodegenParameter fromFormProperty(String name, Schema propertySchema, + Set imports) { + CodegenParameter codegenParameter = super.fromFormProperty(name, propertySchema, imports); + return convertToCustomCodegenParameter(codegenParameter); + } + + @Override + public CodegenParameter fromParameter(Parameter parameter, Set imports) { + CodegenParameter codegenParameter = super.fromParameter(parameter, imports); + + if ("File".equals(codegenParameter.dataType)) { + codegenParameter.dataType = "Resource"; + } + + return convertToCustomCodegenParameter(codegenParameter); + } + + /** + * Converts given codegenParameter to a custom {@link CustomCodegenParameter} to provide + * additional derived properties. + */ + private CustomCodegenParameter convertToCustomCodegenParameter( + CodegenParameter codegenParameter) { + CustomCodegenParameter customCodegenParameter = new CustomCodegenParameter(); + copyFields(CodegenParameter.class, codegenParameter, customCodegenParameter); + + customCodegenParameter.isBaseTypeString = codegenParameter.isString || "String".equals( + codegenParameter.baseType); + + return customCodegenParameter; + } + + @Override + public CodegenOperation fromOperation(String path, + String httpMethod, + Operation operation, + List servers) { + CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); + return convertToCustomCodegenOperation(op); + + } + + /** + * Converts given codegenOperation to a custom {@link CustomCodegenOperation} to provide + * additional derived properties. + */ + private CustomCodegenOperation convertToCustomCodegenOperation( + CodegenOperation codegenOperation) { + + CustomCodegenOperation customOperation = new CustomCodegenOperation(); + + copyFields(CodegenOperation.class, codegenOperation, customOperation); + + customOperation.requiredNonBodyParams.addAll(customOperation.requiredParams + .stream() + .filter(param -> !param.isBodyParam).toList()); + + customOperation.needsConstructorWithAllStringParameter = + !customOperation.requiredParams.isEmpty() && + customOperation.requiredParams + .stream() + .anyMatch( + param -> !param.isBodyParam && !"String".equals(param.dataType)); + + if (customOperation.optionalParams != null) { + customOperation.optionalAndAuthParameterNames.addAll( + customOperation.optionalParams.stream() + .map(codegenParameter -> + toVarName(codegenParameter.nameInCamelCase)) + .toList()); + } + + return customOperation; + } + + @Override + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, + List allModels) { + OperationsMap operationsMap = super.postProcessOperationsWithModels(objs, allModels); + + OperationMap operations = objs.getOperations(); + List operationList = operations.getOperation(); + if (operationList != null) { + operationList.forEach(codegenOperation -> { + if (codegenOperation instanceof CustomCodegenOperation customCodegenOperation + && customCodegenOperation.authMethods != null) { + postProcessSecurityParameters(customCodegenOperation); + } + }); + } + + return operationsMap; + } + + private static void postProcessSecurityParameters( + CustomCodegenOperation customCodegenOperation) { + customCodegenOperation.hasApiKeyAuth = customCodegenOperation.authMethods.stream() + .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); + + customCodegenOperation.authWithParameters = customCodegenOperation.hasApiKeyAuth; + for (CodegenSecurity codegenSecurity : customCodegenOperation.authMethods) { + if (TRUE.equals(codegenSecurity.isBasicBasic)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthUsername"); + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthPassword"); + customCodegenOperation.authWithParameters = true; + } else if (TRUE.equals(codegenSecurity.isApiKey)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); + customCodegenOperation.authWithParameters = true; + } else if (TRUE.equals(codegenSecurity.isBasicBearer)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthBearer"); + customCodegenOperation.authWithParameters = true; + } + } + } + + static class CustomCodegenOperation extends CodegenOperation { + + private final List requiredNonBodyParams; + + /** + * List of all optional parameters plus all authentication specific parameter names. + */ + private final List optionalAndAuthParameterNames; + + private boolean needsConstructorWithAllStringParameter; + + private boolean authWithParameters; + + private boolean hasApiKeyAuth; + + public CustomCodegenOperation() { + super(); + requiredNonBodyParams = new ArrayList<>(); + optionalAndAuthParameterNames = new ArrayList<>(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + CustomCodegenOperation that = (CustomCodegenOperation) o; + return needsConstructorWithAllStringParameter + == that.needsConstructorWithAllStringParameter + && hasApiKeyAuth == that.hasApiKeyAuth && Objects.equals(requiredNonBodyParams, + that.requiredNonBodyParams) && Objects.equals(optionalAndAuthParameterNames, + that.optionalAndAuthParameterNames); + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), requiredNonBodyParams, + optionalAndAuthParameterNames, + needsConstructorWithAllStringParameter, hasApiKeyAuth); + } + } + + static class CustomCodegenParameter extends CodegenParameter { + + boolean isBaseTypeString; + + public CustomCodegenParameter() { + super(); + } + + @Override + public CustomCodegenParameter copy() { + CodegenParameter copy = super.copy(); + CustomCodegenParameter customCopy = new CustomCodegenParameter(); + + copyFields(CodegenParameter.class, copy, customCopy); + customCopy.isBaseTypeString = isBaseTypeString; + + return customCopy; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + CustomCodegenParameter that = (CustomCodegenParameter) o; + return isBaseTypeString == that.isBaseTypeString; + } + + @Override + public int hashCode() { + return Objects.hash(super.hashCode(), isBaseTypeString); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java deleted file mode 100644 index c624c885f6..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/JavaCitrusCodegen.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.generator; - -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toMap; -import static org.openapitools.codegen.CliOption.newString; - -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import java.io.File; -import java.util.ArrayList; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import lombok.Getter; -import lombok.Setter; -import org.openapitools.codegen.CodegenType; -import org.openapitools.codegen.SupportingFile; -import org.openapitools.codegen.languages.AbstractJavaCodegen; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Getter -@Setter -public class JavaCitrusCodegen extends AbstractJavaCodegen { - - private static final Logger logger = LoggerFactory.getLogger(JavaCitrusCodegen.class); - - private static final String ABSTRACT_TEST_REQUEST_JAVA = "AbstractTestRequest.java"; - private static final String API_TYPE_REST = "REST"; - private static final String API_TYPE_SOAP = "SOAP"; - public static final String CODEGEN_NAME = "java-citrus"; - - // possible optional parameters - public static final String API_ENDPOINT = "apiEndpoint"; - public static final String API_TYPE = "apiType"; - public static final String GENERATED_SCHEMA_FOLDER = "generatedSchemaFolder"; - public static final String HTTP_PATH_PREFIX = "httpPathPrefix"; - public static final String OPENAPI_SCHEMA = "openapiSchema"; - public static final String PREFIX = "prefix"; - public static final String RESOURCE_FOLDER = "resourceFolder"; - public static final String SOURCE_FOLDER = "sourceFolder"; - public static final String TARGET_XMLNS_NAMESPACE = "targetXmlnsNamespace"; - - // default values for optional parameters - protected String apiPrefix = "Api"; - - protected String httpClient = API_ENDPOINT; - protected String httpPathPrefix = "api"; - protected String openapiSchema = "oas3"; - protected String resourceFolder = - "src" + File.separator + "main" + File.separator + "resources"; - protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; - protected String targetXmlnsNamespace; - - protected String apiVersion = "1.0.0"; - - public JavaCitrusCodegen() { - super(); - - // the root folder where all files are emitted - outputFolder = "generated-code" + File.separator + "java"; - - // this is the location which templates will be read from in the - resources - directory - templateDir = CODEGEN_NAME; - - // register additional properties which will be available in the templates - additionalProperties.put("apiVersion", apiVersion); - - // set default - additionalProperties.put(API_TYPE, API_TYPE_REST); - additionalProperties.put("useJakartaEe", true); - - // add additional reserved words used in CitrusAbstractTestRequest and its base class to prevent name collisions - Set reservedWordsTemp = reservedWords(); - reservedWordsTemp.addAll( - asList( - "name", - "description", - "actor", - "httpClient", - "dataSource", - "schemaValidation", - "schema", - "headerContentType", - "headerAccept", - "bodyFile", - "responseType", - "responseStatus", - "responseReasonPhrase", - "responseVersion", - "resource", - "responseVariable", - "responseValue", - "cookies", - "script", - "type" - ) - ); - setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); - - // add possibility to set a new value for the properties - cliOptions.add( - newString(API_ENDPOINT, - "Which http client should be used (default " + httpClient + ").")); - cliOptions.add( - newString(API_TYPE, - "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" - ) - ); - cliOptions.add( - newString(GENERATED_SCHEMA_FOLDER, - "The schema output directory (default " + generatedSchemaFolder + ").") - ); - cliOptions.add( - newString(HTTP_PATH_PREFIX, - "Add a prefix to http path for all APIs (default " + httpPathPrefix + ").")); - cliOptions.add( - newString(OPENAPI_SCHEMA, - "Which OpenAPI schema should be used (default " + openapiSchema + ").")); - cliOptions.add( - newString(PREFIX, - "Add a prefix before the name of the files. First character should be upper case (default " + apiPrefix + ")." - ) - ); - cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); - cliOptions.add( - newString(RESOURCE_FOLDER, - "Where the resource files are emitted (default " + resourceFolder + ").")); - cliOptions.add( - newString(TARGET_XMLNS_NAMESPACE, - "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") - ); - } - - /** - * Returns human-friendly help for the generator. Provide the consumer with help tips, - * parameters here - * - * @return A string value for the help message - */ - @Override - public String getHelp() { - return "Generates citrus api requests."; - } - - /** - * Configures a friendly name for the generator. This will be used by the generator to select - * the library with the -g flag. - * - * @return the friendly name for the generator - */ - @Override - public String getName() { - return CODEGEN_NAME; - } - - /** - * Configures the type of generator. - * - * @return the CodegenType for this generator - * @see org.openapitools.codegen.CodegenType - */ - @Override - public CodegenType getTag() { - return CodegenType.CLIENT; - } - - @Override - public void processOpts() { - super.processOpts(); - - if (additionalProperties.containsKey(API_ENDPOINT)) { - this.setHttpClient(additionalProperties.get(API_ENDPOINT).toString()); - } - additionalProperties.put(API_ENDPOINT, httpClient); - - if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { - this.setGeneratedSchemaFolder(additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); - } - additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); - - if (additionalProperties.containsKey(HTTP_PATH_PREFIX)) { - this.setHttpPathPrefix(additionalProperties.get(HTTP_PATH_PREFIX).toString()); - additionalProperties.put(HTTP_PATH_PREFIX, httpPathPrefix); - } else { - logger.warn( - "Using empty http-path-prefix for code generation. A http-path-prefix can be configured using \"{}\" property.", - HTTP_PATH_PREFIX - ); - httpPathPrefix = ""; - } - - if (additionalProperties.containsKey(OPENAPI_SCHEMA)) { - this.setOpenapiSchema(additionalProperties.get(OPENAPI_SCHEMA).toString()); - } - additionalProperties.put(OPENAPI_SCHEMA, openapiSchema); - - if (additionalProperties.containsKey(PREFIX)) { - this.setApiPrefix(additionalProperties.get(PREFIX).toString()); - additionalProperties.put(PREFIX, apiPrefix); - additionalProperties.put(PREFIX + "LowerCase", apiPrefix.toLowerCase()); - } else { - logger.warn( - "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", - PREFIX); - apiPrefix = ""; - } - - if (additionalProperties.containsKey(RESOURCE_FOLDER)) { - this.setResourceFolder(additionalProperties.get(RESOURCE_FOLDER).toString()); - } - additionalProperties.put(RESOURCE_FOLDER, resourceFolder); - - if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { - this.setTargetXmlnsNamespace(additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); - } else { - this.targetXmlnsNamespace = format("http://www.citrusframework.org/citrus-test-schema/%s-api", apiPrefix.toLowerCase()); - } - additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); - - // define different folders where the files will be emitted - final String invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator); - final String citrusFolder = invokerFolder + File.separator + "citrus"; - final String extensionFolder = citrusFolder + File.separator + "extension"; - final String springFolder = invokerFolder + File.separator + "spring"; - final String schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; - - Object apiType = additionalProperties.get(API_TYPE); - if (API_TYPE_REST.equals(apiType)) { - addRestSupportingFiles(citrusFolder, schemaFolder); - } else if (API_TYPE_SOAP.equals(apiType)) { - addSoapSupportingFiles(citrusFolder, schemaFolder); - } else { - throw new IllegalArgumentException(format("Unknown API_TYPE: '%s'", apiType)); - } - - addDefaultSupportingFiles(citrusFolder, extensionFolder, springFolder); - } - - @Override - public void preprocessOpenAPI(OpenAPI openAPI) { - super.preprocessOpenAPI(openAPI); - - Info info = openAPI.getInfo(); - Map extensions = info.getExtensions(); - if (extensions != null) { - additionalProperties.putAll(extensions); - - Map infoExtensions = extensions.entrySet().stream() - .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) - .collect(toMap(Entry::getKey, Entry::getValue)); - additionalProperties.put("infoExtensions", infoExtensions); - } - } - - private void addRestSupportingFiles(final String citrusFolder, String schemaFolder) { - supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); - supportingFiles.add(new SupportingFile("test_base.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); - } - - private void addSoapSupportingFiles(final String citrusFolder, String schemaFolder) { - // Remove the default api template file - apiTemplateFiles().remove("api.mustache"); - apiTemplateFiles().put("api_soap.mustache", ".java"); - - supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); - supportingFiles.add(new SupportingFile("api_soap.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); - supportingFiles.add(new SupportingFile("test_base_soap.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA)); - } - - private void addDefaultSupportingFiles(final String citrusFolder, final String extensionFolder, final String springFolder) { - supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, apiPrefix + "BeanConfiguration.java")); - supportingFiles.add(new SupportingFile("bean_definition_parser.mustache", citrusFolder, apiPrefix + "BeanDefinitionParser.java")); - supportingFiles.add(new SupportingFile("namespace_handler.mustache", extensionFolder, apiPrefix + "NamespaceHandler.java")); - supportingFiles.add(new SupportingFile("api-model.mustache", resourceFolder, apiPrefix.toLowerCase() + "-api-model.csv")); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java deleted file mode 100644 index 7945002312..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/TestApiClientRequestActionBuilder.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.citrusframework.openapi.generator; - -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import org.citrusframework.actions.SendMessageAction; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -public class TestApiClientRequestActionBuilder extends OpenApiClientRequestActionBuilder { - - // TODO: do we really need this? - protected OpenApiSpecification openApiSpec; - - private final String path; - - private final Map pathParameters = new HashMap<>(); - - private final MultiValueMap formData = new LinkedMultiValueMap<>(); - - // TODO: can we just pass in the operation? - public TestApiClientRequestActionBuilder(OpenApiSpecification openApiSpec, String method, String path, String operationName) { - super(openApiSpec, "%s_%s".formatted(method, path)); - name(String.format("%s:%s", "PetStore".toLowerCase(), operationName)); - getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); - getMessageBuilderSupport().header("citrus_open_api_method", method); - getMessageBuilderSupport().header("citrus_open_api_path", path); - - this.openApiSpec = openApiSpec; - this.path = path; - } - - protected void pathParameter(String name, String value) { - pathParameters.put(name, value); - } - - protected void formData(String name, String value) { - formData.add(name, value); - } - - protected String qualifiedPath(String path) { - - String qualifiedPath = path; - for (Entry entry : pathParameters.entrySet()) { - qualifiedPath = qualifiedPath.replace("{%s}".formatted(entry.getKey()), entry.getValue()); - } - return qualifiedPath; - } - - protected String toQueryParam(String...arrayElements) { - return String.join(",", arrayElements); - } - - @Override - public SendMessageAction doBuild() { - // TODO: register callback to modify builder - path(qualifiedPath(path)); - if (!formData.isEmpty()) { - // TODO: do we have to explicitly set the content type or is this done by citrus - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE); - getMessageBuilderSupport().body(formData); - } - return super.doBuild(); - } - - } \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java similarity index 60% rename from test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java rename to test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java index 8243be5aa8..db0be8bfe2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java @@ -28,6 +28,7 @@ import io.swagger.v3.oas.models.Paths; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; import java.net.URI; import java.util.Collections; @@ -38,6 +39,7 @@ import javax.wsdl.BindingOperation; import javax.wsdl.Definition; import javax.wsdl.WSDLException; +import javax.wsdl.extensions.soap.SOAPOperation; import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; @@ -47,14 +49,56 @@ import org.w3c.dom.Element; /** - * Transforms a wsdl specification into a simple OpenApi specification for usage with the OpenApiGenerator. + * Transforms a WSDL specification into a simple OpenAPI specification for usage with the OpenApiGenerator. *

    + * This transformer primarily focuses on mapping WSDL bindings into OpenAPI operations. + * It converts SOAP operations described in the WSDL into corresponding HTTP POST operations + * in the OpenAPI format. However, it does not convert or map schema information, such as + * types or message definitions, from the WSDL. + *

    + * + *

    WSDL to OpenAPI Mapping

    + * The transformer processes the following WSDL elements and maps them to the OpenAPI specification: + *
      + *
    • WSDL Bindings: Mapped to OpenAPI paths and operations. Each binding operation is + * converted into a corresponding POST operation in OpenAPI.
    • + *
    • WSDL Operation Name: The operation name in the WSDL is used as the operation ID + * in OpenAPI and forms part of the path in the OpenAPI specification.
    • + *
    • Binding Name: The binding name (for example, "SoapBinding") is used to tag the operation + * in the OpenAPI specification, allowing operations to be grouped logically by their binding.
    • + *
    • WSDL Documentation: If available, the documentation from the WSDL is extracted and used + * as the description for the OpenAPI operation. This provides human-readable documentation for + * each operation in the OpenAPI spec.
    • + *
    + *

    + * The following elements of the WSDL are not mapped to the OpenAPI specification: + *

      + *
    • WSDL Types and Schema: The schema and type definitions from the WSDL are not included in the + * resulting OpenAPI specification. This transformer focuses solely on operations, not data models.
    • + *
    • WSDL Messages: The message parts (input/output) associated with operations are not included + * in the OpenAPI output. This transformation only extracts the operations without message payload details.
    • + *
    + * + *

    Usage Example

    + *
    + * {@code
    + * URI wsdlUri = new URI("http://example.com/my-service.wsdl");
    + * SimpleWsdlToOpenApiTransformer transformer = new SimpleWsdlToOpenApiTransformer(wsdlUri);
    + * String openApiYaml = transformer.transformToOpenApi();
    + * System.out.println(openApiYaml);
    + * }
    + * 
    + * + * @see io.swagger.v3.oas.models.OpenAPI + * @see io.swagger.v3.oas.models.Operation + * @see javax.wsdl.Definition + * @see javax.wsdl.Binding + * @see javax.wsdl.BindingOperation * - * Note that this transformer only transforms bindings from the wsdl into operations in the OpenApi. */ -public class SimpleWsdlToOpenApiTransformer { +public class WsdlToOpenApiTransformer { - private static final Logger logger = LoggerFactory.getLogger(SimpleWsdlToOpenApiTransformer.class); + private static final Logger logger = LoggerFactory.getLogger(WsdlToOpenApiTransformer.class); private static final YAMLMapper yamlMapper = (YAMLMapper) YAMLMapper.builder() .enable(SORT_PROPERTIES_ALPHABETICALLY) @@ -63,12 +107,12 @@ public class SimpleWsdlToOpenApiTransformer { private final URI wsdlUri; - public SimpleWsdlToOpenApiTransformer(URI wsdlUri) { + public WsdlToOpenApiTransformer(URI wsdlUri) { this.wsdlUri = wsdlUri; } /** - * Transforms the wsdl of this transfromer into a OpenApi yaml representation. + * Transforms the wsdl of this transformer into a OpenApi yaml representation. * * @return the OpenApi yaml * @throws WsdlToOpenApiTransformationException if the parsing fails @@ -149,7 +193,6 @@ private void addOperations(OpenAPI openApi, QName qName, Binding binding) { } else { bindingApiName = localPart; } - List bindingOperations = binding.getBindingOperations(); for (Object operation : bindingOperations) { if (operation instanceof BindingOperation bindingOperation) { @@ -157,21 +200,26 @@ private void addOperations(OpenAPI openApi, QName qName, Binding binding) { openApi.getPaths(), bindingOperation.getName(), retrieveOperationDescription(bindingOperation), + retrieveSoapAction(bindingOperation), bindingApiName ); } } } - private void addOperation(Paths paths, String name, String description, String tag) { + private void addOperation(Paths paths, String name, String description, String soapAction, String tag) { Operation postOperation = new Operation(); logger.debug("Adding operation to spec: {}", name); postOperation.setOperationId(name); postOperation.setDescription(description); + postOperation.setSummary(soapAction); postOperation.tags(Collections.singletonList(tag)); ApiResponses responses = new ApiResponses(); + ApiResponse apiResponse = new ApiResponse(); + apiResponse.setDescription("Generic Response"); + responses.addApiResponse("default", apiResponse); postOperation.responses(responses); PathItem pi = new PathItem(); @@ -184,16 +232,42 @@ private void addOperation(Paths paths, String name, String description, String t * Retrieve the description of the bindingOperation via the documentation of the associated operation. */ private String retrieveOperationDescription(BindingOperation bindingOperation) { - String description = ""; + StringBuilder description = new StringBuilder(); javax.wsdl.Operation soapOperation = bindingOperation.getOperation(); + Element documentationElement = bindingOperation.getDocumentationElement(); + if (documentationElement != null) { + String documentationText = documentationElement.getTextContent().trim(); + description.append(format("%s",documentationText)); + } + if (soapOperation != null) { - Element documentationElement = soapOperation.getDocumentationElement(); + documentationElement = soapOperation.getDocumentationElement(); if (documentationElement != null) { - description = documentationElement.getTextContent(); + String documentationText = documentationElement.getTextContent().trim(); + if (!description.isEmpty()) { + description.append(" "); + } + description.append(format("%s",documentationText)); + } + } + + return description.toString(); + } + + /** + * Retrieve the soap action. + */ + private String retrieveSoapAction(BindingOperation bindingOperation) { + String soapAction = ""; + + List extensibilityElements = bindingOperation.getExtensibilityElements(); + for (Object element : extensibilityElements) { + if (element instanceof SOAPOperation soapOperation) { + soapAction = soapOperation.getSoapActionURI(); } } - return description; + return soapAction; } private String convertToYaml(OpenAPI openAPI) throws JsonProcessingException { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index 33a85c5059..b63055e186 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -1 +1 @@ -org.citrusframework.openapi.generator.JavaCitrusCodegen \ No newline at end of file +org.citrusframework.openapi.generator.CitrusJavaCodegen \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache deleted file mode 100644 index ae513df561..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api-model.mustache +++ /dev/null @@ -1,2 +0,0 @@ -OperationId;Path;Method;Parameters{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}} -{{operationId}};{{path}};{{httpMethod}};{{#allParams}}{{paramName}}:{{{dataType}}}{{^-last}},{{/-last}}{{/allParams}}{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index cb2473c14b..09618550e2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -1,84 +1,615 @@ -{{>licenseInfo}} +{{! + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} package {{package}}; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; import java.util.HashMap; import java.util.Map; -import org.citrusframework.http.client.HttpClient; +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.TestApiClientRequestActionBuilder; -import org.citrusframework.openapi.generator.rest.petstore.model.Pet; -import org.citrusframework.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.ParameterStyle; +import {{requestBuilderClass}}; +import {{responseBuilderClass}}; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; -import {{invokerPackage}}.citrus.{{prefix}}AbstractSendAction; +import {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}; +{{#isRest}}import {{modelPackage}}.*;{{/isRest}} +@SuppressWarnings("unused") {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{classname}} implements GeneratedApi { - public static final {{classname}} INSTANCE = new {{classname}}(); + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + {{#authMethods}} + {{#isBasicBasic}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.basic.username:#{null}}") + private String basicUsername; + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.basic.password:#{null}}") + private String basicPassword; + {{/isBasicBasic}} + {{#isBasicBearer}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.bearer.token:#{null}}") + private String basicAuthBearer; + {{/isBasicBearer}} + {{#isApiKey}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.{{#lambda.kebabcase}}{{keyParamName}}{{/lambda.kebabcase}}:#{null}}") + private String default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}; + {{/isApiKey}} + {{/authMethods}} + + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; - private OpenApiSpecification openApiSpecification = null; + public {{classname}}(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public {{classname}}(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + + URL resource = {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.class.getResource("{{prefix}}_openApi.yaml"); + if (resource == null) { + throw new IllegalStateException(format("Cannot find resource '%s'. This resource is typically created during API generation and should therefore be present. Check API generation.", "{{prefix}}_openApi.yaml")); + } + openApiSpecification = OpenApiSpecification.from(resource); + } + + public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint endpoint) { + return new {{classname}}(endpoint); + } + @Override public String getApiTitle() { - return "{{appName}}"; + return "{{appName}}"; } + @Override public String getApiVersion() { - return "{{appVersion}}"; + return "{{appVersion}}"; } + @Override public String getApiPrefix() { - return "{{prefix}}"; + return "{{prefix}}"; } - public Map getApiInfoExtensions() { + @Override + public Map getApiInfoExtensions() { + {{#infoExtensions}} Map infoExtensionMap = new HashMap<>(); - {{#infoExtensions}} - {{#entrySet}} + {{#entrySet}} infoExtensionMap.put("{{key}}", "{{value}}"); - {{/entrySet}} - {{/infoExtensions}} + {{/entrySet}} return infoExtensionMap; + {{/infoExtensions}} + {{^infoExtensions}} + return emptyMap(); + {{/infoExtensions}} + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; } {{#operations}} {{#operation}} - public {{operationIdCamelCase}}ActionBuilder {{operationId}}() { - return new {{operationIdCamelCase}}ActionBuilder(); - } + /** + * Builder with type safe required parameters. + */ + public {{operationIdCamelCase}}SendActionBuilder send{{operationIdCamelCase}}({{#requiredNonBodyParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredNonBodyParams}}) { + {{#authWithParameters}} + {{operationIdCamelCase}}SendActionBuilder builder = new {{operationIdCamelCase}}SendActionBuilder(this, openApiSpecification{{#requiredNonBodyParams}}, {{paramName}}{{/requiredNonBodyParams}}); + {{#hasApiKeyAuth}} + builder.setBase64EncodeApiKey(base64EncodeApiKey); + {{/hasApiKeyAuth}} + {{#isBasicBasic}} + builder.setBasicAuthUsername(basicUsername); + builder.setBasicAuthPassword(basicPassword); + {{/isBasicBasic}} + {{#isBasicBearer}} + builder.setBasicAuthBearer(basicAuthBearer); + {{/isBasicBearer}} + {{#isApiKey}} + builder.set{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}(default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}); + {{/isApiKey}} + return builder; + {{/authWithParameters}} + {{^authWithParameters}} + return new {{operationIdCamelCase}}SendActionBuilder(this, openApiSpecification{{#requiredNonBodyParams}}, {{paramName}}{{/requiredNonBodyParams}}); + {{/authWithParameters}} + } + {{#needsConstructorWithAllStringParameter}} + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public {{operationIdCamelCase}}SendActionBuilder send{{operationIdCamelCase}}$({{#requiredNonBodyParams}}{{^isArray}}String {{paramName}}Expression{{/isArray}}{{#isArray}}List {{paramName}}Expression{{/isArray}}{{^-last}}, {{/-last}} {{/requiredNonBodyParams}}) { + {{#authWithParameters}} + {{operationIdCamelCase}}SendActionBuilder builder = new {{operationIdCamelCase}}SendActionBuilder(openApiSpecification, this{{#requiredNonBodyParams}}, {{paramName}}Expression{{/requiredNonBodyParams}}); + {{#hasApiKeyAuth}} + builder.setBase64EncodeApiKey(base64EncodeApiKey); + {{/hasApiKeyAuth}} + {{#authMethods}} + {{#isBasicBasic}} + builder.setBasicAuthUsername(basicUsername); + builder.setBasicAuthPassword(basicPassword); + {{/isBasicBasic}} + {{#isBasicBearer}} + builder.setBasicAuthBearer(basicAuthBearer); + {{/isBasicBearer}} + {{#isApiKey}} + builder.set{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}(default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}); + {{/isApiKey}} + {{/authMethods}} + return builder; + {{/authWithParameters}} + {{^authWithParameters}} + return new {{operationIdCamelCase}}SendActionBuilder(openApiSpecification, this{{#requiredNonBodyParams}}, {{paramName}}Expression{{/requiredNonBodyParams}}); + {{/authWithParameters}} + } + {{/needsConstructorWithAllStringParameter}} + + public {{operationIdCamelCase}}ReceiveActionBuilder receive{{operationIdCamelCase}}(@NotNull HttpStatus statusCode) { + return new {{operationIdCamelCase}}ReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public {{operationIdCamelCase}}ReceiveActionBuilder receive{{operationIdCamelCase}}(@NotNull String statusCode) { + return new {{operationIdCamelCase}}ReceiveActionBuilder(this, openApiSpecification, statusCode); + } {{/operation}} {{/operations}} - {{#operations}} {{#operation}} - public class {{operationIdCamelCase}}ActionBuilder extends TestApiClientRequestActionBuilder { + public static class {{operationIdCamelCase}}SendActionBuilder extends + {{requestBuilderClassName}} { - private static final String METHOD = "{{httpMethod}}"; + private static final String METHOD = "{{httpMethod}}"; - private static final String ENDPOINT = "{{path}}"; + private static final String ENDPOINT = "{{basePath}}{{path}}"; - private static final String OPERATION_NAME = "{{operationId}}"; + private static final String OPERATION_NAME = "{{operationId}}"; + {{#hasApiKeyAuth}} - public AddPetActionBuilder() { - super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - } + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + {{/hasApiKeyAuth}} + {{#authMethods}} + {{#isBasicBasic}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.basic.username:#{null}}") + private String defaultBasicUsername; + + private String basicUsername; + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.basic.password:#{null}}") + private String defaultBasicPassword; + + private String basicPassword; + {{/isBasicBasic}} + {{#isBasicBearer}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.bearer.token:#{null}}") + private String defaultBasicAuthBearer; + + private String basicAuthBearer; + {{/isBasicBearer}} + {{#isApiKey}} + + @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.{{#lambda.kebabcase}}{{keyParamName}}{{/lambda.kebabcase}}:#{null}}") + private String default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}; + + private String {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}; + {{/isApiKey}} + {{/authMethods}} + + /** + * Constructor with type safe required parameters. + */ + public {{operationIdCamelCase}}SendActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, OpenApiSpecification openApiSpecification{{#requiredNonBodyParams}}, {{{dataType}}} {{paramName}}{{/requiredNonBodyParams}}) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + {{#requiredNonBodyParams}} + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + {{/requiredNonBodyParams}} + } + {{#needsConstructorWithAllStringParameter}} + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + {{! + Note that the change in the order of parameters is intentional to be able to differentiate + constructors with Collections parameters which would otherwise have the same erasure type. + }} + public {{operationIdCamelCase}}SendActionBuilder(OpenApiSpecification openApiSpecification, {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}{{#requiredNonBodyParams}}, {{^isArray}}String {{paramName}}Expression{{/isArray}}{{#isArray}}List {{paramName}}Expression{{/isArray}}{{/requiredNonBodyParams}}) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + {{#requiredNonBodyParams}} + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + {{/requiredNonBodyParams}} + } + {{/needsConstructorWithAllStringParameter}} + + {{#requiredNonBodyParams}} + {{#-first}} + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + {{/-first}} + {{/requiredNonBodyParams}} + public {{operationIdCamelCase}}SendActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder{{#requiredNonBodyParams}}, {{^isArray}}String {{paramName}}Expression{{/isArray}}{{#isArray}}List {{paramName}}{{/isArray}}{{/requiredNonBodyParams}}) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + {{#requiredNonBodyParams}} + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}{{^isArray}}Expression{{/isArray}}){{/isBinary}} {{^isBinary}}{{paramName}}{{^isArray}}Expression{{/isArray}}{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + {{/requiredNonBodyParams}} + } + {{#requiredNonBodyParams}} - {{#queryParams}} - public {{operationIdCamelCase}}ActionBuilder with{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - queryParam("{{paramName}}", {{paramName}}); - return this; + {{! + Type safe setting of parameter, using builder pattern. + }} + public {{operationIdCamelCase}}SendActionBuilder {{paramName}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + return this; + } + {{^isBaseTypeString}} + + {{! + Non type safe setting of parameter, using builder pattern. + }} + public {{operationIdCamelCase}}SendActionBuilder {{paramName}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + return this; + } + {{/isBaseTypeString}} + {{/requiredNonBodyParams}} + {{#optionalParams}} + + {{! + Type safe setting of the parameter value. + Depending on the parameter type (query, path, header, form, or cookie), + the appropriate method is invoked to set the parameter. + }} + public {{operationIdCamelCase}}SendActionBuilder {{paramName}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + return this; + } + + {{! + Type safe setting of the parameter value. + These setters are used by SendApiRequestActionParser and ReceiveApiResponseActionParser + to inject attributes into the request or response. + Depending on the parameter type (query, path, header, form, or cookie), + the appropriate method is invoked to set the parameter. + }} + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + } + {{^isBaseTypeString}} + + {{! + Configures a request action by setting the value of a parameter + (query, path, header, form, or cookie) as a dynamic string expression, + supporting citrus variables. This method handles different parameter types + based on the context and updates the respective parameter accordingly. + Supports arrays if the parameter is marked as such. + }} + public {{operationIdCamelCase}}SendActionBuilder {{paramName}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}Expression); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + return this; + } + + {{! + Sets the value of the parameter as a string expression. + These setters are used by SendApiRequestActionParser and ReceiveApiResponseActionParser + to inject attributes into the request or response. + Depending on the parameter type (query, path, header, form, or cookie), + the appropriate method is invoked to set the parameter. + If the parameter is marked as an array, multiple values are supported. + }} + public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { + {{#isQueryParam}} + queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isQueryParam}} + {{#isPathParam}} + pathParameter("{{baseName}}", {{paramName}}Expression); + {{/isPathParam}} + {{#isHeaderParam}} + headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isHeaderParam}} + {{#isFormParam}} + formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); + {{/isFormParam}} + {{#isCookieParam}} + cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + {{/isCookieParam}} + } + {{/isBaseTypeString}} + {{/optionalParams}} + {{#hasApiKeyAuth}} + + public void setBase64EncodeApiKey(boolean encode) { + this.base64EncodeApiKey = encode; + } + {{/hasApiKeyAuth}} + {{#authMethods}} + {{#isBasicBasic}} + + public {{operationIdCamelCase}}SendActionBuilder basicAuthUsername(String basicUsername) { + this.basicUsername = basicUsername; + return this; + } + + public void setBasicAuthUsername(String basicUsername) { + this.basicUsername = basicUsername; + } + + public {{operationIdCamelCase}}SendActionBuilder basicAuthPassword(String password) { + this.basicPassword = password; + return this; + } + + public void setBasicAuthPassword(String password) { + this.basicPassword = password; + } + + protected void addBasicAuthHeader(String basicUsername, String basicPassword, + HttpMessageBuilderSupport messageBuilderSupport) { + TestApiUtils.addBasicAuthHeader( + isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, + isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, + messageBuilderSupport); + } + {{/isBasicBasic}} + {{#isBasicBearer}} + + public {{operationIdCamelCase}}SendActionBuilder basicAuthBearer(String basicAuthBearer) { + this.basicAuthBearer = basicAuthBearer; + return this; + } + + public void setBasicAuthBearer(String basicAuthBearer) { + this.basicAuthBearer = basicAuthBearer; + } + {{/isBasicBearer}} + {{#isApiKey}} + + public {{operationIdCamelCase}}SendActionBuilder {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}(String {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}) { + this.{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}} = {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}; + return this; + } + + public void set{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}(String {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}) { + this.{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}} = {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}; + } + {{/isApiKey}} + {{/authMethods}} + + @Override + public SendMessageAction doBuild() { + {{#authMethods}} + {{#isBasicBasic}} + addBasicAuthHeader(basicUsername, basicPassword, getMessageBuilderSupport()); + {{/isBasicBasic}} + {{#isBasicBearer}} + if (!isEmpty(basicAuthBearer) || !isEmpty(defaultBasicAuthBearer)) { + headerParameter("Authorization", "Bearer " +getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); + } + {{/isBasicBearer}} + {{/authMethods}} + {{#authMethods}} + {{#isApiKey}} + {{#isKeyInHeader}} + headerParameter("{{keyParamName}}", getOrDefault({{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}, default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}, base64EncodeApiKey)); + {{/isKeyInHeader}} + {{#isKeyInQuery}} + queryParameter("{{keyParamName}}", getOrDefault({{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}, default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}, base64EncodeApiKey)); + {{/isKeyInQuery}} + {{#isKeyInCookie}} + cookieParameter("{{keyParamName}}", getOrDefault({{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}, default{{#lambda.titlecase}}{{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}}{{/lambda.titlecase}}, base64EncodeApiKey)); + {{/isKeyInCookie}} + {{/isApiKey}} + {{/authMethods}} + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } } - {{/queryParams}} - // public AddPetActionBuilder withPet(Pet pet) { - // // TODO: fix this - // getMessageBuilderSupport().body(pet.toString()); - // return this; - // } + public static class {{operationIdCamelCase}}ReceiveActionBuilder extends + {{responseBuilderClassName}} { + + private static final String METHOD = "{{httpMethod}}"; + + private static final String ENDPOINT = "{{basePath}}{{path}}"; + + private static final String OPERATION_NAME = "{{operationId}}"; + + public {{operationIdCamelCase}}ReceiveActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, OpenApiSpecification openApiSpecification, String statusCode) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public {{operationIdCamelCase}}ReceiveActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } } + {{^-last}} + + {{/-last}} {{/operation}} {{/operations}} } \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache new file mode 100644 index 0000000000..8155517939 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache @@ -0,0 +1,28 @@ +{{! + + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} +package {{invokerPackage}}; + +import java.net.URL; + +public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}} { + + public static URL {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Api() { + return {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.class.getResource("{{prefix}}_openApi.yaml"); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache deleted file mode 100644 index a023345fb7..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_old.mustache +++ /dev/null @@ -1,259 +0,0 @@ -{{>licenseInfo}} - -package {{package}}; - -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{classname}} implements GeneratedApi -{ - - public static final {{classname}} INSTANCE = new {{classname}}(); - - public String getApiTitle() { - return "{{appName}}"; - } - - public String getApiVersion() { - return "{{appVersion}}"; - } - - public String getApiPrefix() { - return "{{prefix}}"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - {{#infoExtensions}} - {{#entrySet}} - infoExtensionMap.put("{{key}}", "{{value}}"); - {{/entrySet}} - {{/infoExtensions}} - return infoExtensionMap; - } - - {{#operations}} - {{#operation}} - /** {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) - {{summary}} - {{description}} - **/ - public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "{{httpPathPrefix}}{{{path}}}"; - private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); - - {{#queryParams}} - private String {{paramName}}; - - {{/queryParams}} - {{#pathParams}} - private String {{paramName}}; - - {{/pathParams}} - {{#isMultipart}} - {{#formParams}} - private String {{paramName}}; - - {{/formParams}} - {{/isMultipart}} - {{#authMethods}}{{#isBasic}} - @Value("${" + "{{apiEndpoint}}.basic.username:#{null}}") - private String basicUsername; - @Value("${" + "{{apiEndpoint}}.basic.password:#{null}}") - private String basicPassword; - - {{/isBasic}} - {{/authMethods}} - - public {{operationIdCamelCase}}Request() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); - } - - public String getOperationName() { - return "{{operationId}}"; - } - - public String getMethod() { - return "{{httpMethod}}"; - } - - public String getPath() { - return "{{path}}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - {{#isMultipart}} - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - {{#formParams}} - {{#required}} - if(StringUtils.isBlank({{paramName}})) { - throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "{{paramName}}")); - } - {{/required}} - {{#isBinary}} - if (StringUtils.isNotBlank({{paramName}})) { - multiValues.add("{{paramName}}", new ClassPathResource({{paramName}})); - bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - {{/isBinary}} - {{^isBinary}} - if (StringUtils.isNotBlank({{paramName}})) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource({{paramName}}); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("{{paramName}}", resource); - } else { - multiValues.add("{{paramName}}", {{paramName}}); - } - bodyLog += {{paramName}}.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - {{/isBinary}} - {{/formParams}} - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - {{/isMultipart}} - {{^isMultipart}} - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - {{/isMultipart}} - - Map queryParams = new HashMap<>(); - {{#allParams}}{{#isQueryParam}} - - if (StringUtils.isNotBlank(this.{{paramName}})) { - queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); - httpClientRequestActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); - } - {{/isQueryParam}}{{/allParams}} - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - {{#authMethods}}{{#isBasic}} - - if(basicUsername != null && basicPassword != null){ - messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); - } - {{/isBasic}}{{/authMethods}} - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - {{#queryParams}} - - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/queryParams}} - {{#pathParams}} - - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/pathParams}} - {{#isMultipart}} - {{#formParams}} - - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; - } - {{/formParams}} - {{/isMultipart}} - {{#authMethods}}{{#isBasic}} - - public void setBasicUsername(String basicUsername) { - this.basicUsername = basicUsername; - } - - public void setBasicPassword(String basicPassword) { - this.basicPassword = basicPassword; - } - {{/isBasic}}{{/authMethods}} - private String replacePathParams(String endpoint) { - {{#pathParams}}endpoint = endpoint.replace("{" + "{{baseName}}" + "}", {{paramName}});{{/pathParams}} - return endpoint; - } - } - {{/operation}} - {{/operations}} -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache index ba2f8d48a6..4371a2a3bb 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -1,160 +1,152 @@ -{{>licenseInfo}} +{{! + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} package {{package}}; -import java.io.IOException; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; -import org.citrusframework.spi.Resources; -import org.citrusframework.util.FileUtils; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; -import org.citrusframework.ws.actions.SendSoapMessageAction.Builder.SendSoapMessageBuilderSupport; -import org.citrusframework.ws.actions.SoapActionBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import {{invokerPackage}}.citrus.{{prefix}}AbstractTestRequest; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +@SuppressWarnings("unused") {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{classname}} implements GeneratedApi { - public static final {{classname}} INSTANCE = new {{classname}}(); + private final Endpoint endpoint; + + private final List customizers; + + public {{classname}}(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public {{classname}}(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + } + + public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint endpoint) { + return new {{classname}}(endpoint); + } + + @Override public String getApiTitle() { return "{{appName}}"; } + @Override public String getApiVersion() { return "{{appVersion}}"; } + @Override public String getApiPrefix() { return "{{prefix}}"; } - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - {{#infoExtensions}} - {{#entrySet}} + @Override + public Map getApiInfoExtensions() { + {{#infoExtensions}} + Map infoExtensionMap = new HashMap<>(); + {{#entrySet}} infoExtensionMap.put("{{key}}", "{{value}}"); - {{/entrySet}} - {{/infoExtensions}} - return infoExtensionMap; + {{/entrySet}} + return infoExtensionMap; + {{/infoExtensions}} + {{^infoExtensions}} + return emptyMap(); + {{/infoExtensions}} } - {{#operations}} + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + +{{#operations}} {{#operation}} - /** - {{operationId}} ({{httpMethod}} {{httpPathPrefix}}{{{path}}}) - {{summary}} - {{description}} - **/ - public static class {{operationIdCamelCase}}Request extends {{prefix}}AbstractTestRequest implements GeneratedApiRequest { - - private final Logger coverageLogger = LoggerFactory.getLogger({{operationIdCamelCase}}Request.class); - - // Query params - {{#allParams}}{{#isQueryParam}}private String {{paramName}}; - {{/isQueryParam}}{{/allParams}} - - public {{operationIdCamelCase}}Request(){ - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("{{prefix}}".toLowerCase() + ":{{operationId}}RequestType"); - } + public {{operationIdCamelCase}}SendActionBuilder send{{operationIdCamelCase}}({{#requiredNonBodyParams}}{{{dataType}}} {{paramName}}{{^-last}}, {{/-last}}{{/requiredNonBodyParams}}) { + return new {{operationIdCamelCase}}SendActionBuilder(this); + } - public String getOperationName() { - return "{{operationId}}"; - } + public {{operationIdCamelCase}}ReceiveActionBuilder receive{{operationIdCamelCase}}() { + return new {{operationIdCamelCase}}ReceiveActionBuilder(this); + } - public String getMethod() { - return "{{httpMethod}}"; - } + {{/operation}} +{{/operations}} +{{#operations}} + {{#operation}} + public static class {{operationIdCamelCase}}SendActionBuilder extends {{requestBuilderClassName}} { + + private static final String SOAP_ACTION = "{{summary}}"; - public String getPath() { - return "{{path}}"; + public {{operationIdCamelCase}}SendActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, SOAP_ACTION); } - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - - SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); - SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport.soapAction("{{operationId}}"); - - String payload = null; - String payloadType = null; - - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } + @Override + public SendSoapMessageAction doBuild() { - if (!CollectionUtils.isEmpty(soapHeaders)) { - for (Entry entry : soapHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), - entry.getValue()); - } + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); } - if (!CollectionUtils.isEmpty(mimeHeaders)) { - for (Entry entry : mimeHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), - entry.getValue()); - } - } - - Map queryParams = new HashMap<>(); - {{#allParams}}{{#isQueryParam}} - if (StringUtils.isNotBlank(this.{{paramName}})) { - queryParams.put("{{baseName}}", context.replaceDynamicContentInString(this.{{paramName}})); - sendSoapMessageActionBuilder.queryParam("{{baseName}}", this.{{paramName}}); - } - {{/isQueryParam}}{{/allParams}} - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); + return super.doBuild(); + } + } - soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); + public static class {{operationIdCamelCase}}ReceiveActionBuilder extends {{responseBuilderClassName}} { - soapSendMessageActionBuilder.build().execute(context); + private static final String SOAP_ACTION = "{{summary}}"; - coverageLogger.trace(coverageMarker, "{{operationId}};{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}};\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); + public {{operationIdCamelCase}}ReceiveActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}) { + super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, SOAP_ACTION); } - {{#allParams}}{{#isQueryParam}} - public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - this.{{paramName}} = {{paramName}}; + @Override + public ReceiveSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); } - {{/isQueryParam}}{{/allParams}} + } + {{^-last}} + + {{/-last}} {{/operation}} - {{/operations}} +{{/operations}} } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache index 7bf35af55f..a9b329dba5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -1,33 +1,58 @@ -{{>licenseInfo}} +{{! -package {{invokerPackage}}.spring; + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} +package {{invokerPackage}}.spring; + +import java.util.List; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; {{#apiInfo}} {{#apis}} import {{package}}.{{classname}}; {{/apis}} {{/apiInfo}} +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; +import {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}; + @Configuration {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{prefix}}BeanConfiguration { -{{#apiInfo}} - {{#apis}} - {{#operations}} - {{#operation}} +public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}BeanConfiguration { @Bean - @Scope(SCOPE_PROTOTYPE) - public {{classname}}.{{operationIdCamelCase}}Request {{operationId}}Request() { - return new {{classname}}.{{operationIdCamelCase}}Request(); + public OpenApiRepository {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}OpenApiRepository() { + var openApiRepository = new OpenApiRepository(); + openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( + {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.{{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Api())); + return openApiRepository; + } + +{{#apiInfo}} + {{#apis}} + @Bean(name="{{classname}}") + public {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(@Qualifier("{{apiEndpoint}}") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new {{classname}}(endpoint, customizers); } - {{/operation}} - {{/operations}} + {{/apis}} {{/apiInfo}} } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache deleted file mode 100644 index 01e502f284..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_definition_parser.mustache +++ /dev/null @@ -1,205 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.citrus; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.core.Conventions; -import org.springframework.util.Assert; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; - -{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{prefix}}BeanDefinitionParser implements BeanDefinitionParser { - - private static final String COOKIE = "cookie"; - private static final String HEADER = "header"; - private static final String SOAP_HEADER = "soapHeader"; - private static final String MIME_HEADER = "mimeHeader"; - private static final String NAME = "name"; - private static final String REQUEST_BODY = "body"; - private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; - private static final String MULTIPART_BODY = "multipartBody"; - private static final String RESPONSE = "response"; - private static final String RESPONSE_JSONPATH = "json-path"; - private static final String RESPONSE_XPATH = "xpath"; - private static final String EXPRESSION = "expression"; - private static final String VALUE = "value"; - private static final String RESPONSE_RESOURCE = "resource"; - private static final String FILE = "file"; - private static final String RESPONSE_VARIABLE = "responseVariable"; - private static final String RESPONSE_VALUE = "responseValue"; - private static final String SCRIPT = "script"; - private static final String TYPE = "type"; - private static final String SQL = "sql"; - private static final String COLUMN = "column"; - private static final String VARIABLE = "variable"; - // new - private static final String SCHEMA = "schema"; - // new - private static final String SCHEMA_VALIDATION = "schemaValidation"; - - private final Class beanClass; - - public {{prefix}}BeanDefinitionParser(Class beanClass) { - this.beanClass = beanClass; - } - - public BeanDefinition parse(Element element) { - return parse(element, null); - } - - /** - * Note: The {@link {{prefix}}BeanDefinitionParser#parse(Element element)} allows access direct - * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. - */ - @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); - retrieveRootNodeAttributes(element, builder); - retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); - retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); - retrieveOptionalNodeAttributes(element, RESPONSE, builder); - retrieveParamNodeData(element, builder, COOKIE); - retrieveParamNodeData(element, builder, HEADER); - retrieveParamNodeData(element, builder, SOAP_HEADER); - retrieveParamNodeData(element, builder, MIME_HEADER); - retrieveOptionalNodeAttributes(element, SCHEMA, builder); - retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); - retrieveOptionalMultipartElements(element, builder); - retrieveResponseNodeData(element, builder); - builder.addPropertyValue("name", element.getTagName()); - return builder.getBeanDefinition(); - } - - private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { - var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); - if (multipartBodyElement != null) { - var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); - for(int i = 0; i < multipartBodyChildElements.size(); i++){ - var multipartBodyChildElement = multipartBodyChildElements.get(i); - String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); - builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); - } - } - } - - private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { - NamedNodeMap attributes = element.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - builder.addPropertyValue(propertyName, attribute.getValue()); - } - } - - private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - } - } - - private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el1.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); - String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - builder.addPropertyValue(elementName, el.getTextContent()); - } - } - - private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { - if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { - Map params = new HashMap<>(); - List elements = DomUtils.getChildElementsByTagName(element, paramType); - elements.forEach(e -> { - String name = e.getAttribute(NAME); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - params.put(name, value); - }); - builder.addPropertyValue(paramType, params); - } - } - - private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { - - if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { - Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); - List elements = DomUtils.getChildElements(response); - - Map responseVariable = new HashMap<>(); - Map responseValue = new HashMap<>(); - - for (int i = 0; i < elements.size(); i++) { - Element e = elements.get(i); - - if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { - String expression = e.getAttribute(EXPRESSION); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - // variable to save @variable('ebid')@ else value to validate - if (value.matches("\\@variable\\('.*'\\)\\@")) { - Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); - if (match.find()) { - responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); - } - } else { - responseValue.put(expression, value); - } - } else if (e.getTagName().contains(SCRIPT)) { - String script = e.getTextContent(); - Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); - builder.addPropertyValue(SCRIPT, script); - - if (!e.getAttribute(TYPE).isEmpty()) { - String type = e.getAttribute(TYPE); - Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); - builder.addPropertyValue(TYPE, type); - } - } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { - String filePath = e.getAttribute(FILE); - Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); - builder.addPropertyValue(RESPONSE_RESOURCE, filePath); - } - - } - - builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); - builder.addPropertyValue(RESPONSE_VALUE, responseValue); - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache index 8ca4a446da..27fe698993 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -1,18 +1,47 @@ -{{>licenseInfo}} +{{! -package {{invokerPackage}}.citrus.extension; + Copyright the original author or authors. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} +package {{invokerPackage}}.spring; + +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; {{#apiInfo}} {{#apis}} import {{package}}.{{classname}}; {{/apis}} {{/apiInfo}} -import {{invokerPackage}}.citrus.{{prefix}}BeanDefinitionParser; - +import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; +import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; +import {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{prefix}}NamespaceHandler extends NamespaceHandlerSupport { +public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}NamespaceHandler extends NamespaceHandlerSupport { + + {{#apiInfo}} + {{#apis}} + {{#-first}} + private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( + {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.{{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Api()); + {{/-first}} + {{/apis}} + {{/apiInfo}} @Override public void init() { @@ -20,10 +49,37 @@ public class {{prefix}}NamespaceHandler extends NamespaceHandlerSupport { {{#apis}} {{#operations}} {{#operation}} - registerBeanDefinitionParser("{{operationId}}Request", new {{prefix}}BeanDefinitionParser({{classname}}.{{operationIdCamelCase}}Request.class)); + + registerOperationParsers({{classname}}.class,"{{#lambda.kebabcase}}{{operationId}}{{/lambda.kebabcase}}", "{{operationId}}", "{{path}}", + {{classname}}.{{operationIdCamelCase}}SendActionBuilder.class, + {{classname}}.{{operationIdCamelCase}}ReceiveActionBuilder.class, + new String[]{ {{#requiredNonBodyParams}}"{{paramName}}{{^isString}}{{/isString}}"{{^-last}}, {{/-last}}{{/requiredNonBodyParams}} }, + new String[]{ {{#optionalAndAuthParameterNames}}"{{.}}"{{^-last}}, {{/-last}}{{/optionalAndAuthParameterNames}} }); {{/operation}} {{/operations}} {{/apis}} {{/apiInfo}} } + + private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { + + RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "{{apiEndpoint}}"); + sendParser.setConstructorParameters(constructorParameters); + sendParser.setNonConstructorParameters(nonConstructorParameters); + registerBeanDefinitionParser("send-"+elementName, sendParser); + + RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, + operationName, apiClass, receiveBeanClass, "{{apiEndpoint}}"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); + } + } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache new file mode 100644 index 0000000000..4104f0b454 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache @@ -0,0 +1,78 @@ +{{! + + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} +package {{invokerPackage}}.spring; + +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +{{#apiInfo}} +{{#apis}} +import {{package}}.{{classname}}; +{{/apis}} +{{/apiInfo}} +import org.citrusframework.openapi.testapi.spring.SoapApiReceiveMessageActionParser; +import org.citrusframework.openapi.testapi.spring.SoapApiSendMessageActionParser; +import {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} +public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}NamespaceHandler extends NamespaceHandlerSupport { + + {{#apiInfo}} + {{#apis}} + {{#-first}} + private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( + {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.{{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Api()); + {{/-first}} + {{/apis}} + {{/apiInfo}} + + @Override + public void init() { + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + + registerOperationParsers({{classname}}.class,"{{#lambda.kebabcase}}{{operationId}}{{/lambda.kebabcase}}", + {{classname}}.{{operationIdCamelCase}}SendActionBuilder.class, + {{classname}}.{{operationIdCamelCase}}ReceiveActionBuilder.class); + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} + } + + private void registerOperationParsers(Class apiClass, String elementName, + Class sendBeanClass, + Class receiveBeanClass) { + + SoapApiSendMessageActionParser sendParser = new SoapApiSendMessageActionParser( + apiClass, + sendBeanClass, + receiveBeanClass, + "{{apiEndpoint}}"); + registerBeanDefinitionParser("send-"+elementName, sendParser); + + SoapApiReceiveMessageActionParser receiveParser = new SoapApiReceiveMessageActionParser( + apiClass, receiveBeanClass, "{{apiEndpoint}}"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache deleted file mode 100644 index b59349ae63..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/openApi.mustache +++ /dev/null @@ -1,83 +0,0 @@ -{{>licenseInfo}} - -package {{package}}; - -import java.util.HashMap; -import java.util.Map; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.model.Pet; -import org.citrusframework.testapi.GeneratedApi; - -import {{invokerPackage}}.citrus.{{prefix}}AbstractSendAction; - -{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public class {{classname}} implements GeneratedApi -{ - - public static final {{classname}} INSTANCE = new {{classname}}(); - - private OpenApiSpecification openApiSpecification = null; - - public String getApiTitle() { - return "{{appName}}"; - } - - public String getApiVersion() { - return "{{appVersion}}"; - } - - public String getApiPrefix() { - return "{{prefix}}"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - {{#infoExtensions}} - {{#entrySet}} - infoExtensionMap.put("{{key}}", "{{value}}"); - {{/entrySet}} - {{/infoExtensions}} - return infoExtensionMap; - } - - {{#operations}} - {{#operation}} - public {{operationIdCamelCase}}ActionBuilder {{operationId}}() { - return new {{operationIdCamelCase}}ActionBuilder(); - } - {{/operation}} - {{/operations}} - - {{#operations}} - {{#operation}} - public class {{operationIdCamelCase}}ActionBuilder extends {{prefix}}AbstractSendAction.Builder { - - private static final String METHOD = ""{{httpMethod}}"; - - private static final String ENDPOINT = "{{path}}"; - - private static final String OPERATION_NAME = "{{operationId}}"; - - public AddPetActionBuilder() { - super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - } - - {{#queryParams}} - public {{operationIdCamelCase}}ActionBuilder with{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String {{paramName}}) { - queryParam("{{paramName}}", {{paramName}}); - return this; - } - } - {{/queryParams}} - -// public AddPetActionBuilder withPet(Pet pet) { -// // TODO: fix this -// getMessageBuilderSupport().body(pet.toString()); -// return this; -// } - - } - {{/operation}} - {{/operations}} -} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache index 1beddbdebc..64e0738760 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache @@ -1,78 +1,123 @@ +{{! + + Copyright the original author or authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} - + - + - + - + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + + {{^isMultipart}} + + + + {{^required}}Optional {{/required}}Body - {{summary}}{{#description}} +

    {{description}}

    {{/description}} +
    +
    +
    + {{/isMultipart}} +
    +
    +
    - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -111,28 +156,12 @@ {{#operations}} {{#operation}} - {{#isMultipart}} - - - {{#formParams}} - - - - {{^required}}Optional {{/required}}{{#required}}Required{{/required}} - must either be set as attribute or element: {{#description}} -

    {{description}}

    {{/description}} -
    -
    -
    - {{/formParams}} -
    -
    - {{/isMultipart}} - - + + {{notes}} {{operationId}} -

    {{httpMethod}} {{httpPathPrefix}}{{{path}}}

    +

    {{httpMethod}} {{{path}}}

      {{#queryParams}}
    • {{paramName}} {{description}}
    • @@ -143,10 +172,18 @@ {{#bodyParams}}
    • Body: {{description}}
    • {{/bodyParams}} - {{#authMethods}}{{#isBasic}} -
    • basicUsername http basic authentication username
    • -
    • basicPassword http basic authentication password
    • - {{/isBasic}}{{/authMethods}} + {{#authMethods}} + {{#isBasicBasic}} +
    • basicAuthUsername http basic authentication username
    • +
    • basicAuthPassword http basic authentication password
    • + {{/isBasicBasic}} + {{#isBasicBearer}} +
    • basicAuthBearer http basic authentication bearer token
    • + {{/isBasicBearer}} + {{#isApiKey}} +
    • {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}} {{#lambda.camelcase}}{{keyParamName}}{{/lambda.camelcase}} authentication token
    • + {{/isApiKey}} + {{/authMethods}} {{#isMultipart}} {{#formParams}}
    • {{paramName}} {{description}}
    • @@ -156,65 +193,210 @@ - + - {{#isMultipart}} - - {{/isMultipart}} - {{^isMultipart}} - {{#bodyParams}} - - - - {{^required}}Optional {{/required}}Body - {{summary}}{{#description}} -

      {{description}}

      {{/description}} -
      -
      + {{#queryParams}} + {{#isArray}} + + {{#description}} + + {{description}} + + {{/description}} - {{/bodyParams}} - {{/isMultipart}} - + {{/isArray}} + {{/queryParams}} + {{#headerParams}} + {{#isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/headerParams}} + {{#pathParams}} + {{#isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/pathParams}} + {{#formParams}} + {{#isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/formParams}} + {{#cookieParams}} + {{#isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/cookieParams}} +
      {{#queryParams}} - + {{^isArray}} + + {{#description}} {{description}} + {{/description}} + {{/isArray}} {{/queryParams}} + {{#headerParams}} + {{^isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/headerParams}} {{#pathParams}} - + {{^isArray}} + + {{#description}} {{description}} + {{/description}} + {{/isArray}} {{/pathParams}} - {{#isMultipart}} {{#formParams}} - - + {{^isArray}} + + {{#description}} - The filename of the {{paramName}} to upload + {{description}} + {{/description}} + {{/isArray}} {{/formParams}} - {{/isMultipart}} - {{#authMethods}}{{#isBasic}} - + {{#cookieParams}} + {{^isArray}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isArray}} + {{/cookieParams}} + {{#authMethods}} + {{#isBasicBasic}} + http basic authentication username - + http basic authentication password - {{/isBasic}}{{/authMethods}} + {{/isBasicBasic}} + {{#isBasicBearer}} + + + http basic authentication bearer token + + + {{/isBasicBearer}} + {{#isApiKey}} + + {{#description}} + + {{description}} + + {{/description}} + + {{/isApiKey}} + {{/authMethods}} +
      +
      + + + + + + {{notes}} + {{operationId}} +

      {{httpMethod}} {{{path}}}

      +
        + {{#queryParams}} +
      • {{paramName}} {{description}}
      • + {{/queryParams}} + {{#pathParams}} +
      • {{baseName}} {{description}}
      • + {{/pathParams}} + {{#bodyParams}} +
      • Body: {{description}}
      • + {{/bodyParams}} + {{#isMultipart}} + {{#formParams}} +
      • {{paramName}} {{description}}
      • + {{/formParams}} + {{/isMultipart}} +
      +
      +
      + + + {{#responses}} + {{#-first}} + + + + An enumeration of all specified API response codes. + + + + + {{/-first}} + + + + {{#message}} + Message: {{message}}
      + {{/message}} + {{#dataType}} + Datatype: {{dataType}}
      + {{/dataType}} +
      +
      +
      + {{#-last}} +
      +
      +
      + {{/-last}} + {{/responses}} +
      @@ -225,7 +407,8 @@ {{#operations}} {{#operation}} - + + {{/operation}} {{/operations}} {{/apis}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache index 096cdc9392..39fac4680c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema_soap.mustache @@ -1,123 +1,72 @@ - - +{{! - + Copyright the original author or authors. - - - - - - - - - - - - - - - - + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - - - - - - - - - - - - - - - - + http://www.apache.org/licenses/LICENSE-2.0 - - - - - - - - - - - - - - - - - - - - - - + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +}} + + + + {{#apiInfo}} - {{#apis}} - {{#operations}} - {{#operation}} - - - - {{operationId}} -

      {{{path}}}

      -
      • - Body: {{description}}
      • -
      -
      -
      - - - - - - - {{^required}}SOAP {{/required}}Body{{summary}}{{#description}} -

      {{description}}

      {{/description}} -
      -
      -
      - -
      -
      -
      -
      + {{#apis}} + {{#operations}} + {{#operation}} + + + + {{notes}} + + + + + + + + + + - {{/operation}} - {{/operations}} - {{/apis}} - {{#apis}} - {{#operations}} - {{#operation}} - + + + + {{notes}} + + + + + + + {{/operation}} + {{/operations}} + {{/apis}} + {{#apis}} + {{#operations}} + {{#operation}} - {{/operation}} - {{/operations}} - {{/apis}} + + + {{/operation}} + {{/operations}} + {{/apis}} {{/apiInfo}}
      diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache deleted file mode 100644 index be87ee214a..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base.mustache +++ /dev/null @@ -1,239 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.citrus; - -import static org.springframework.util.CollectionUtils.isEmpty; - -import jakarta.annotation.Nullable; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.actions.ReceiveMessageAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.spi.Resources; -import org.citrusframework.message.Message; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.json.JsonMessageValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); - - @Autowired - @Qualifier("{{apiEndpoint}}") - protected HttpClient httpClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected boolean schemaValidation; - protected String schema; - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - protected String responseAcceptType = "*/*"; - protected String responseType = "json"; - protected int responseStatus = 200; - protected String responseReasonPhrase = "OK"; - protected String responseVersion = "HTTP/1.1"; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value - protected Map cookies; - protected Map headers; - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - recieveResponse(context); - } - - /** - * This method receives the HTTP-Response. - * - * @deprecated use {@link {{prefix}}AbstractTestRequest#receiveResponse(TestContext)} instead. - */ - public ReceiveMessageAction recieveResponse(TestContext context) { - - HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); - HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport - .statusCode(responseStatus) - .reasonPhrase(responseReasonPhrase) - .version(responseVersion) - .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - messageBuilderSupport.type(responseType); - httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); - var responseAction = httpClientResponseActionBuilder.build(); - - responseAction.execute(context); - - return responseAction; - } - - public @Nullable Message receiveResponse(TestContext context) { - var responseAction = recieveResponse(context); - - var messageStore = context.getMessageStore(); - return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); - } - - public abstract void sendRequest(TestContext context); - - public void setSchemaValidation(boolean schemaValidation) { - this.schemaValidation = schemaValidation; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setResponseAcceptType(String responseAcceptType) { - this.responseAcceptType = responseAcceptType; - } - - public void setCookie(Map cookies) { - this.cookies = cookies; - } - - public void setHeader(Map headers) { - this.headers = headers; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResponseType(String responseType) { - this.responseType = responseType; - } - - public void setResponseStatus(int responseStatus) { - this.responseStatus = responseStatus; - } - - public void setResponseReasonPhrase(String responseReasonPhrase) { - this.responseReasonPhrase = responseReasonPhrase; - } - - public void setResponseVersion(String responseVersion) { - this.responseVersion = responseVersion; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, - TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - - httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, - httpClientRequestActionBuilder); - - httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); - - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); - } - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeByBeans( - GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, httpClientRequestActionBuilder); - } - } - return httpClientRequestActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache deleted file mode 100644 index 04f3c5568c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/test_base_soap.mustache +++ /dev/null @@ -1,182 +0,0 @@ -{{>licenseInfo}} - -package {{invokerPackage}}.citrus; - -import java.util.List; -import java.util.ServiceLoader; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.spi.Resources; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction.SoapMessageBuilderSupport; -import org.citrusframework.ws.actions.SendSoapMessageAction; -import org.citrusframework.ws.actions.SoapActionBuilder; -import org.citrusframework.ws.client.WebServiceClient; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.util.CollectionUtils; - -import javax.sql.DataSource; -import java.util.Map; - -{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} -public abstract class {{prefix}}AbstractTestRequest extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("{{#lambda.uppercase}}{{prefix}}{{/lambda.uppercase}}-API-COVERAGE"); - - @Autowired - @Qualifier("{{apiEndpoint}}") - protected WebServiceClient wsClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'XPATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'XPATH' as key and the 'VALUE TO BE VALIDATED' as value - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - protected Map soapHeaders; - protected Map mimeHeaders; - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - receiveResponse(context); - } - - /** - * This method receives the HTTP-Response - */ - public void receiveResponse(TestContext context) { - - ReceiveSoapMessageAction.Builder soapReceiveMessageActionBuilder = new SoapActionBuilder().client(wsClient).receive(); - SoapMessageBuilderSupport messageBuilderSupport = soapReceiveMessageActionBuilder.getMessageBuilderSupport(); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!CollectionUtils.isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!CollectionUtils.isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - soapReceiveMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapReceiveMessageActionBuilder.build().execute(context); - } - - public abstract void sendRequest(TestContext context); - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - public void setSoapHeader(Map soapHeaders) { - this.soapHeaders = soapHeaders; - } - - public void setMimeHeader(Map mimeHeaders) { - this.mimeHeaders = mimeHeaders; - } - - protected SendSoapMessageAction.Builder customizeBuilder(GeneratedApi generatedApi, - TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - sendSoapMessageActionBuilder = customizeByBeans(generatedApi, context, sendSoapMessageActionBuilder); - - sendSoapMessageActionBuilder = customizeBySpi(generatedApi, context, sendSoapMessageActionBuilder); - - return sendSoapMessageActionBuilder; - } - - private SendSoapMessageAction.Builder customizeBySpi(GeneratedApi generatedApi, TestContext context, - SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - sendSoapMessageActionBuilder = service.build(generatedApi, this, context, sendSoapMessageActionBuilder); - } - - return sendSoapMessageActionBuilder; - } - - private SendSoapMessageAction.Builder customizeByBeans( - GeneratedApi generatedApi, TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - sendSoapMessageActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, sendSoapMessageActionBuilder); - } - } - - return sendSoapMessageActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java new file mode 100644 index 0000000000..07eb532c9b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java @@ -0,0 +1,177 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.servers.Server; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenOperation; +import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenParameter; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.openapitools.codegen.CodegenConfigLoader; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; + +/** + * This test validates the code generation process. + */ +class CitrusJavaCodegenTest { + + private CitrusJavaCodegen codegen; + + @BeforeEach + void setUp() { + codegen = new CitrusJavaCodegen(); + } + + @Test + void retrieveGeneratorBySpi() { + CitrusJavaCodegen codegen = (CitrusJavaCodegen) CodegenConfigLoader.forName("java-citrus"); + assertThat(codegen).isNotNull(); + } + + @Test + void arePredefinedValuesNotEmptyTest() { + CitrusJavaCodegen codegen = new CitrusJavaCodegen(); + + assertThat(codegen.getName()).isEqualTo(CODEGEN_NAME); + assertThat(codegen.getHelp()).isNotEmpty(); + assertThat(codegen.getHttpClient()).isNotEmpty(); + assertThat(codegen.getApiPrefix()).isNotEmpty(); + assertThat(codegen.getTargetXmlnsNamespace()).isNull(); + assertThat(codegen.getGeneratedSchemaFolder()).isNotEmpty(); + } + + @Test + void testGetName() { + assertThat(codegen.getName()).isEqualTo("java-citrus"); + } + + @Test + void testGetHelp() { + String helpMessage = codegen.getHelp(); + assertThat(helpMessage).isEqualTo("Generates citrus api requests."); + } + + @Test + void testAdditionalPropertiesConfiguration() { + assertThat(codegen.additionalProperties()) + .containsEntry("apiVersion", "1.0.0") + .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST) + .containsEntry("useJakartaEe", true); + } + + @Test + void testReservedWordsConfiguration() { + assertThat(codegen.reservedWords()) + .contains("name", "description", "httpclient") + .doesNotContain("nonReservedWord"); + } + + @Test + void testTypeMappings() { + assertThat(codegen.typeMapping()) + .containsEntry("binary", "Resource") + .containsEntry("file", "Resource"); + } + + @Test + void testProcessOptsWithApiType() { + codegen.additionalProperties().put(CitrusJavaCodegen.API_TYPE, "XXX"); + + assertThatThrownBy(() -> codegen.processOpts()) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unknown API_TYPE: 'XXX'"); + } + + @Test + void testProcessOptsValidApiType() { + codegen.additionalProperties().put(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST); + codegen.processOpts(); + + assertThat(codegen.additionalProperties()) + .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST); + } + + @Test + void testPreprocessOpenAPI() { + OpenAPI openAPI = new OpenAPI(); + Info info = new Info(); + Map extensions = new HashMap<>(); + extensions.put("x-api-owner", "citrus-framework"); + extensions.put("x-api-version", "2.0.0"); + info.setExtensions(extensions); + openAPI.setInfo(info); + + codegen.preprocessOpenAPI(openAPI); + + assertThat(codegen.additionalProperties()) + .containsEntry("x-api-owner", "citrus-framework") + .containsEntry("x-api-version", "2.0.0") + .containsEntry("infoExtensions", extensions); + } + + @Test + void testFromProperty() { + // Mock schema + Schema schema = Mockito.mock(Schema.class); + + // Call fromProperty and verify conversion + CodegenProperty codegenProperty = codegen.fromProperty("name", schema, true); + assertThat(codegenProperty) + .isInstanceOf(CodegenProperty.class) + .hasFieldOrPropertyWithValue("name", "_name") + .hasFieldOrPropertyWithValue("required", true); + } + + @Test + void testFromFormProperty() { + Schema schema = Mockito.mock(Schema.class); + + @SuppressWarnings("unchecked") + Set imports = Mockito.mock(Set.class); + + CodegenParameter codegenParameter = codegen.fromFormProperty("formParam", schema, imports); + assertThat(codegenParameter) + .isInstanceOf(CustomCodegenParameter.class) + .hasFieldOrPropertyWithValue("paramName", "formParam"); + } + + @Test + void testFromParameter() { + Parameter parameter = Mockito.mock(Parameter.class); + + @SuppressWarnings("unchecked") + Set imports = Mockito.mock(Set.class); + + CodegenParameter codegenParameter = codegen.fromParameter(parameter, imports); + assertThat(codegenParameter) + .isInstanceOf(CustomCodegenParameter.class); + } + + @Test + void testFromOperation() { + Operation operation = Mockito.mock(Operation.class); + List servers = Collections.emptyList(); + + CodegenOperation codegenOperation = codegen.fromOperation("/path", "GET", operation, servers); + assertThat(codegenOperation) + .isInstanceOf(CustomCodegenOperation.class) + .hasFieldOrPropertyWithValue("httpMethod", "GET") + .hasFieldOrPropertyWithValue("path", "/path"); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java similarity index 80% rename from test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java rename to test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java index 1d205f9400..1af4ffa9f6 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java @@ -3,12 +3,11 @@ import static java.nio.file.Files.readString; import static java.nio.file.Files.walk; import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.openapi.generator.JavaCitrusCodegenTest.getAbsoluteTargetDirectoryPath; -import static org.citrusframework.openapi.generator.JavaCitrusCodegenTest.getAbsoluteTestResourcePath; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.File; import java.io.IOException; +import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Stream; @@ -25,31 +24,25 @@ /** * This test case is designed to validate the consistency of the code generation process and detect * any discrepancies between the generated API files and the reference files stored in - * '/JavaCitrusCodegenIT/expectedgen/'. It compares the results of API generation against the + * '/ExpectedCodeGenIT/expectedgen/'. It compares the results of API generation against the * reference files, and a failure indicates potential changes in mustache templates or code * generation logic. *

      * If this test fails, it is essential to review the code generation process and underlying * templates carefully. If the changes are intentional and verified, update the reference files by - * copying the generated API sources to the '/JavaCitrusCodegenIT/expectedgen/' directory. To ensure + * copying the generated API sources to the '/ExpectedCodeGenIT/expectedgen/' directory. To ensure * accurate copying, without unwanted code formatting, use a simple File Explorer instead of relying * on IDE-based operations. */ -class JavaCitrusCodegenIT { +class ExpectedCodeGenIT { public static final String BASE_PACKAGE = "org/citrusframework/openapi/generator"; - private static long countFilesRecursively(Path dir) throws IOException { - try (Stream walk = walk(dir)) { - return walk.filter(Files::isRegularFile).count(); - } - } - @Test void noAdditionalFiles() throws IOException { long expectedFileCount = countFilesRecursively( Path.of(getAbsoluteTestResourcePath( - BASE_PACKAGE + "/JavaCitrusCodegenIT/expectedgen/rest"))); + BASE_PACKAGE + "/ExpectedCodeGenIT/expectedgen/rest"))); long actualFileCount = countFilesRecursively( Path.of(getAbsoluteTargetDirectoryPath( "generated-test-sources/" + BASE_PACKAGE + "/rest"))); @@ -114,7 +107,7 @@ private static Stream geClassResourcesIgnoringInnerClasses(String pat private void assertFileContent(File file, String apiDir) throws IOException { assertThat(file).exists(); - String expectedFilePath = BASE_PACKAGE + "/JavaCitrusCodegenIT/expectedgen/" + file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(apiDir)); + String expectedFilePath = BASE_PACKAGE + "/ExpectedCodeGenIT/expectedgen/" + file.getAbsolutePath().substring(file.getAbsolutePath().indexOf(apiDir)); ClassPathResource classPathResource = new ClassPathResource(expectedFilePath); String actualContent = readString(file.toPath()); @@ -129,4 +122,29 @@ private void assertFileContent(File file, String apiDir) throws IOException { assertThat(actualContent).isEqualTo(expectedContent); } + + private static long countFilesRecursively(Path dir) throws IOException { + try (Stream walk = walk(dir)) { + return walk.filter(Files::isRegularFile).count(); + } + } + + /** + * Get the absolute path to the test resources directory. + */ + static String getAbsoluteTestResourcePath(String pathToFileInTestResources) { + URL resourceUrl = CitrusJavaCodegenTest.class.getClassLoader().getResource(pathToFileInTestResources); + assert resourceUrl != null; + File inputSpecFile = new File(resourceUrl.getFile()); + return inputSpecFile.getAbsolutePath(); + } + + /** + * Get the absolute path to the project's target directory. + */ + static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { + String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project + File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); + return outputDirFile.getAbsolutePath(); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java deleted file mode 100644 index 4ad6df823a..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedApiIT.java +++ /dev/null @@ -1,628 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.message.MessagePayloadUtils.normalizeWhitespace; -import static org.citrusframework.util.FileUtils.readToString; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.networknt.schema.JsonSchema; -import com.networknt.schema.ValidationMessage; -import jakarta.servlet.http.Cookie; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Stream; -import org.assertj.core.api.InstanceOfAssertFactories; -import org.citrusframework.Citrus; -import org.citrusframework.CitrusInstanceManager; -import org.citrusframework.TestAction; -import org.citrusframework.TestCase; -import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; -import org.citrusframework.common.SpringXmlTestLoader; -import org.citrusframework.common.TestLoader; -import org.citrusframework.config.CitrusSpringConfig; -import org.citrusframework.context.TestContext; -import org.citrusframework.endpoint.EndpointConfiguration; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.exceptions.ValidationException; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.http.client.HttpEndpointConfiguration; -import org.citrusframework.http.message.HttpMessage; -import org.citrusframework.json.schema.SimpleJsonSchema; -import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; -import org.citrusframework.message.DefaultMessage; -import org.citrusframework.message.Message; -import org.citrusframework.messaging.Producer; -import org.citrusframework.messaging.SelectiveConsumer; -import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi.PostFileRequest; -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.AddPetRequest; -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; -import org.citrusframework.spi.Resources; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.api.parallel.Isolated; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.core.io.Resource; -import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.TestPropertySource; -import org.springframework.util.MultiValueMap; - -/** - * This test tests the generated API - */ -@Isolated -@DirtiesContext -@ExtendWith({CitrusSpringExtension.class}) -@SpringBootTest(classes = {CitrusSpringConfig.class, GeneratedApiIT.Config.class}) -@TestPropertySource( - properties = { - "applicationServiceClient.basic.username=Max Mustermann", - "applicationServiceClient.basic.password=Top secret" - } -) -class GeneratedApiIT { - - @Autowired - private ApplicationContext applicationContext; - - @Autowired - private HttpClient httpClientMock; - - @Mock - private Producer producerMock; - - @Mock - private SelectiveConsumer consumerMock; - - private TestContext testContext; - - @BeforeEach - void beforeEach() { - testContext = applicationContext.getBean(TestContext.class); - } - - @Test - void testValidationFailure() { - mockProducerAndConsumer(createReceiveMessage("{\"some\": \"payload\"}")); - assertThatThrownBy( - () -> executeTest("getPetByIdRequestTest", testContext)).hasCauseExactlyInstanceOf( - ValidationException.class); - } - - @Nested - class WithValidationMatcher { - - @BeforeEach - void beforeEach() { - mockProducerAndConsumer(createReceiveMessage("")); - } - - @Test - void testSendWithBody() { - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - try { - assertThat(httpMessage.getPayload()) - .isEqualTo( - readToString(Resources.create( - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/addPetMessage.json"), - StandardCharsets.UTF_8) - ); - } catch (IOException e) { - throw new CitrusRuntimeException("Unable to parse file!", e); - } - return true; - }; - - sendAndValidateMessage("sendWithBodyTest", messageMatcher); - } - - @Test - void testSendWithBodyLiteralWithVariable() { - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(((String) httpMessage.getPayload()).trim()).isEqualTo("{\"id\": 15}"); - return true; - }; - sendAndValidateMessage("sendWithBodyLiteralWithVariableTest", messageMatcher); - } - - @Test - void testXCitrusApiHeaders() { - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(httpMessage.getHeader("x-citrus-api-name")).isEqualTo("petstore"); - assertThat(httpMessage.getHeader("x-citrus-app")).isEqualTo("PETS"); - assertThat(httpMessage.getHeader("x-citrus-api-version")).isEqualTo("1.0.0"); - return true; - }; - - sendAndValidateMessage("sendWithBodyLiteralTest", messageMatcher); - } - - @Test - void testSendWithExtraHeaders() { - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(httpMessage.getHeader("h1")).isEqualTo("v1"); - assertThat(httpMessage.getHeader("h2")).isEqualTo("v2"); - return true; - }; - - sendAndValidateMessage("sendWithExtraHeaderTest", messageMatcher); - } - - @Test - void testSendWithBodyLiteral() { - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(((String) httpMessage.getPayload()).trim()).isEqualTo("{\"id\": 13}"); - return true; - }; - - sendAndValidateMessage("sendWithBodyLiteralTest", messageMatcher); - } - - private void sendAndValidateMessage(String testName, - ArgumentMatcher messageMatcher) { - GeneratedApiIT.this.sendAndValidateMessage(testName, messageMatcher, - AddPetRequest.class); - } - - } - - @Nested - class WithMultipartMessage { - - @Test - void testSendMultipartFile() { - mockProducerAndConsumer(createReceiveMessage("")); - - ArgumentMatcher messageMatcher = message -> { - assertThat(message.getPayload()).isInstanceOf(MultiValueMap.class); - MultiValueMap multiValueMap = (MultiValueMap) message.getPayload(); - List multipartFile = multiValueMap.get("multipartFile"); - try { - assertThat(((Resource) multipartFile.get(0)).getURL().toString()) - .endsWith( - "test-classes/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"); - } catch (IOException e) { - throw new CitrusRuntimeException("Unable to parse file!", e); - } - - return true; - }; - - sendAndValidateMessage("postFileTest", messageMatcher, PostFileRequest.class); - } - - @Test - void testSendMultipartWithFileAttribute() { - Message payload = createReceiveMessage("{\"id\": 1}"); - mockProducerAndConsumer(payload); - - executeTest("multipartWithFileAttributesTest", testContext); - ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); - Object producedMessagePayload = messageArgumentCaptor.getValue().getPayload(); - assertThat(producedMessagePayload).isInstanceOf(MultiValueMap.class); - - Object templateValue = ((MultiValueMap) producedMessagePayload).get("template"); - assertThat(templateValue) - .asInstanceOf(InstanceOfAssertFactories.LIST) - .element(0) - .hasFieldOrPropertyWithValue("path", - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/MultipartTemplate.xml"); - - Object additionalDataValue = ((MultiValueMap) producedMessagePayload).get( - "additionalData"); - assertThat(additionalDataValue) - .asInstanceOf(InstanceOfAssertFactories.LIST) - .element(0) - .hasFieldOrPropertyWithValue("path", - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/AdditionalData.json"); - - Object schemaValue = ((MultiValueMap) producedMessagePayload).get("_schema"); - assertThat(schemaValue) - .asInstanceOf(InstanceOfAssertFactories.LIST) - .element(0) - .hasFieldOrPropertyWithValue("path", - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/Schema.json"); - } - - @Test - void testSendMultipartWithPlainText() { - mockProducerAndConsumer(createReceiveMessage("{\"id\": 1}")); - executeTest("multipartWithPlainTextTest", testContext); - ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); - String producedMessagePayload = normalizeWhitespace( - messageArgumentCaptor.getValue().getPayload().toString(), - true, - true - ); - - String expectedPayload = - "{template=[ ], additionalData=[ {\"data1\":\"value1\"} ], _schema=[ {\"schema\":\"mySchema\"} ]}"; - assertThat(producedMessagePayload).isEqualTo(expectedPayload); - } - - @Test - void testSendMultipartWithMultipleDatatypes() { - Message receiveMessage = createReceiveMessage("{\"id\": 1}"); - mockProducerAndConsumer(receiveMessage); - - executeTest("multipartWithMultipleDatatypesTest", testContext); - ArgumentCaptor messageArgumentCaptor = ArgumentCaptor.forClass(Message.class); - verify(producerMock).send(messageArgumentCaptor.capture(), eq(testContext)); - String producedMessagePayload = normalizeWhitespace( - messageArgumentCaptor.getValue().getPayload().toString(), - true, - true - ); - - String expectedPayload = "{stringData=[Test], booleanData=[true], integerData=[1]}"; - assertThat(producedMessagePayload).isEqualTo(expectedPayload); - } - } - - @Nested - class WithDefaultReceiveMessage { - - private Message defaultRecieveMessage; - - @BeforeEach - void beforeEach() throws IOException { - defaultRecieveMessage = createReceiveMessage( - readToString(Resources.create( - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), - StandardCharsets.UTF_8) - ); - mockProducerAndConsumer(defaultRecieveMessage); - } - - @Test - void testJsonPathExtraction() { - TestCase testCase = executeTest("jsonPathExtractionTest", testContext); - TestAction testAction = testCase.getActions().get(0); - assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); - - assertThat(testContext.getVariable("name")).isEqualTo("Snoopy"); - assertThat(testContext.getVariable("id")).isEqualTo("12"); - } - - @Test - void testCustomizer() { - TestCase testCase = executeTest("getPetByIdRequestTest", testContext); - - TestAction testAction = testCase.getActions().get(0); - assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); - - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(httpMessage.getHeader("x-citrus-api-version")).isEqualTo( - "1.0.0"); - - return true; - }; - verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); - verify(consumerMock).receive(testContext, 5000L); - } - - @Test - void testBasicAuthorization() { - TestCase testCase = executeTest("getPetByIdRequestTest", testContext); - - TestAction testAction = testCase.getActions().get(0); - assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); - - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(httpMessage.getHeader("Authorization")).isEqualTo( - "Basic YWRtaW46dG9wLXNlY3JldA=="); - return true; - }; - verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); - verify(consumerMock).receive(testContext, 5000L); - } - - @Test - void testRequestPath() { - TestCase testCase = executeTest("getPetByIdRequestTest", testContext); - TestAction testAction = testCase.getActions().get(0); - assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); - - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - assertThat(httpMessage.getHeader("citrus_request_path")).isEqualTo("/pet/1234"); - return true; - }; - verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); - verify(consumerMock).receive(testContext, 5000L); - } - - @Test - void testCookies() { - TestCase testCase = executeTest("getPetByIdRequestTest", testContext); - TestAction testAction = testCase.getActions().get(0); - assertThat(testAction).isInstanceOf(GetPetByIdRequest.class); - - ArgumentMatcher messageMatcher = message -> { - HttpMessage httpMessage = (HttpMessage) message; - Cookie cookie1 = httpMessage.getCookies().get(0); - Cookie cookie2 = httpMessage.getCookies().get(1); - assertThat(cookie1.getName()).isEqualTo("c1"); - assertThat(cookie1.getValue()).isEqualTo("v1"); - assertThat(cookie2.getName()).isEqualTo("c2"); - assertThat(cookie2.getValue()).isEqualTo("v2"); - return true; - }; - verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); - verify(consumerMock).receive(testContext, 5000L); - } - - @Test - void testJsonPathValidation() { - TestCase testCase = executeTest("jsonPathValidationTest", testContext); - assertTestActionType(testCase, GetPetByIdRequest.class); - } - - @Test - void scriptValidationFailureTest() { - TestCase testCase = executeTest("scriptValidationTest", testContext); - assertTestActionType(testCase, GetPetByIdRequest.class); - } - - @Test - void jsonSchemaValidationFailureTest() { - assertThatThrownBy(() -> executeTest("jsonSchemaValidationFailureTest", testContext)) - .hasCauseExactlyInstanceOf(ValidationException.class); - - SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( - "failingTestSchema"); - - // Assert that schema validation was called - verify(testSchema).getSchema(); - JsonSchema schema = testSchema.getSchema(); - verify(schema).validate(any()); - } - - @Test - void jsonDeactivatedSchemaValidationTest() { - SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( - "testSchema"); - Mockito.clearInvocations(testSchema, testSchema.getSchema()); - - TestCase testCase = executeTest("jsonDeactivatedSchemaValidationTest", testContext); - - assertTestActionType(testCase, GetPetByIdRequest.class); - - // Assert that schema validation was called - Mockito.verifyNoInteractions(testSchema); - } - - @Test - void defaultOas3SchemaValidationTest() { - SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean("oas3"); - Mockito.clearInvocations(testSchema, testSchema.getSchema()); - - TestCase testCase = executeTest("defaultOas3SchemaValidationTest", testContext); - - assertTestActionType(testCase, GetPetByIdRequest.class); - - // Assert that schema validation was called - verify(testSchema).getSchema(); - JsonSchema schema = testSchema.getSchema(); - verify(schema).validate(any()); - } - - @Test - void jsonSchemaValidationTest() { - SimpleJsonSchema testSchema = (SimpleJsonSchema) applicationContext.getBean( - "testSchema"); - Mockito.clearInvocations(testSchema, testSchema.getSchema()); - - TestCase testCase = executeTest("jsonSchemaValidationTest", testContext); - - assertTestActionType(testCase, GetPetByIdRequest.class); - - // Assert that schema validation was called - verify(testSchema).getSchema(); - JsonSchema schema = testSchema.getSchema(); - verify(schema).validate(any()); - } - - @Test - void testJsonPathValidationFailure() { - mockProducerAndConsumer(defaultRecieveMessage); - - assertThatThrownBy(() -> executeTest("jsonPathValidationFailureTest", testContext)) - .hasCauseExactlyInstanceOf(ValidationException.class); - } - - private static Stream testValidationFailures() { - return Stream.of( - Arguments.of("failOnStatusTest", - "Values not equal for header element 'citrus_http_status_code', expected '201' but was '200'"), - Arguments.of( - "failOnReasonPhraseTest", - "Values not equal for header element 'citrus_http_reason_phrase', expected 'Almost OK' but was 'OK'" - ), - Arguments.of( - "failOnVersionTest", - "Values not equal for header element 'citrus_http_version', expected 'HTTP/1.0' but was 'HTTP/1.1'" - ) - ); - } - - @ParameterizedTest - @MethodSource - void testValidationFailures(String testName, String expectedErrorMessage) { - assertThatThrownBy(() -> executeTest(testName, testContext)) - .hasCauseExactlyInstanceOf(ValidationException.class) - .message() - .startsWith(expectedErrorMessage); - } - } - -// @Test -// void testCoverageLogger() throws IOException { -// List logMessages = new ArrayList<>(); -// Logger logger = LoggerFactory.getLogger(GetPetByIdRequest.class); -// org.qos.logback.classic.Logger l = (org.qos.logback.classic.Logger) logger; -// l.setLevel(Level.TRACE); -// l.addAppender( -// new AppenderBase<>() { -// @Override -// protected void append(ILoggingEvent eventObject) {} -// -// @Override -// public synchronized void doAppend(ILoggingEvent eventObject) { -// logMessages.add(eventObject.getMessage()); -// super.doAppend(eventObject); -// } -// } -// ); -// -// -// -// mockProducer(httpClient); -// -// Message receiveMessage = createReceiveMessage( -// FileUtils.readToString(Resources.create("org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), StandardCharsets.UTF_8) -// ); -// -// mockConsumer(httpClient, testContext, receiveMessage); -// -// executeTest("getPetByIdRequestTest", testContext); -// -// assertThat(logMessages.get(0)).isEqualTo("getPetById;GET;\"{}\";\"\";\"\""); -// } - - /** - * Test the send message using the given matcher - */ - private void sendAndValidateMessage(String testName, ArgumentMatcher messageMatcher, - Class apiClass) { - - TestCase testCase = executeTest(testName, testContext); - assertTestActionType(testCase, apiClass); - - verify(producerMock).send(ArgumentMatchers.argThat(messageMatcher), eq(testContext)); - } - - /** - * Assert that an action of type 'apiClass' is contained in the list of test actions - */ - private void assertTestActionType(TestCase testCase, Class apiClass) { - TestAction testAction = testCase - .getActions() - .stream() - .filter(action -> apiClass.isAssignableFrom(action.getClass())) - .findAny() - .orElse(null); - assertThat(testAction).isNotNull(); - } - - private void mockProducerAndConsumer(Message receiveMessage) { - when(httpClientMock.createProducer()).thenReturn(producerMock); - when(httpClientMock.createConsumer()).thenReturn(consumerMock); - when(consumerMock.receive(testContext, 5000L)).thenReturn(receiveMessage); - } - - private TestCase executeTest(String testName, TestContext testContext) { - assertThat(CitrusInstanceManager.get()).isPresent(); - - Citrus citrus = CitrusInstanceManager.get().get(); - TestLoader loader = new SpringXmlTestLoader().citrusContext(citrus.getCitrusContext()) - .citrus(citrus) - .context(testContext); - loader.setTestName(testName); - loader.setPackageName("org.citrusframework.openapi.generator.GeneratedApiTest"); - loader.load(); - return loader.getTestCase(); - } - - private Message createReceiveMessage(String payload) { - Message receiveMessage = new DefaultMessage(); - receiveMessage.setPayload(payload); - receiveMessage.getHeaders().put("citrus_http_reason_phrase", "OK"); - receiveMessage.getHeaders().put("citrus_http_version", "HTTP/1.1"); - receiveMessage.getHeaders().put("citrus_http_status_code", 200); - return receiveMessage; - } - - public static class Config { - - @Bean(name = {"applicationServiceClient", "multipartTestEndpoint", - "soapSampleStoreEndpoint", "petStoreEndpoint"}) - public HttpClient applicationServiceClient() { - HttpClient clientMock = mock(); - EndpointConfiguration endpointConfigurationMock = mock(); - when(clientMock.getEndpointConfiguration()).thenReturn(new HttpEndpointConfiguration()); - when(endpointConfigurationMock.getTimeout()).thenReturn(5000L); - return clientMock; - } - - @Bean - public ApiActionBuilderCustomizerService customizer() { - return new ApiActionBuilderCustomizerService() { - @Override - public > T build( - GeneratedApi generatedApi, TestAction action, TestContext context, T builder) { - builder.getMessageBuilderSupport() - .header("x-citrus-api-version", generatedApi.getApiVersion()); - return builder; - } - }; - } - - @Bean({"oas3", "testSchema"}) - public SimpleJsonSchema testSchema() { - JsonSchema schemaMock = mock(); - SimpleJsonSchema jsonSchemaMock = mock(); - - when(jsonSchemaMock.getSchema()).thenReturn(schemaMock); - - Set okReport = new HashSet<>(); - when(schemaMock.validate(any())).thenReturn(okReport); - return jsonSchemaMock; - } - - @Bean - public SimpleJsonSchema failingTestSchema() { - JsonSchema schemaMock = mock(); - SimpleJsonSchema jsonSchemaMock = mock(); - - when(jsonSchemaMock.getSchema()).thenReturn(schemaMock); - - Set nokReport = new HashSet<>(); - nokReport.add(new ValidationMessage.Builder().customMessage( - "This is a simulated validation error message").build()); - when(schemaMock.validate(any())).thenReturn(nokReport); - return jsonSchemaMock; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java new file mode 100644 index 0000000000..7124bb9536 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -0,0 +1,3510 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMap; +import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; +import static org.springframework.http.HttpStatus.OK; + +import jakarta.servlet.http.Cookie; +import java.io.IOException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import org.assertj.core.api.Assertions; +import org.citrusframework.TestActor; +import org.citrusframework.TestCaseRunner; +import org.citrusframework.annotations.CitrusResource; +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.annotations.CitrusTestSource; +import org.citrusframework.common.TestLoader; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.MessageTimeoutException; +import org.citrusframework.exceptions.TestCaseFailedException; +import org.citrusframework.exceptions.ValidationException; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpServerRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.generator.GeneratedRestApiIT.Config; +import org.citrusframework.openapi.generator.rest.extpetstore.model.PetIdentifier; +import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; +import org.citrusframework.openapi.generator.rest.extpetstore.spring.ExtPetStoreBeanConfiguration; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdReceiveActionBuilder; +import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; +import org.citrusframework.spi.Resources; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.SocketUtils; +import org.citrusframework.validation.json.JsonPathVariableExtractor; +import org.citrusframework.validation.script.ScriptValidationContext; +import org.citrusframework.variable.GlobalVariables; +import org.citrusframework.variable.MessageHeaderVariableExtractor; +import org.citrusframework.ws.endpoint.builder.WebServiceEndpoints; +import org.citrusframework.ws.server.WebServiceServer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; + +/** + * This integration test class for the generated TestAPI aims to comprehensively test all aspects of + * accessing the API using both Java and XML. In addition to serving as a test suite, it also acts + * as a reference example. + * + *

      Therefore, each test is designed to be self-contained and straightforward, allowing + * anyone reviewing the code to easily grasp the purpose and context of the test without needing to + * rely on shared setup or utility methods. + */ + +@ExtendWith(CitrusSpringExtension.class) +@SpringBootTest(classes = {PetStoreBeanConfiguration.class, ExtPetStoreBeanConfiguration.class, + CitrusSpringConfig.class, Config.class}, properties = { + "extpetstore.basic.username=extUser", + "extpetstore.basic.password=extPassword", + "extpetstore.bearer.token=defaultBearerToken", + "extpetstore.api-key-query=defaultTopSecretQueryApiKey", + "extpetstore.api-key-header=defaultTopSecretHeaderApiKey", + "extpetstore.api-key-cookie=defaultTopSecretCookieApiKey", + "extpetstore.base64-encode-api-key=true" +} +) +class GeneratedRestApiIT { + + public static final List PET_ID_LIST = List.of(1, 2); + public static final List PET_ID_AS_STRING_LIST = List.of("1", "2"); + public static final List PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST = List.of("${one}", + "${two}"); + + public static final PetIdentifier PET_IDENTIFIER = new PetIdentifier()._name("Louis") + .alias("Alexander"); + public static final String PET_IDENTIFIER_AS_STRING = """ + {"alias":"Alexander","name":"Louis"}"""; + + @Autowired + private HttpServer httpServer; + + @Autowired + private HttpServer otherHttpServer; + + @Autowired + private PetApi petApi; + + @Autowired + private ExtPetApi extPetApi; + + @Autowired + private TestActor petStoreActor; + + @Autowired + private HttpClient otherApplicationServiceClient; + + /** + * Demonstrates usage of parameter serialization according to + * ... + */ + @Nested + class ParameterSerialization { + + @Nested + class PathParameter { + + @Nested + class SimpleStyle { + + @Nested + class Array { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleArray(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleArray(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleArray$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when( + extPetApi.sendGetPetWithSimpleStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithSimpleStyleObject( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithSimpleStyleObject$(PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); + } + + } + + @Nested + class ExplodedArray { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(extPetApi.sendGetPetWithSimpleStyleArrayExploded(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/exploded/1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(extPetApi.sendGetPetWithSimpleStyleArrayExploded(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when( + extPetApi.sendGetPetWithSimpleStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when( + extPetApi.sendGetPetWithSimpleStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); + } + + } + } + + @Nested + class LabelStyle { + + @Nested + class Array { + + /** + * Non exploded representation is currently not supported by validator. + * Therefore, we get a validation exception. The other tests use disabled + * request validation to overcome this issue. + */ + @Test + void throws_request_validation_exception( + @CitrusResource TestCaseRunner runner) { + + HttpClientRequestActionBuilder builder = extPetApi.sendGetPetWithLabelStyleArray( + PET_ID_LIST) + .fork(false); + + assertThatThrownBy(() -> runner.when(builder)) + .isInstanceOf(TestCaseFailedException.class) + .hasCauseInstanceOf(ValidationException.class) + .hasMessageContaining( + "ERROR - Instance type (string) does not match any allowed primitive type (allowed: [\"integer\"]): []"); + } + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleArray(List.of(1)) + .schemaValidation(true) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/.1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleArray(PET_ID_LIST) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleArray$(PET_ID_AS_STRING_LIST) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + runner.variable("one", "1"); + runner.variable("two", "2"); + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when( + extPetApi.sendGetPetWithLabelStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleObject( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleObject$(""" + {"name":"Louis","alias":"Alexander"} + """) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); + } + } + + @Nested + class ExplodedArray { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(extPetApi.sendGetPetWithLabelStyleArrayExploded(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/exploded/.1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(extPetApi.sendGetPetWithLabelStyleArrayExploded(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when( + extPetApi.sendGetPetWithLabelStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when( + extPetApi.sendGetPetWithLabelStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded$(""" + {"name":"Louis","alias":"Alexander"} + """) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); + } + } + + } + + @Nested + class MatrixStyle { + + @Nested + class Array { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithMatrixStyleArray(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithMatrixStyleArray(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithMatrixStyleArray$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when( + extPetApi.sendGetPetWithMatrixStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithMatrixStyleObject( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithMatrixStyleObject$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); + } + + } + + @Nested + class ExplodedArray { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when( + extPetApi.sendGetPetWithMatrixStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when( + extPetApi.sendGetPetWithMatrixStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get( + "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); + } + + } + } + } + + @Nested + class HeaderParameter { + + @Nested + class SimpleStyle { + + @Nested + class Array { + + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$( + PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithSimpleStyleObjectHeader( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/object") + .message().header("petId", "alias,Alexander,name,Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithSimpleStyleObjectHeader$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/object") + .message().header("petId", "alias,Alexander,name,Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + } + + } + + @Nested + class ArrayExploded { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( + PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithSimpleStyleExplodedObjectHeader( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded/object") + .message().header("petId", "alias=Alexander,name=Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when( + extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithSimpleStyleExplodedObjectHeader$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/header/simple/exploded/object") + .message().header("petId", "alias=Alexander,name=Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when( + extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); + } + } + + } + + } + + @Nested + class QueryParameter { + + @Nested + class FormStyle { + + @Nested + class Array { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleQuery(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + + } + + @Test + void java_arrya_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleQuery(PET_ID_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_arrya_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleQuery$(PET_ID_AS_STRING_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_arrya_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when(extPetApi.sendGetPetWithFormStyleQuery$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithFormStyleObjectQuery( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/object") + .message().queryParam("petId", "alias,Alexander,name,Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi + .sendGetPetWithFormStyleObjectQuery$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/object") + .message().queryParam("petId", "alias,Alexander,name,Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); + } + } + + @Nested + class ArrayExploded { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message().queryParam("petId", "1")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(PET_ID_LIST) + .fork(true)); + + // Note that citrus currently fails to validate a query parameter array. Thus, we + // assert against the query_params header. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when( + extPetApi.sendGetPetWithFormStyleExplodedQuery$(PET_ID_AS_STRING_LIST) + .fork(true)); + + // Note that citrus currently fails to validate a query parameter array. Thus, we + // assert against the query_params header. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + // Note that citrus currently fails to validate a query parameter array. Thus, we + // assert against the query_params header. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi + .sendGetPetWithFormStyleExplodedObjectQuery( + PET_IDENTIFIER) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded/object") + .message() + .queryParam("alias", "Alexander") + .queryParam("name", "Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi + .sendGetPetWithFormStyleExplodedObjectQuery$( + PET_IDENTIFIER_AS_STRING) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/form/exploded/object") + .message() + .queryParam("alias", "Alexander") + .queryParam("name", "Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); + } + } + } + + @Nested + class DeepObjectStyleExploded { + + @Nested + class ArrayExploded { + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi + .sendGetPetWithDeepObjectTypeQuery( + PET_IDENTIFIER) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/deep/object") + .message() + .queryParam("petId[alias]", "Alexander") + .queryParam("petId[name]", "Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); + } + + @Test + void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi + .sendGetPetWithDeepObjectTypeQuery$( + PET_IDENTIFIER_AS_STRING) + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/query/deep/object") + .message() + .queryParam("petId[alias]", "Alexander") + .queryParam("petId[name]", "Louis")); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); + } + } + } + } + + @Nested + class CookieParameter { + + @Nested + class FormStyle { + + @Nested + class Array { + + @Test + void java_single_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleCookie(List.of(1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + + @Test + void java_array_value(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleCookie(PET_ID_LIST) + .fork(true)); + + // Cookies may not contain "," which is used to separate array values. + // Therefore, cookies are URL encoded and reach the server accordingly. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + + @Test + void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithFormStyleCookie$(PET_ID_AS_STRING_LIST) + .fork(true)); + + // Cookies may not contain "," which is used to separate array values. + // Therefore, cookies are URL encoded and reach the server accordingly. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + + @Test + void java_array_value_non_type_safe_with_variables( + @CitrusResource TestCaseRunner runner) { + + runner.variable("one", "1"); + runner.variable("two", "2"); + + runner.when(extPetApi.sendGetPetWithFormStyleCookie$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); + + // Cookies may not contain "," which is used to separate array values. + // Therefore, cookies are URL encoded and reach the server accordingly. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + + @Test + void java_object_value(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); + + // Cookies may not contain "," which is used to separate array values. + // Therefore, cookies are URL encoded and reach the server accordingly. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form/object") + .message() + .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + + @Test + void java_object_value_none_type(@CitrusResource TestCaseRunner runner) { + + // Note that we need to disable oas validation here, as validation is + // currently not supported with the chosen serialization approach. + runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); + + // Cookies may not contain "," which is used to separate array values. + // Therefore, cookies are URL encoded and reach the server accordingly. + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/cookie/form/object") + .message() + .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); + + runner.then(http().server(httpServer) + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); + + } + } + } + } + + /** + * Demonstrates testing of array data in query parameters. + */ + @Nested + class Combined { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withArrayQueryDataTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + runner.variable("nick1", "Wind"); + runner.variable("nick2", "Storm"); + runner.variable("tag2", "tag2Value"); + + runner.when(extPetApi + .sendUpdatePetWithArrayQueryData$("${petId}", "Thunder", "sold", + List.of("tag1", "${tag2}"), + List.of("${nick1}", "${nick2}"), "header1") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/ext/pet/1234") + .message() + .validate(ScriptValidationContext.Builder.groovy().script(""" + assert receivedMessage.getHeader("sampleStringHeader") == header1 + org.assertj.core.api.Assertions.assertThat(((org.citrusframework.http.message.HttpMessage)receivedMessage).getQueryParams()).containsExactlyInAnyOrderEntriesOf( + java.util.Map.of( + "tags", java.util.List.of("tag1", "tag2Value"), + "name", java.util.List.of("Thunder"), + "nicknames", java.util.List.of("Wind", "Storm"), + "status", java.util.List.of("sold") + """)) + .validate((message, context) -> { + assertThat(message.getHeader("sampleStringHeader")).isEqualTo("header1"); + assertThat( + ((HttpMessage) message).getQueryParams()).containsExactlyInAnyOrderEntriesOf( + Map.of( + "tags", List.of("tag1", "tag2Value"), + "name", List.of("Thunder"), + "nicknames", List.of("Wind", "Storm"), + "status", List.of("sold") + ) + ); + })); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(extPetApi + .receiveUpdatePetWithArrayQueryData(OK) + .message()); + + } + } + } + + /** + * Demonstrates the usage of form data. + */ + @Nested + class FormData { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFormDataTest") + void xml() { + } + + @Test + void updatePetWithForm_java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(petApi.sendUpdatePetWithForm$("${petId}") + ._name("Tom") + .status("sold") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .post("/api/v3/pet/${petId}") + .message() + .queryParam("name", "Tom") + .queryParam("status", "sold")); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(petApi.receiveUpdatePetWithForm("200")); + + } + } + + /** + * Demonstrates the usage of validation is disablement in API requests and + * responses. + */ + @Nested + class DisabledValidation { + + /** + * Test scenarios where response validation is disabled for the API requests. + */ + @Nested + class ResponseValidationDisabled { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withResponseValidationDisabledTest") + void xml() { + } + + @Test + void java( + @CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); + + runner.when(petApi + .receiveGetPetById(OK) + .schemaValidation(false)); + + } + } + } + + /** + * Contains test cases for scenarios where validation failures are expected. + */ + @Nested + class ValidationFailures { + + /** + * Tests where validation fails due to an incorrect reason phrase in the API response. + */ + @Nested + class FailOnReasonPhrase { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnReasonPhraseTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi + .receiveGetPetById(OK).message().reasonPhrase("Almost OK"); + assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_reason_phrase', expected 'Almost OK' but was 'OK'") + .hasCauseInstanceOf(ValidationException.class); + } + } + + /** + * Tests where validation fails due to an incorrect HTTP status in the API response. + */ + @Nested + class FailOnStatus { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnStatusTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi + .receiveGetPetById("201"); + assertThatThrownBy(() -> runner.when(getPetByIdResponseActionBuilder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_reason_phrase', expected 'CREATED' but was 'OK'") + .hasCauseInstanceOf(ValidationException.class); + } + } + + /** + * Tests where validation fails due to an incorrect HTTP version in the API response. + */ + @Nested + class FailOnVersion { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnVersionTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi + .receiveGetPetById(OK).message().version("HTTP/1.0"); + assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_version', expected 'HTTP/1.0' but was 'HTTP/1.1'") + .hasCauseInstanceOf(ValidationException.class); + } + } + + /** + * Tests where validation fails due to an invalid response body. + */ + @Nested + class FailOnInvalidResponse { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnInvalidResponseTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); + + GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi.receiveGetPetById( + OK); + assertThatThrownBy(() -> runner.when(getPetByIdResponseActionBuilder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining("Object has missing required properties ([\"name\"]): []") + .hasCauseInstanceOf(ValidationException.class); + + } + } + + /** + * Tests where validation fails due to an incorrect body resource during validation. + */ + @Nested + class FailOnBodyResourceValidation { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnBodyResourceValidationTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi + .receiveGetPetById(OK).message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json")); + assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining( + "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") + .hasCauseInstanceOf(ValidationException.class); + + } + } + + /** + * Tests where validation fails due to incorrect data in the response body. + */ + @Nested + class FailOnBodyDataValidation { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnBodyDataValidationTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi + .receiveGetPetById(OK).message().body(""" + {"description": "no pet"}"""); + assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( + TestCaseFailedException.class) + .hasMessageContaining( + "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") + .hasCauseInstanceOf(ValidationException.class); + + } + } + + /** + * Tests where validation fails due to invalid JSON path expressions in the response body. + */ + @Nested + class FailOnJsonPathInvalid { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFailOnJsonPathInvalidTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi + .receiveGetPetById(OK).message() + .validate(jsonPath().expression("$.name", "unknown")); + assertThatThrownBy(() -> runner.when(builder)) + .isInstanceOf(TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for element '$.name', expected 'unknown' but was") + .hasCauseInstanceOf(ValidationException.class); + + } + } + } + + /** + * Demonstrates the usage of a TestActor to control execution of test actions. + */ + @Nested + class Actor { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withActorTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .actor(petStoreActor) + .fork(true)); + + HttpMessageBuilderSupport builder = http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@"); + + assertThatThrownBy(() -> runner.$(builder)) + .isInstanceOf(TestCaseFailedException.class) + .hasCauseInstanceOf(MessageTimeoutException.class) + .hasMessageContaining( + "Action timeout after 5000 milliseconds. Failed to receive message on endpoint: 'httpServer.inbound'"); + } + } + + /** + * Demonstrates the usage of a specific URI for sending HTTP requests in tests. + */ + @Nested + class SpecificUri { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withSpecificUriTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .uri("http://localhost:${petstoreApplicationPort}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + ); + } + } + + /** + * Demonstrates the usage of a specific endpoint for sending HTTP requests in tests. + */ + @Nested + class SpecificEndpoint { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withSpecificEndpointTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}").endpoint(otherApplicationServiceClient) + .fork(true)); + + runner.then(http().server(otherHttpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(otherHttpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK).endpoint(otherApplicationServiceClient) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + ); + } + } + + /** + * Demonstrates the usage of a nested element within an XML configuration for + * testing. + */ + @Nested + class NestedReceiveInXml { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withNestedReceiveInXmlTest") + void xml() { + } + + } + + /** + * Demonstrates the usage of different authentication mechanisms for testing. + */ + @Nested + class Security { + + @Nested + class BasicAuthentication { + + /** + * Demonstrates basic authentication using global credentials from properties. + */ + @Nested + class BasicAuthenticationFromProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBasicAuthenticationFromPropertiesTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-basic/pet/${petId}") + .message() + .header("Authorization", "Basic ZXh0VXNlcjpleHRQYXNzd29yZA==")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithBasicAuthentication(OK) + .message()); + + } + + } + + /** + * Demonstrates specific basic authentication with custom credentials. + */ + @Nested + class WithBasicAuthenticationOverridingProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBasicAuthenticationOverridingPropertiesTest") + void xml() { + } + + @Test + void java( + @CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") + .basicAuthUsername("admin") + .basicAuthPassword("topSecret") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-basic/pet/${petId}") + .message().header("Authorization", "Basic YWRtaW46dG9wU2VjcmV0")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithBasicAuthentication(OK) + .message()); + + } + + } + } + + @Nested + class BearerAuthentication { + + /** + * Demonstrates bearer authentication using a global token from properties. + */ + @Nested + class WithBasicBearerAuthenticationFromProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBasicBearerAuthenticationFromPropertiesTest") + void xml() { + } + + @Test + void java( + @CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-bearer/pet/${petId}") + .message() + .header("Authorization", "Bearer ZGVmYXVsdEJlYXJlclRva2Vu")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithBearerAuthentication(OK) + .message()); + + } + } + + /** + * Demonstrates bearer authentication using specific token. + */ + @Nested + class WithBasicBearerAuthenticationOverridingProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBasicBearerAuthenticationOverridingPropertiesTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") + .basicAuthBearer("bearerToken") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-bearer/pet/${petId}") + .message().header("Authorization", "Bearer YmVhcmVyVG9rZW4=")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithBearerAuthentication(OK) + .message()); + + } + + } + + } + + + @Nested + class ApiKeyAuthentication { + + + /** + * Demonstrates API key authentication using default values from properties. + */ + @Nested + class ApiKeyAuthenticationFromProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withApiKeysFromPropertiesTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-api-key/pet/${petId}") + .message() + .header("api_key_header", + "citrus:encodeBase64('defaultTopSecretHeaderApiKey')") + .cookie(new Cookie("api_key_cookie", + "citrus:encodeBase64('defaultTopSecretCookieApiKey')")) + .queryParam("api_key_query", + "citrus:encodeBase64('defaultTopSecretQueryApiKey')") + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithApiKeyAuthentication(OK) + .schemaValidation(false)); + } + + } + + /** + * Demonstrates API key authentication with custom values overriding properties. + */ + @Nested + class ApiKeyAuthenticationOverridingProperties { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withApiKeysOverridingPropertiesTest") + void xml() { + } + + @Test + void java( + @CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + runner.variable("apiKeyHeader", "TopSecretHeader"); + runner.variable("apiKeyCookie", "TopSecretCookie"); + runner.variable("apiKeyQuery", "TopSecretQuery"); + + runner.when(extPetApi + .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") + .apiKeyHeader("${apiKeyHeader}") + .apiKeyCookie("${apiKeyCookie}") + .apiKeyQuery("${apiKeyQuery}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/secure-api-key/pet/${petId}") + .message() + .header("api_key_header", "citrus:encodeBase64('TopSecretHeader')") + .cookie( + new Cookie("api_key_cookie", "citrus:encodeBase64('TopSecretCookie')")) + .queryParam("api_key_query", "citrus:encodeBase64('TopSecretQuery')") + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetByIdWithApiKeyAuthentication(OK) + .schemaValidation(false)); + } + } + } + } + + /** + * Demonstrates testing of multipart requests. + */ + @Nested + class Multipart { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withMultiPartTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) throws IOException { + + byte[] templateData = FileUtils.copyToByteArray( + Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin")); + String additionalData = FileUtils.readToString(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json")); + + runner.when(extPetApi.sendGenerateVaccinationReport$( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin", + "1") + .additionalData(additionalData) + .optIntVal(100) + .optBoolVal(true) + .optStringVal("a") + .optNumberVal(BigDecimal.valueOf(1L)) + .optDateVal(LocalDate.of(2024, 12, 1)) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .post("/api/v3/ext/pet/vaccination/status-report") + .message() + .validate((message, context) -> + Assertions.assertThat(multipartMessageToMap((HttpMessage) message)) + .containsExactlyInAnyOrderEntriesOf(Map.of( + "additionalData", additionalData, + "reqIntVal", "1", + "template", templateData, + "optIntVal", "100", + "optBoolVal", "true", + "optDateVal", "[2024,12,1]", + "optNumberVal", "1", + "optStringVal", "a")) + ) + ); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message().contentType("application/pdf") + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf"))); + + runner.then(extPetApi.receiveGenerateVaccinationReport(OK)); + } + } + + /** + * Demonstrates testing of requests using additional, non-API query parameters, headers, and + * cookies. + */ + @Nested + class NonApiQueryParameters { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withNonApiQueryParamTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(petApi.sendUpdatePet() + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .queryParam("nonApiQueryParam", "nonApiQueryParamValue") + .header("nonApiHeader", "nonApiHeaderValue") + .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/pet") + .message() + .queryParam("nonApiQueryParam", "nonApiQueryParamValue") + .header("nonApiHeader", "nonApiHeaderValue") + .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(petApi.receiveUpdatePetWithForm("200")); + + } + + } + + /** + * Demonstrates testing of form URL-encoded data in requests. + */ + @Nested + class FormUrlEncoded { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFormUrlEncodedTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + runner.variable("nick1", "Wind"); + runner.variable("nick2", "Storm"); + runner.variable("tag2", "tag2Value"); + + runner.when(extPetApi + .sendUpdatePetWithFormUrlEncoded$("${petId}", "Thunder", "sold", "5", + List.of("tag1", "${tag2}")) + .nicknames( + "${nick1}", + "${nick2}", + URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", + StandardCharsets.UTF_8) + ) + .owners("2") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/ext/pet/form/1234") + .message() + .contentType("application/x-www-form-urlencoded") + .validate((Message message, TestContext context) -> + assertThat(message.getPayload(String.class)) + .contains("name=Thunder") + .contains("status=sold") + .contains("nicknames=Wind") + .contains("nicknames=Storm") + .contains("tags=tag2") + .contains("tags=tag2Value") + .contains("age=5") + .contains( + "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + )); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(extPetApi + .receiveUpdatePetWithFormUrlEncoded(OK) + .message()); + + } + } + + /** + * Demonstrates testing of requests using the type-safe Java DSL. + */ + @Nested + class TypeSafeJavaDsl { + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + runner.variable("nick1", "Wind"); + runner.variable("nick2", "Storm"); + runner.variable("tag2", "tag2Value"); + + runner.when(extPetApi + .sendUpdatePetWithFormUrlEncoded(1234L, "Thunder", "sold", 5, + List.of("tag1", "${tag2}")) + .nicknames( + "${nick1}", + "${nick2}", + URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", + StandardCharsets.UTF_8) + ) + .owners("2") + .fork(true)); + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/ext/pet/form/1234") + .message() + .contentType("application/x-www-form-urlencoded") + .validate((Message message, TestContext context) -> + assertThat(message.getPayload(String.class)) + .contains("name=Thunder") + .contains("status=sold") + .contains("nicknames=Wind") + .contains("nicknames=Storm") + .contains("tags=tag2") + .contains("tags=tag2Value") + .contains("age=5") + .contains( + "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + )); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(extPetApi + .receiveUpdatePetWithFormUrlEncoded(OK) + .message()); + + } + } + + /** + * Demonstrates testing of plain text bodies in requests. + */ + @Nested + class BodyAsPlainText { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBodyAsPlainTextTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(petApi.sendUpdatePet() + .message().body(""" + { + "id": ${petId}, + "name": "citrus:randomEnumValue('hasso','cutie','fluffy')", + "category": { + "id": ${petId}, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" + } + """) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/pet") + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(petApi.receiveUpdatePetWithForm("200")); + + } + } + + /** + * Demonstrates testing of request bodies read from resources. + */ + @Nested + class BodyFromResource { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withBodyFromResourceTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "citrus:randomNumber(10)"); + + runner.when(petApi.sendUpdatePet() + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .put("/api/v3/pet") + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + + runner.then(http().server(httpServer) + .send() + .response(OK)); + + runner.when(petApi.receiveUpdatePetWithForm("200")); + + } + } + + /** + * Demonstrates testing of control response bodies from plain text. + */ + @Nested + class ReceiveBodyFromPlainText { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withReceiveBodyFromPlainTextTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK) + .message() + .body(""" + { + "id": ${petId}, + "name": "@matches('hasso|cutie|fluffy')@", + "category": { + "id": ${petId}, + "name": "@matches('dog|cat|fish')@" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "@matches('available|pending|sold')@" + } + """) + ); + } + } + + /** + * Demonstrates testing of control response bodies from resource. + */ + @Nested + class ReceiveBodyFromResource { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withReceiveBodyFromResourceTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json")) + ); + } + } + + /** + * Demonstrates testing of received non-API cookies. + */ + @Nested + class ReceiveNonApiCookie { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withReceiveNonApiCookieTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + ); + } + } + + /** + * Demonstrates validation of response by JSON path validation. + */ + @Nested + class JsonPathValidation { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withJsonPathValidationTest") + void xml() { + } + + @Test + @CitrusTest + void java(@CitrusResource TestCaseRunner runner) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.then(petApi.receiveGetPetById(OK) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + ); + } + } + + /** + * Demonstrates extraction of response data using JSON path. + */ + @Nested + class JsonPathExtraction { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withJsonPathExtractionTest") + void xml() { + } + + @Test + void java( + @CitrusResource TestCaseRunner runner, @CitrusResource TestContext context) { + + runner.variable("petId", "1234"); + + runner.when(petApi + .sendGetPetById$("${petId}") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(petApi + .receiveGetPetById(OK) + .message() + .extract(MessageHeaderVariableExtractor.Builder.fromHeaders() + .expression("Content-Type", "varContentType")) + .extract(JsonPathVariableExtractor.Builder.fromJsonPath() + .expression("$.name", "varName"))) + ; + + assertThat(context.getVariable("varContentType")).isEqualTo("application/json"); + assertThat(context.getVariable("varName")).matches("hasso|cutie|fluffy"); + } + } + + /** + * Demonstrates testing of API cookies in requests. + */ + @Nested + class ApiCookie { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withApiCookieTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + runner.variable("petId", "1234"); + + runner.when(extPetApi + .sendGetPetWithCookie$("${petId}", "cookieValue") + .optTrxId("trxId") + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/${petId}") + .message() + .cookie(new Cookie("session_id", "cookieValue")) + .cookie(new Cookie("opt_trx_id", "trxId")) + ); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); + + runner.when(extPetApi + .receiveGetPetWithCookie(OK) + .message()); + } + } + + /** + * Demonstrates testing of file uploads and validations of the response. + */ + @Nested + class FileUpload { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withFileUploadTest") + void uploadFile_xml() { + } + + @Test + @CitrusTest + void uploadFile_java(@CitrusResource TestCaseRunner runner) { + + String additionalMetadata = "myMeta"; + String file = "filedata"; + + runner.variable("petId", "1234"); + + runner.when(petApi.sendUploadFile$("${petId}") + .additionalMetadata(additionalMetadata) + .message() + .body(file) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .post("/api/v3/pet/${petId}/uploadImage") + .message() + .contentType("application/octet-stream") + .queryParam("additionalMetadata", "myMeta") + .validate((message, context) -> { + Object payload = message.getPayload(); + assertThat(payload).isInstanceOf(byte[].class); + assertThat(new String((byte[]) payload, StandardCharsets.UTF_8)).isEqualTo( + "filedata"); + }) + ); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(""" + {"code": 12, "type":"post-image-ok", "message":"image successfully uploaded"} + """) + .contentType("application/json")); + + runner.then(petApi + .receiveUploadFile(OK) + .message() + .validate(jsonPath().expression("$.code", "12")) + .validate(jsonPath().expression("$.message", "image successfully uploaded"))); + } + } + + @TestConfiguration + public static class Config { + + private final int port = SocketUtils.findAvailableTcpPort(8080); + + private final int otherPort = SocketUtils.findAvailableTcpPort(8081); + + private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + + /** + * Main http client for accessing the main http server. + */ + @Bean(name = {"petstore.endpoint", "extpetstore.endpoint"}) + public HttpClient applicationServiceClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .handleCookies(true) + .build(); + } + + /** + * Http client accessing "other" server, see configuration of other server bean below. + */ + @Bean + public HttpClient otherApplicationServiceClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(otherPort)) + .build(); + } + + /** + * A sample actor used to test actor configuration and functionality. + */ + @Bean + public TestActor petStoreActor() { + TestActor petStoreActor = new TestActor(); + petStoreActor.setName("PetStoreActor"); + petStoreActor.setDisabled(true); + return petStoreActor; + } + + /** + * Http server for mocking server side messaging and asserting data being send from test api + * requests. + */ + @Bean + public HttpServer httpServer() { + return new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .handleCookies(true) + .handleHandleSemicolonPathContent(true) + .build(); + } + + @Bean + public WebServiceServer soapServer() { + return WebServiceEndpoints.soap().server() + .port(wsPort) + .timeout(5000) + .autoStart(true) + .build(); + } + + /** + * A second http server. Mainly for tests that assert, that the default endpoint + * configuration can be overridden by an explicit endpoint. + */ + @Bean + public HttpServer otherHttpServer() { + return new HttpServerBuilder() + .port(otherPort) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + } + + /* + * Global variables, that make the ports available within the test context. Mainly + * used to access to port for explicit endpoint configuration tests. + */ + @Bean + public GlobalVariables globalVariables() { + return new GlobalVariables.Builder() + .variable("petstoreApplicationPort", port) + .variable("otherPetstoreApplicationPort", otherPort).build(); + } + +// @Bean +// public ApiActionBuilderCustomizer petApiCustomizer() { +// return new ApiActionBuilderCustomizer() { +// @Override +// public T customizeRequestBuilder( +// GeneratedApi generatedApi, T builder) { +// return ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApi, +// builder); +// } +// +// @Override +// public T customizeResponseBuilder( +// GeneratedApi generatedApi, T builder) { +// return ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApi, +// builder); +// } +// }; +// } + } +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java new file mode 100644 index 0000000000..ac8289eb9e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java @@ -0,0 +1,117 @@ +package org.citrusframework.openapi.generator; + +import static org.citrusframework.ws.actions.SoapActionBuilder.soap; + +import org.citrusframework.TestCaseRunner; +import org.citrusframework.annotations.CitrusResource; +import org.citrusframework.annotations.CitrusTestSource; +import org.citrusframework.common.TestLoader; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; +import org.citrusframework.openapi.generator.GeneratedSoapApiIT.Config; +import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; +import org.citrusframework.openapi.generator.soap.bookservice.spring.BookServiceBeanConfiguration; +import org.citrusframework.util.SocketUtils; +import org.citrusframework.ws.client.WebServiceClient; +import org.citrusframework.ws.client.WebServiceClientBuilder; +import org.citrusframework.ws.endpoint.builder.WebServiceEndpoints; +import org.citrusframework.ws.server.WebServiceServer; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +/** + * This integration test class for the generated TestAPI aims to comprehensively test all aspects of + * accessing the API using both Java and XML. In addition to serving as a test suite, it also acts + * as a reference example. + * + *

      Therefore, each test is designed to be self-contained and straightforward, allowing + * anyone reviewing the code to easily grasp the purpose and context of the test without needing to + * rely on shared setup or utility methods. + */ + +@ExtendWith(CitrusSpringExtension.class) +@SpringBootTest(classes = {BookServiceBeanConfiguration.class, CitrusSpringConfig.class, Config.class} +) +class GeneratedSoapApiIT { + + + @Autowired + private WebServiceServer soapServer; + + @Autowired + private BookServiceSoapApi bookServiceSoapApi; + + @Nested + class SoapApi { + + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withSoapTest") + void xml() { + } + + @Test + void java(@CitrusResource TestCaseRunner runner) { + String request = """ + + + Lord of the Rings + J.R.R. Tolkien + + + """; + runner.when(bookServiceSoapApi.sendAddBook().fork(true).message().body(request)); + + runner.then(soap().server(soapServer) + .receive() + .message() + .body(request)); + + String response = """ + + + Lord of the Rings + J.R.R. Tolkien + + + """; + + runner.then(soap().server(soapServer) + .send() + .message() + .body(response)); + + runner.then(bookServiceSoapApi.receiveAddBook() + .message() + .body(response)); + } + } + + @TestConfiguration + public static class Config { + + private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + + @Bean(name = {"bookstore.endpoint"}) + public WebServiceClient soapClient() { + return new WebServiceClientBuilder() + .defaultUri("http://localhost:%d".formatted(wsPort)) + .build(); + } + + @Bean + public WebServiceServer soapServer() { + return WebServiceEndpoints.soap().server() + .port(wsPort) + .timeout(5000) + .autoStart(true) + .build(); + } + + } +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java new file mode 100644 index 0000000000..db2664db43 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java @@ -0,0 +1,73 @@ +package org.citrusframework.openapi.generator; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.citrusframework.annotations.CitrusResource; +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.config.CitrusSpringConfig; +import org.citrusframework.context.TestContext; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpEndpointConfiguration; +import org.citrusframework.junit.jupiter.spring.CitrusSpringSupport; +import org.citrusframework.openapi.generator.GeneratedSpringBeanConfigurationIT.ClientConfiguration; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; +import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.test.context.ContextConfiguration; + +@CitrusSpringSupport +@ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, + PetStoreBeanConfiguration.class}) +class GeneratedSpringBeanConfigurationIT { + + @Test + @CitrusTest + void petStoreOpenApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { + var petStoreOpenApiRepository = testContext.getReferenceResolver() + .resolve("petStoreOpenApiRepository"); + assertThat(petStoreOpenApiRepository) + .isNotNull(); + } + + @Test + @CitrusTest + void petApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { + var petApi = testContext.getReferenceResolver() + .resolve(PetApi.class); + assertThat(petApi) + .isNotNull(); + } + + @Test + @CitrusTest + void storeApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { + var storeApi = testContext.getReferenceResolver() + .resolve(StoreApi.class); + assertThat(storeApi) + .isNotNull(); + } + + @Test + @CitrusTest + void userApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { + var userApi = testContext.getReferenceResolver() + .resolve(UserApi.class); + assertThat(userApi) + .isNotNull(); + } + + @TestConfiguration + public static class ClientConfiguration { + + @Bean(name = {"petstore.endpoint"}) + public HttpClient applicationServiceClient() { + var config = new HttpEndpointConfiguration(); + config.setRequestUrl("http://localhost:9000"); + return new HttpClient(config); + } + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java deleted file mode 100644 index 77961399e3..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GetPetByIdIT.java +++ /dev/null @@ -1,404 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.container.Assert.Builder.assertException; -import static org.citrusframework.http.actions.HttpActionBuilder.http; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AddressEntityValidationContext.Builder.address; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.allOf; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.anyOf; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext.Builder.oneOf; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder.pet; -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.openApiPetStore; -import static org.citrusframework.util.FileUtils.readToString; -import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; -import org.citrusframework.TestCaseRunner; -import org.citrusframework.annotations.CitrusResource; -import org.citrusframework.annotations.CitrusTest; -import org.citrusframework.config.CitrusSpringConfig; -import org.citrusframework.context.TestContext; -import org.citrusframework.endpoint.EndpointConfiguration; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.http.client.HttpEndpointConfiguration; -import org.citrusframework.http.server.HttpServer; -import org.citrusframework.http.server.HttpServerBuilder; -import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension; -import org.citrusframework.message.DefaultMessage; -import org.citrusframework.message.Message; -import org.citrusframework.messaging.Producer; -import org.citrusframework.messaging.SelectiveConsumer; -import org.citrusframework.openapi.generator.GetPetByIdIT.Config; -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest; -import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AddressEntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; -import org.citrusframework.openapi.generator.sample.PetApi; -import org.citrusframework.spi.BindToRegistry; -import org.citrusframework.spi.Resources; -import org.citrusframework.util.SocketUtils; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpStatus; - -@ExtendWith(CitrusSpringExtension.class) -@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class, Config.class}) -class GetPetByIdIT { - - private final int port = SocketUtils.findAvailableTcpPort(8080); - - @BindToRegistry - private final HttpServer httpServer = new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); - - @Autowired - private GetPetByIdRequest getPetByIdRequest; - - @Autowired - @Qualifier("petStoreEndpoint") - private HttpClient httpClient; - - private String defaultResponse; - - @BeforeEach - public void beforeTest() throws IOException { - defaultResponse = readToString(Resources.create( - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"), - StandardCharsets.UTF_8) ; - - mockProducer(); - mockConsumer(); - } - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void testByEntityMatcher(@CitrusResource TestCaseRunner runner) { - - when(PetApi.openApiPetStore(httpClient) - .getPetById() - .withId("1234") - .fork(true)); - - runner.then(http().server(httpServer) - .receive() - .get("/pet/${petId}") - .message() - .accept("@contains('application/json')@")); - - runner.then(http().server(httpServer) - .send() - .response(HttpStatus.OK) - .message() - .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) - .contentType("application/json")); - - runner.then(openApiPetStore(httpClient) - .receivePetById(HttpStatus.OK) - .message() - .validate(pet().id("1234") - .name("Garfield") - .category("Cat") - .address(address -> address - .street("Nina Hagen Hang") - .zip("12345") - .city("Hagen ATW")) - .owners(anyOf(List.of( - owner -> owner.name("Peter Lustig"), - owner -> owner.name("Hans Meier") - ))) - .owners(oneOf(List.of( - owner -> owner.name("Seppel Hinterhuber") - ))) - .urls(0, "url1") - .urls(1, "url2") - .urls("@contains('url1', 'url2')")). - validate(jsonPath().expression("$.name", "Garfield"))); - - runner.then(openApiPetStore(httpClient) - .receivePetById200() - .withPet(validator -> validator.id("1234") - .name("Garfield") - .category("Cat") - .urls(0,"url1") - .urls(1,"url2") - .urls("@contains('url1', 'url2')")). - validate(jsonPath().expression("$.name", "Garfield")) - ); - } - - @Test - @CitrusTest - void testFindByStatus(@CitrusResource TestCaseRunner runner) { - - when(openApiPetStore(httpClient) - .findByStatus() - .withStatus("SOLD") - .fork(true)); - - runner.then(http().server(httpServer) - .receive() - .get("/pet/${petId}") - .message() - .accept("@contains('application/json')@")); - - runner.then(http().server(httpServer) - .send() - .response(HttpStatus.OK) - .message() - .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) - .contentType("application/json")); - - runner.then(openApiPetStore(httpClient) - .receivePetById(HttpStatus.OK) - .message() - .validate(pet().id("1234") - .name("Garfield") - .category("Cat") - .address(address -> address - .street("Nina Hagen Hang") - .zip("12345") - .city("Hagen ATW")) - .owners(anyOf(List.of( - owner -> owner.name("Peter Lustig"), - owner -> owner.name("Hans Meier") - ))) - .owners(oneOf(List.of( - owner -> owner.name("Seppel Hinterhuber") - ))) - .urls(0, "url1") - .urls(1, "url2") - .urls("@contains('url1', 'url2')")). - validate(jsonPath().expression("$.name", "Garfield"))); - - runner.then(openApiPetStore(httpClient) - .receivePetById200() - .withPet(validator -> validator.id("1234") - .name("Garfield") - .category("Cat") - .urls(0,"url1") - .urls(1,"url2") - .urls("@contains('url1', 'url2')")). - validate(jsonPath().expression("$.name", "Garfield")) - ); - } - - @Test - @CitrusTest - void testByJsonPath(@CitrusResource TestCaseRunner runner) { - - when(openApiPetStore(httpClient) - .getPetById() - .withPetId("1234") - .fork(true)); - - runner.then(http().server(httpServer) - .receive() - .get("/pet/${petId}") - .message() - .accept("@contains('application/json')@")); - - runner.then(http().server(httpServer) - .send() - .response(HttpStatus.OK) - .message() - .body(Resources.create("classpath:org/citrusframework/openapi/petstore/pet.json")) - .contentType("application/json")); - - runner.then(openApiPetStore(httpClient) - .receivePetById(HttpStatus.OK) - .message().validate(jsonPath().expression("$.name", "Garfield")) - ); - } - - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void testValidationFailureByJsonPath(@CitrusResource TestCaseRunner runner) { - - // Given - getPetByIdRequest.setPetId("1234"); - - // Then - getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); - getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); - - // Assert body by json path - getPetByIdRequest.setResponseValue(Map.of("$.name", "Garfield")); - - // When - runner.$(assertException() - .exception(org.citrusframework.exceptions.CitrusRuntimeException.class) - .message("Values not equal for element '$.name', expected 'Garfield' but was 'Snoopy'") - .when( - getPetByIdRequest - ) - ); - // When - - } - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void testByResource(@CitrusResource TestCaseRunner runner) { - - // Given - getPetByIdRequest.setPetId("1234"); - - // Then - getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); - getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); - // Assert body by resource - getPetByIdRequest.setResource( - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"); - - // When - runner.$(getPetByIdRequest); - } - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void testValidationFailureByResource(@CitrusResource TestCaseRunner runner) { - - // Given - getPetByIdRequest.setPetId("1234"); - - // Then - getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); - getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); - // Assert body by resource - getPetByIdRequest.setResource( - "org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json"); - - // When - runner.$(assertException() - .exception(org.citrusframework.exceptions.CitrusRuntimeException.class) - .message("Values not equal for entry: '$['name']', expected 'Garfield' but was 'Snoopy'") - .when( - getPetByIdRequest - ) - ); - } - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void validateByVariable(@CitrusResource TestContext testContext, - @CitrusResource TestCaseRunner runner) { - - // Given - getPetByIdRequest.setPetId("1234"); - - // Then - getPetByIdRequest.setResponseStatus(HttpStatus.OK.value()); - getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase()); - - // Assert load data into variables - getPetByIdRequest.setResponseVariable(Map.of("$", "RESPONSE", "$.id", "ID")); - - // When - runner.$(getPetByIdRequest); - - // Then - assertThat(testContext) - .satisfies( - c -> assertThat(c.getVariable("RESPONSE")) - .isNotNull(), - c -> assertThat(c.getVariable("ID")) - .isNotNull() - .isEqualTo("12") - ); - } - - /** - * TODO #1161 - Improve with builder pattern - */ - @Test - @CitrusTest - void validateReceivedResponse(@CitrusResource TestContext testContext) { - - // Given - getPetByIdRequest.setPetId("1234"); - - // When - getPetByIdRequest.sendRequest(testContext); - - // Then - Message receiveResponse = getPetByIdRequest.receiveResponse(testContext); - assertThat(receiveResponse) - .isNotNull() - .extracting(Message::getPayload) - .asString() - .isEqualToIgnoringWhitespace(defaultResponse); - assertThat(receiveResponse.getHeaders()) - .containsEntry("citrus_http_status_code", 200) - .containsEntry("citrus_http_reason_phrase", "OK"); - } - - private void mockProducer() { - Producer producerMock = mock(); - when(httpClient.createProducer()).thenReturn(producerMock); - } - - private void mockConsumer() { - Message receiveMessage = createReceiveMessage(); - - SelectiveConsumer consumer = mock(SelectiveConsumer.class); - when(httpClient.createConsumer()).thenReturn(consumer); - when(consumer.receive(any(), eq(5000L))).thenReturn(receiveMessage); - } - - private Message createReceiveMessage() { - Message receiveMessage = new DefaultMessage(); - receiveMessage.setPayload(defaultResponse); - receiveMessage.getHeaders().put("citrus_http_reason_phrase", "OK"); - receiveMessage.getHeaders().put("citrus_http_version", "HTTP/1.1"); - receiveMessage.getHeaders().put("Content-Type", 200); - receiveMessage.getHeaders().put("citrus_http_status_code", 200); - return receiveMessage; - } - - @TestConfiguration - public static class Config { - - @Bean(name = {"applicationServiceClient", "petStoreEndpoint"}) - public HttpClient applicationServiceClient() { - HttpClient client = mock(HttpClient.class); - EndpointConfiguration endpointConfiguration = mock(EndpointConfiguration.class); - when(client.getEndpointConfiguration()).thenReturn(new HttpEndpointConfiguration()); - when(endpointConfiguration.getTimeout()).thenReturn(5000L); - return client; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java deleted file mode 100644 index f3860de3b4..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/JavaCitrusCodegenTest.java +++ /dev/null @@ -1,219 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.openapitools.codegen.ClientOptInput; -import org.openapitools.codegen.CodegenConfigLoader; -import org.openapitools.codegen.DefaultGenerator; -import org.openapitools.codegen.config.CodegenConfigurator; - -/** - * This test validates the code generation process. - *

      - * It may also serve as an entry point for debugging the code generation process. When executed in debug mode, it allows you to - * step through the generation process and inspect the resulting output in the specified output directory. - *

      - * To debug the code generator: - *

        - *
      1. Set a breakpoint in the {@code postProcessOperationsWithModels()} method of {@code JavaCitrusCodegen.java}.
      2. - *
      3. In your IDE, launch this test by right-clicking and selecting Debug As > JUnit Test.
      4. - *
      - */ - -class JavaCitrusCodegenTest { - - /** - * Get the absolute path to the test resources directory. - * - * @param pathToFileInTestResources The file within {@code src/test/resources} to look for - * @return the absolute path to the file - */ - static String getAbsoluteTestResourcePath(String pathToFileInTestResources) { - URL resourceUrl = JavaCitrusCodegenTest.class.getClassLoader().getResource(pathToFileInTestResources); - assert resourceUrl != null; - File inputSpecFile = new File(resourceUrl.getFile()); - return inputSpecFile.getAbsolutePath(); - } - - /** - * Get the absolute path to the project's target directory. - * - * @param pathToFileInTargetDirectory The file within {@code target} to look for - * @return the absolute path to the file - */ - static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { - String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project - File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); - return outputDirFile.getAbsolutePath(); - } - - @Test - void retrieveGeneratorBsSpi() { - JavaCitrusCodegen codegen = (JavaCitrusCodegen) CodegenConfigLoader.forName("java-citrus"); - assertThat(codegen).isNotNull(); - } - - @Test - void arePredefinedValuesNotEmptyTest() { - JavaCitrusCodegen codegen = new JavaCitrusCodegen(); - - assertThat(codegen.getName()).isEqualTo(CODEGEN_NAME); - assertThat(codegen.getHelp()).isNotEmpty(); - assertThat(codegen.getHttpClient()).isNotEmpty(); - assertThat(codegen.getOpenapiSchema()).isNotEmpty(); - assertThat(codegen.getApiPrefix()).isNotEmpty(); - assertThat(codegen.getHttpPathPrefix()).isNotEmpty(); - assertThat(codegen.getTargetXmlnsNamespace()).isNull(); - assertThat(codegen.getGeneratedSchemaFolder()).isNotEmpty(); - } - - @Test - void areAdditionalPropertiesProcessedTest() { - final String httpClient = "myTestEndpoint"; - final String openapiSchema = "testSchema"; - final String prefix = "testPrefix"; - final String httpPathPrefix = "test/path"; - final String targetXmlnsNamespace = "http://www.citrusframework.org/schema/test/extension"; - final String generatedSchemaFolder = "generatedResourceFolder"; - - Map properties = new HashMap<>(); - properties.put(JavaCitrusCodegen.API_ENDPOINT, httpClient); - properties.put(JavaCitrusCodegen.GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); - properties.put(JavaCitrusCodegen.HTTP_PATH_PREFIX, httpPathPrefix); - properties.put(JavaCitrusCodegen.OPENAPI_SCHEMA, openapiSchema); - properties.put(JavaCitrusCodegen.PREFIX, prefix); - properties.put(JavaCitrusCodegen.TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); - - JavaCitrusCodegen codegen = new JavaCitrusCodegen(); - codegen.additionalProperties().putAll(properties); - codegen.processOpts(); - - assertThat(codegen.getApiPrefix()).isEqualTo(prefix); - assertThat(codegen.getGeneratedSchemaFolder()).isEqualTo(generatedSchemaFolder); - assertThat(codegen.getHttpClient()).isEqualTo(httpClient); - assertThat(codegen.getHttpPathPrefix()).isEqualTo(httpPathPrefix); - assertThat(codegen.getOpenapiSchema()).isEqualTo(openapiSchema); - assertThat(codegen.getTargetXmlnsNamespace()).isEqualTo(targetXmlnsNamespace); - } - - @Test - void areReservedWordsEscapedTest() throws IOException { - String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore_reservedWords.yaml"); - String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore_escapedWords"); - - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName(CODEGEN_NAME) - .setInputSpec(absoluteInputSpecPath) - .setOutputDir(absoluteOutputDirPath); - - final ClientOptInput clientOptInput = configurator.toClientOptInput(); - DefaultGenerator generator = new DefaultGenerator(); - List outputFiles = generator.opts(clientOptInput).generate(); - - Optional file = outputFiles.stream() - .filter(x -> "PetApi.java".equals(x.getName())) - .findFirst(); - - assertThat(file).isPresent(); - - List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); - - // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat( - lines.stream() - .filter(x -> x.contains("\"name\", this._name")) - .count()) - .isEqualTo(1L); - } - - @Test - void arePathParamsFieldsPresent() throws IOException { - String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore.yaml"); - String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); - - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName(CODEGEN_NAME) - .setInputSpec(absoluteInputSpecPath) - .setOutputDir(absoluteOutputDirPath); - - final ClientOptInput clientOptInput = configurator.toClientOptInput(); - DefaultGenerator generator = new DefaultGenerator(); - List outputFiles = generator.opts(clientOptInput).generate(); - - Optional file = outputFiles.stream() - .filter(x -> "PetApi.java".equals(x.getName())) - .findFirst(); - - assertThat(file).isPresent(); - - List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); - - // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat( - lines.stream() - .filter(x -> x.contains("private String petId;")) - .count()) - .isEqualTo(4L); - assertThat( - lines.stream() - .filter(x -> x.contains( - "endpoint = endpoint.replace(\"{\" + \"petId\" + \"}\", petId);")) - .count()) - .isEqualTo(4L); - } - - @Test - void areBasicAuthFieldsPresent() throws IOException { - String absoluteInputSpecPath = getAbsoluteTestResourcePath("apis/petstore.yaml"); - String absoluteOutputDirPath = getAbsoluteTargetDirectoryPath("JavaCitrusCodegenTest/petstore"); - - final CodegenConfigurator configurator = new CodegenConfigurator() - .setGeneratorName(CODEGEN_NAME) - .setInputSpec(absoluteInputSpecPath) - .setOutputDir(absoluteOutputDirPath); - - final ClientOptInput clientOptInput = configurator.toClientOptInput(); - DefaultGenerator generator = new DefaultGenerator(); - List outputFiles = generator.opts(clientOptInput).generate(); - - Optional file = outputFiles.stream() - .filter(x -> "PetApi.java".equals(x.getName())) - .findFirst(); - - assertThat(file).isPresent(); - - List lines = Files.readAllLines(file.get().toPath(), StandardCharsets.UTF_8); - - // "name" is a reserved word, so it should be escaped with an underline for the second parameter - assertThat( - lines.stream() - .filter(x -> x.contains("@Value(\"${\" + \"apiEndpoint.basic.username:#{null}}\")")) - .count()) - .isEqualTo(1L); - assertThat( - lines.stream() - .filter(x -> x.contains("private String basicUsername;")) - .count()) - .isEqualTo(1L); - assertThat( - lines.stream() - .filter(x -> - x.contains( - "messageBuilderSupport.header(\"Authorization\", \"Basic \" + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+\":\"+context.replaceDynamicContentInString(basicPassword)).getBytes()));" - ) - ) - .count()) - .isEqualTo(1L); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java deleted file mode 100644 index 372219d262..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/OpenApiPetStoreTest.java +++ /dev/null @@ -1,181 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder.pet; -import static org.mockito.Mockito.mock; - -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.ReadContext; -import java.util.Map; -import net.minidev.json.parser.JSONParser; -import net.minidev.json.parser.ParseException; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.functions.DefaultFunctionRegistry; -import org.citrusframework.json.JsonPathUtils; -import org.citrusframework.message.DefaultMessage; -import org.citrusframework.message.Message; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.AggregateEntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.EntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; -import org.citrusframework.validation.AbstractMessageValidator; -import org.citrusframework.validation.DefaultMessageValidatorRegistry; -import org.citrusframework.validation.ValidationUtils; -import org.testng.annotations.Test; - -public class OpenApiPetStoreTest { - - @Test - public void test() { - Builder petValidationContextBuilder = pet().id("1234") - .name("Garfield") - .category("Cat") - .address(address -> address - .street("Nina Hagen Hang") - .zip("12345") - .city("Hagen ATW")) -// .owners(anyOf(List.of( -// owner -> owner.name("Peter Lustig"), -// owner -> owner.name("Hans Meier") -// ))) -// .owners(oneOf(List.of( -// owner -> owner.name("Seppel Hinterhuber") -// ))) -// .urls(0, "url1") -// .urls(1, "url2") -// .urls("@contains('url1', 'url2')") - ; - - PetEntityValidationContext petValidationContext = petValidationContextBuilder.build(); - OpenApiEntityValidator validator = new OpenApiEntityValidator(); - - Message receivedMessage = new DefaultMessage(); - receivedMessage.setPayload(""" - { - "id": 1234, - "name": "Garfield", - "category": "Cat", - "address": { - "street": "Nina Hagen Hang", - "zip": "12345", - "city": "Hagen ATW" - }, - "owners": [ - { - "name": "Peter Lustig" - }, - { - "name": "Hans Meier" - } - ] - } - """); - TestContext testContext = new TestContext(); - testContext.setReferenceResolver(mock()); - testContext.setMessageValidatorRegistry(new DefaultMessageValidatorRegistry()); - testContext.setFunctionRegistry(new DefaultFunctionRegistry()); - - validator.validateMessage(receivedMessage, null, testContext, petValidationContext); - - - } - - public class OpenApiEntityValidator extends - AbstractMessageValidator { - - public void validateMessage(Message receivedMessage, Message controlMessage, - TestContext context, EntityValidationContext validationContext) { - System.out.println("asSD"); - - validateJson(receivedMessage.getPayload(String.class), context, validationContext); - - - } - - private void validateJson(String jsonString, TestContext context, - EntityValidationContext validationContext) { - validateJsonPathExpressions(jsonString, context, validationContext); - validateNestedJsonPathExpressions(jsonString, context, validationContext); - } - - @Override - protected Class getRequiredValidationContextType() { - return EntityValidationContext.class; - } - - @Override - public boolean supportsMessageType(String messageType, Message message) { - return true; - } - - - private void validateJsonPathExpressions(String jsonString, TestContext context, - EntityValidationContext validationContext) { - String jsonPathExpression; - try { - JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE); - Object receivedJson = parser.parse(jsonString); - ReadContext readerContext = JsonPath.parse(receivedJson); - - for (Map.Entry entry : validationContext.getJsonPathExpressions() - .entrySet()) { - Object expectedValue = entry.getValue(); - - jsonPathExpression = context.replaceDynamicContentInString(entry.getKey()); - Object jsonPathResult = JsonPathUtils.evaluate(readerContext, - jsonPathExpression); - - if (expectedValue instanceof EntityValidationContext entityValidationContext) { - validateJson((String) jsonPathResult, context, entityValidationContext); - } else if (expectedValue instanceof AggregateEntityValidationContext) { - - } else { - - if (expectedValue instanceof String) { - //check if expected value is variable or function (and resolve it, if yes) - expectedValue = context.replaceDynamicContentInString( - String.valueOf(expectedValue)); - } - - //do the validation of actual and expected value for element - ValidationUtils.validateValues(jsonPathResult, expectedValue, - jsonPathExpression, context); - - logger.debug("Validating element: {}='{}': OK", jsonPathExpression, - expectedValue); - } - - } - - logger.debug("JSONPath element validation successful: All values OK"); - } catch (ParseException e) { - throw new CitrusRuntimeException("Failed to parse JSON text", e); - } - } - - private void validateNestedJsonPathExpressions(String jsonString, TestContext context, - EntityValidationContext validationContext) { - String jsonPathExpression; - try { - JSONParser parser = new JSONParser(JSONParser.MODE_JSON_SIMPLE); - Object receivedJson = parser.parse(jsonString); - ReadContext readerContext = JsonPath.parse(receivedJson); - - for (Map.Entry entry : validationContext.getNestedValidationContextsBuilders() - .entrySet()) { - - jsonPathExpression = context.replaceDynamicContentInString(entry.getKey()); - Object jsonPathResult = JsonPathUtils.evaluate(readerContext, - jsonPathExpression); - - validateJson(jsonPathResult.toString(), context, entry.getValue()); - - } - - logger.debug("JSONPath element validation successful: All values OK"); - } catch (ParseException e) { - throw new CitrusRuntimeException("Failed to parse JSON text", e); - } - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java deleted file mode 100644 index 419cea9ade..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ServiceLoaderTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import java.util.ServiceLoader; -import java.util.ServiceLoader.Provider; -import org.citrusframework.openapi.generator.util.TestApiActionBuilderCustomizer; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.junit.jupiter.api.Test; - -class ServiceLoaderTest { - - @Test - void test() { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - List> list = serviceLoader.stream().toList(); - assertThat(list).hasSize(1); - ApiActionBuilderCustomizerService apiActionBuilderCustomizerService = list.iterator().next() - .get(); - assertThat(apiActionBuilderCustomizerService).isInstanceOf(TestApiActionBuilderCustomizer.class); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java deleted file mode 100644 index 15dfb85dc3..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SpringBeanConfigurationIT.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.citrusframework.openapi.generator; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.citrusframework.annotations.CitrusResource; -import org.citrusframework.annotations.CitrusTest; -import org.citrusframework.config.CitrusSpringConfig; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.http.client.HttpEndpointConfiguration; -import org.citrusframework.junit.jupiter.spring.CitrusSpringSupport; -import org.citrusframework.openapi.generator.SpringBeanConfigurationIT.ClientConfiguration; -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.AddPetRequest; -import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.test.context.ContextConfiguration; - -@CitrusSpringSupport -@ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, PetStoreBeanConfiguration.class}) -class SpringBeanConfigurationIT { - - @Autowired - private ApplicationContext applicationContext; - - @Test - @CitrusTest - void fromReferenceResolverIsPrototypeScoped(@CitrusResource TestContext testContext) { - var addPetRequest = testContext.getReferenceResolver().resolve(AddPetRequest.class); - assertThat(addPetRequest) - .isNotNull() - .isNotEqualTo(testContext.getReferenceResolver().resolve(AddPetRequest.class)); - } - - @Test - void fromSpringApplicationContextIsPrototypeScoped() { - assertThat(applicationContext.getBean(AddPetRequest.class)) - .isNotNull() - .isNotEqualTo(applicationContext.getBean(AddPetRequest.class)); - } - - @TestConfiguration - public static class ClientConfiguration { - - @Bean(name= {"applicationServiceClient", "petStoreEndpoint"}) - public HttpClient applicationServiceClient() { - var config = new HttpEndpointConfiguration(); - config.setRequestUrl("http://localhost:9000"); - return new HttpClient(config); - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java similarity index 87% rename from test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java rename to test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java index 1ae66986fd..581a3f065a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java @@ -10,14 +10,14 @@ import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; -class SimpleWsdlToOpenApiTransformerTest { +class WsdlToOpenApiTransformerTest { @Test void testTransform() throws WsdlToOpenApiTransformationException, IOException { ClassPathResource wsdlResource = new ClassPathResource( "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl"); - SimpleWsdlToOpenApiTransformer simpleWsdlToOpenApiTransformer = new SimpleWsdlToOpenApiTransformer(wsdlResource.getURI()); + WsdlToOpenApiTransformer simpleWsdlToOpenApiTransformer = new WsdlToOpenApiTransformer(wsdlResource.getURI()); String generatedYaml = simpleWsdlToOpenApiTransformer.transformToOpenApi(); Resource expectedYamlResource = new ClasspathResource( diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java deleted file mode 100644 index 5ed27a3765..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore.java +++ /dev/null @@ -1,306 +0,0 @@ -package org.citrusframework.openapi.generator.sample; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import org.citrusframework.builder.WithExpressions; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.message.DelegatingPathExpressionProcessor; -import org.citrusframework.message.MessageProcessor; -import org.citrusframework.message.MessageProcessorAdapter; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.EntityValidationContext; -import org.citrusframework.openapi.generator.sample.OpenApiPetStore.PetEntityValidationContext.Builder; -import org.citrusframework.openapi.generator.sample.PetApi.FindPetByStatusActionBuilder; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.context.DefaultValidationContext; -import org.citrusframework.validation.context.ValidationContext; -import org.citrusframework.variable.VariableExtractor; -import org.citrusframework.variable.VariableExtractorAdapter; -import org.springframework.http.HttpStatus; - -public class OpenApiPetStore { - - public static OpenApiPetStore openApiPetStore(HttpClient httpClient) { - return new OpenApiPetStore(); - } - - public GetPetIdRequestActionBuilder getPetById() { - return new GetPetIdRequestActionBuilder(); - } - - public FindPetByStatusActionBuilder findByStatus() { - return new PetApi.FindPetByStatusActionBuilder(); - } - - public static class GetPetIdRequestActionBuilder extends HttpClientRequestActionBuilder { - - public GetPetIdRequestActionBuilder withPetId(String petId) { - return this; - } - - } - - public GetPetIdResponseActionBuilder receivePetById(HttpStatus status) { - return new GetPetIdResponseActionBuilder(); - } - - public GetPetIdResponseActionBuilder200 receivePetById200() { - return new GetPetIdResponseActionBuilder200(); - } - - public static class GetPetIdResponseActionBuilder extends HttpClientResponseActionBuilder { - - } - - // Per configured response - public static class GetPetIdResponseActionBuilder200 extends HttpClientResponseActionBuilder { - - public HttpMessageBuilderSupport withPet( - Consumer validator) { - PetEntityValidationContext.Builder builder = new PetEntityValidationContext.Builder(); - validator.accept(builder); - return message().validate(builder); - } - } - - public static class EntityValidationContext extends DefaultValidationContext { - - private Map expressions; - - - private Map nestedValidationContextsBuilders = new HashMap<>(); - - public EntityValidationContext(Builder builder) { - super(); - this.expressions = builder.expressions; - builder.nestedValidationContextBuilders.forEach((key, value) -> - nestedValidationContextsBuilders.put(key, value.build())); - - } - - public Map getJsonPathExpressions() { - return expressions; - } - - public Map getNestedValidationContextsBuilders() { - return nestedValidationContextsBuilders; - } - - public static class Builder> implements - ValidationContext.Builder, - WithExpressions, VariableExtractorAdapter, - MessageProcessorAdapter { - - private final Map expressions = new HashMap<>(); - - protected final Map> nestedValidationContextBuilders= new HashMap<>(); - - @Override - public B expressions(Map expressions) { - this.expressions.putAll(expressions); - return (B) this; - } - - @Override - public B expression(final String expression, - final Object value) { - this.expressions.put(expression, value); - return (B) this; - } - - @Override - public EntityValidationContext build() { - return new EntityValidationContext(this); - } - - @Override - public MessageProcessor asProcessor() { - return new DelegatingPathExpressionProcessor.Builder() - .expressions(expressions) - .build(); - } - - @Override - public VariableExtractor asExtractor() { - return new DelegatingPayloadVariableExtractor.Builder() - .expressions(expressions) - .build(); - } - - } - } - - public static class PetEntityValidationContext extends EntityValidationContext { - - public PetEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - public Builder id(String expression) { - return expression("$.id", expression); - } - - public Builder name(String expression) { - return expression("$.name", expression); - } - - public Builder category(String expression) { - return expression("$.category", expression); - } - - public Builder urls(String expression) { - return expression("$.urls", expression); - } - - - public Builder urls(int index, String expression) { - return expression("$.urls[%d]".formatted(index), expression); - } - - public Builder address(Consumer validator) { - AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); - validator.accept(addressEntityValidationContextBuilder); - nestedValidationContextBuilders.put("$.address", addressEntityValidationContextBuilder); - - return this; - } - - - public Builder owners(AggregateEntityValidationContext.Builder aggregateContext) { - nestedValidationContextBuilders.put("$.owners", aggregateContext); - return this; - } - - public static Builder pet() { - return new Builder(); - } - - @Override - public PetEntityValidationContext build() { - return new PetEntityValidationContext(this); - } - - } - } - - public static class AddressEntityValidationContext extends EntityValidationContext { - - public AddressEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - - public Builder street(String expression) { - return expression("$.street", expression); - } - - public Builder city(String expression) { - return expression("$.city", expression); - } - - public Builder zip(String expression) { - return expression("$.zip", expression); - } - - public static Builder address() { - return new Builder(); - } - - @Override - public AddressEntityValidationContext build() { - return new AddressEntityValidationContext(this); - } - - } - } - - public static class OwnerEntityValidationContext extends EntityValidationContext { - - public OwnerEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - public OwnerEntityValidationContext.Builder address(Consumer validator) { - AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); - validator.accept(addressEntityValidationContextBuilder); - nestedValidationContextBuilders.put("address", addressEntityValidationContextBuilder); - return this; - } - - public OwnerEntityValidationContext.Builder name(String expression) { - expression("$.name", expression); - return this; - } - - @Override - public OwnerEntityValidationContext build() { - return new OwnerEntityValidationContext(this); - } - } - } - - public static class AggregateEntityValidationContext> extends EntityValidationContext { - - private final Type type; - - private List> validator; - - public AggregateEntityValidationContext(Builder builder) { - super(builder); - - this.type = builder.type; - this.validator = builder.validator; - } - - public enum Type { - ONE_OF, ANY_OF, ALL_OF, NONE_OF - } - - public static class Builder> extends EntityValidationContext.Builder, Builder> { - - private final Type type; - - private final List> validator; - - public Builder(Type type, List> validator) { - this.type = type; - this.validator = validator; - } - - public static > AggregateEntityValidationContext.Builder anyOf(List> validator) { - return new Builder<>(Type.ANY_OF, validator); - } - - public static > AggregateEntityValidationContext.Builder allOf(List> validator) { - return new Builder<>(Type.ALL_OF, validator); - } - - public static > AggregateEntityValidationContext.Builder noneOf(List> validator) { - - return new Builder<>(Type.NONE_OF, validator); - } - - public static > AggregateEntityValidationContext.Builder oneOf(List> validator) { - return new Builder<>(Type.ONE_OF, validator); - } - - @Override - public AggregateEntityValidationContext build() { - return null; - } - } - - } -} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java deleted file mode 100644 index b810d81281..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/OpenApiPetStore_.java +++ /dev/null @@ -1,304 +0,0 @@ -package org.citrusframework.openapi.generator.sample; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Consumer; -import org.citrusframework.builder.WithExpressions; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.message.DelegatingPathExpressionProcessor; -import org.citrusframework.message.MessageProcessor; -import org.citrusframework.message.MessageProcessorAdapter; -import org.citrusframework.openapi.generator.sample.PetApi.FindPetByStatusActionBuilder; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.context.DefaultValidationContext; -import org.citrusframework.validation.context.ValidationContext; -import org.citrusframework.variable.VariableExtractor; -import org.citrusframework.variable.VariableExtractorAdapter; -import org.springframework.http.HttpStatus; - -public class OpenApiPetStore_ { - - public static OpenApiPetStore_ openApiPetStore(HttpClient httpClient) { - return new OpenApiPetStore_(); - } - - public GetPetIdRequestActionBuilder getPetById() { - return new GetPetIdRequestActionBuilder(); - } - - public FindPetByStatusActionBuilder findByStatus() { - return new FindPetByStatusActionBuilder(); - } - - public static class GetPetIdRequestActionBuilder extends HttpClientRequestActionBuilder { - - public GetPetIdRequestActionBuilder withPetId(String petId) { - return this; - } - - } - - public GetPetIdResponseActionBuilder receivePetById(HttpStatus status) { - return new GetPetIdResponseActionBuilder(); - } - - public GetPetIdResponseActionBuilder200 receivePetById200() { - return new GetPetIdResponseActionBuilder200(); - } - - public static class GetPetIdResponseActionBuilder extends HttpClientResponseActionBuilder { - - } - - // Per configured response - public static class GetPetIdResponseActionBuilder200 extends HttpClientResponseActionBuilder { - - public HttpMessageBuilderSupport withPet( - Consumer validator) { - PetEntityValidationContext.Builder builder = new PetEntityValidationContext.Builder(); - validator.accept(builder); - return message().validate(builder); - } - } - - public static class EntityValidationContext extends DefaultValidationContext { - - private Map expressions; - - - private Map nestedValidationContextsBuilders = new HashMap<>(); - - public EntityValidationContext(Builder builder) { - super(); - this.expressions = builder.expressions; - builder.nestedValidationContextBuilders.forEach((key, value) -> - nestedValidationContextsBuilders.put(key, value.build())); - - } - - public Map getJsonPathExpressions() { - return expressions; - } - - public Map getNestedValidationContextsBuilders() { - return nestedValidationContextsBuilders; - } - - public static class Builder> implements - ValidationContext.Builder, - WithExpressions, VariableExtractorAdapter, - MessageProcessorAdapter { - - private final Map expressions = new HashMap<>(); - - protected final Map> nestedValidationContextBuilders= new HashMap<>(); - - @Override - public B expressions(Map expressions) { - this.expressions.putAll(expressions); - return (B) this; - } - - @Override - public B expression(final String expression, - final Object value) { - this.expressions.put(expression, value); - return (B) this; - } - - @Override - public EntityValidationContext build() { - return new EntityValidationContext(this); - } - - @Override - public MessageProcessor asProcessor() { - return new DelegatingPathExpressionProcessor.Builder() - .expressions(expressions) - .build(); - } - - @Override - public VariableExtractor asExtractor() { - return new DelegatingPayloadVariableExtractor.Builder() - .expressions(expressions) - .build(); - } - - } - } - - public static class PetEntityValidationContext extends EntityValidationContext { - - public PetEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - public Builder id(String expression) { - return expression("$.id", expression); - } - - public Builder name(String expression) { - return expression("$.name", expression); - } - - public Builder category(String expression) { - return expression("$.category", expression); - } - - public Builder urls(String expression) { - return expression("$.urls", expression); - } - - - public Builder urls(int index, String expression) { - return expression("$.urls[%d]".formatted(index), expression); - } - - public Builder address(Consumer validator) { - AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); - validator.accept(addressEntityValidationContextBuilder); - nestedValidationContextBuilders.put("$.address", addressEntityValidationContextBuilder); - - return this; - } - - - public Builder owners(AggregateEntityValidationContext.Builder aggregateContext) { - nestedValidationContextBuilders.put("$.owners", aggregateContext); - return this; - } - - public static Builder pet() { - return new Builder(); - } - - @Override - public PetEntityValidationContext build() { - return new PetEntityValidationContext(this); - } - - } - } - - public static class AddressEntityValidationContext extends EntityValidationContext { - - public AddressEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - - public Builder street(String expression) { - return expression("$.street", expression); - } - - public Builder city(String expression) { - return expression("$.city", expression); - } - - public Builder zip(String expression) { - return expression("$.zip", expression); - } - - public static Builder address() { - return new Builder(); - } - - @Override - public AddressEntityValidationContext build() { - return new AddressEntityValidationContext(this); - } - - } - } - - public static class OwnerEntityValidationContext extends EntityValidationContext { - - public OwnerEntityValidationContext(Builder builder) { - super(builder); - } - - public static class Builder extends - EntityValidationContext.Builder { - - public Builder address(Consumer validator) { - AddressEntityValidationContext.Builder addressEntityValidationContextBuilder = new AddressEntityValidationContext.Builder(); - validator.accept(addressEntityValidationContextBuilder); - nestedValidationContextBuilders.put("address", addressEntityValidationContextBuilder); - return this; - } - - public Builder name(String expression) { - expression("$.name", expression); - return this; - } - - @Override - public OwnerEntityValidationContext build() { - return new OwnerEntityValidationContext(this); - } - } - } - - public static class AggregateEntityValidationContext> extends EntityValidationContext { - - private final Type type; - - private List> validator; - - public AggregateEntityValidationContext(Builder builder) { - super(builder); - - this.type = builder.type; - this.validator = builder.validator; - } - - public enum Type { - ONE_OF, ANY_OF, ALL_OF, NONE_OF - } - - public static class Builder> extends EntityValidationContext.Builder, Builder> { - - private final Type type; - - private final List> validator; - - public Builder(Type type, List> validator) { - this.type = type; - this.validator = validator; - } - - public static > Builder anyOf(List> validator) { - return new Builder<>(Type.ANY_OF, validator); - } - - public static > Builder allOf(List> validator) { - return new Builder<>(Type.ALL_OF, validator); - } - - public static > Builder noneOf(List> validator) { - - return new Builder<>(Type.NONE_OF, validator); - } - - public static > Builder oneOf(List> validator) { - return new Builder<>(Type.ONE_OF, validator); - } - - @Override - public AggregateEntityValidationContext build() { - return null; - } - } - - } -} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java deleted file mode 100644 index 325be20a88..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetApi.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi.generator.sample; - -import java.util.HashMap; -import java.util.Map; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.TestApiClientRequestActionBuilder; -import org.citrusframework.openapi.generator.rest.petstore.model.Pet; -import org.citrusframework.testapi.GeneratedApi; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetApi implements GeneratedApi { - - public static final PetApi INSTANCE = new PetApi(); - - public String getApiTitle() { - return "OpenAPI Petstore"; - } - - public String getApiVersion() { - return "1.0.0"; - } - - public String getApiPrefix() { - return "PetStore"; - } - - private OpenApiSpecification openApiSpecification = null; - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - infoExtensionMap.put("x-citrus-api-name", "petstore"); - infoExtensionMap.put("x-citrus-app", "PETS"); - return infoExtensionMap; - } - - public static PetApi openApiPetStore(HttpClient httpClient) { - - return new PetApi(); - } - - private static OpenApiSpecification petApi() { - // TODO implement me - return null; - } - - public AddPetActionBuilder addPet() { - return new AddPetActionBuilder(); - } - - public DeletePetActionBuilder deletePet() { - return new DeletePetActionBuilder(); - } - - public FindPetByStatusActionBuilder findPetsByStatus() { - return new FindPetByStatusActionBuilder(); - } - - public FindPetsByTagsActionBuilder findPetsByTags() { - return new FindPetsByTagsActionBuilder(); - } - - public GetPetByIdActionBuilder getPetById() { - return new GetPetByIdActionBuilder(); - } - - public class AddPetActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "POST"; - - private static final String ENDPOINT = "/pet"; - - private static final String OPERATION_NAME = "addPet"; - - public AddPetActionBuilder() { - super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - } - - public AddPetActionBuilder withStatus(String status) { - queryParam("status", status); - return this; - } - - public AddPetActionBuilder withPet(Pet pet) { - // TODO: fix this - getMessageBuilderSupport().body(pet.toString()); - return this; - } - - } - - public class DeletePetActionBuilder extends TestApiClientRequestActionBuilder { - - private static final String METHOD = "DELETE"; - - private static final String ENDPOINT = "/pet/{petId}"; - - private static final String OPERATION_NAME = "deletePet"; - - public DeletePetActionBuilder() { - super(openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - } - - public DeletePetActionBuilder withId(String id) { - pathParameter("id", id); - return this; - } - - public DeletePetActionBuilder withPet(Pet pet) { - // TODO: fix this pet.toString will not properly work - getMessageBuilderSupport().body(pet.toString()); - return this; - } - - } - - public static class FindPetByStatusActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "GET"; - - private static final String ENDPOINT = "/pet/findByStatus"; - - private static final String OPERATION_NAME = "findPetsByStatus"; - - public FindPetByStatusActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public FindPetByStatusActionBuilder withStatus(String status) { - queryParam("status", status); - return this; - } - - } - - public static class FindPetsByTagsActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "GET"; - - private static final String ENDPOINT = "/pet/findByTags"; - - private static final String OPERATION_NAME = "findPetsByTags"; - - public FindPetsByTagsActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public FindPetsByTagsActionBuilder withTags(String... tags) { - queryParam("tags", toQueryParam(tags)); - return this; - } - } - - public static class GetPetByIdActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "GET"; - - private static final String ENDPOINT = "/pet/{petId}"; - - private static final String OPERATION_NAME = "getPetById"; - - public GetPetByIdActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public GetPetByIdActionBuilder withId(String id) { - pathParameter("id", id); - return this; - } - - - - // TODO: find solution for authentication -// public GetPetByIdActionBuilder withBasicUsername(String basicUsername) { -// this.basicUsername = basicUsername; -// return this; -// } -// -// public GetPetByIdActionBuilder withBasicPassword(String basicPassword) { -// this.basicPassword = basicPassword; -// return this; -// } - } - - public static class UpdatePetActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "PUT"; - - private static final String ENDPOINT = "/pet"; - - private static final String OPERATION_NAME = "updatePet"; - - public UpdatePetActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public UpdatePetActionBuilder withId(String id) { - pathParameter("id", id); - return this; - } - - public UpdatePetActionBuilder withPet(Pet pet) { - // TODO: fix this pet.toString - getMessageBuilderSupport().body(pet.toString()); - return this; - } - } - - public static class UpdatePetWithFormDataActionBuilder extends - PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "POST"; - - private static final String ENDPOINT = "/pet/{petId}"; - - private static final String OPERATION_NAME = "updatePetWithForm"; - - public UpdatePetWithFormDataActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public UpdatePetWithFormDataActionBuilder withId(String id) { - pathParameter("id", id); - return this; - } - - // TODO: what is the magic about form data request? - } - - public static class UploadFileActionBuilder extends PetStoreAbstractSendAction.Builder { - - private static final String METHOD = "POST"; - - private static final String ENDPOINT = "/pet/{petId}/uploadImage"; - - private static final String OPERATION_NAME = "uploadImage"; - - public UploadFileActionBuilder() { - super(PetApi.petApi(), METHOD, ENDPOINT, OPERATION_NAME); - } - - public UploadFileActionBuilder withId(String id) { - pathParameter("id", id); - return this; - } - - public UploadFileActionBuilder withAdditionalMetadata(String additionalMetadata) { - - // TODO: what is the magic about form data request? - formData("additionalMetadata", additionalMetadata); - return this; - } - } - - - -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java deleted file mode 100644 index e8f1e5c473..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractReceiveActionBuilder.java +++ /dev/null @@ -1,250 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.sample; - -import static org.springframework.util.CollectionUtils.isEmpty; - -import jakarta.annotation.Nullable; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.actions.ReceiveMessageAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.message.Message; -import org.citrusframework.spi.Resources; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.json.JsonMessageValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public abstract class PetStoreAbstractReceiveActionBuilder extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); - - @Autowired - @Qualifier("petStoreEndpoint") - protected HttpClient httpClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected boolean schemaValidation; - protected String schema; - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - protected String responseAcceptType = "*/*"; - protected String responseType = "json"; - protected int responseStatus = 200; - protected String responseReasonPhrase = "OK"; - protected String responseVersion = "HTTP/1.1"; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value - protected Map cookies; - protected Map headers; - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - - @Override - public void doExecute(TestContext context) { - recieveResponse(context); - } - - /** - * This method receives the HTTP-Response. - * - * @deprecated use {@link PetStoreAbstractReceiveActionBuilder#receiveResponse(TestContext)} instead. - */ - public ReceiveMessageAction recieveResponse(TestContext context) { - - HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); - HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport - .statusCode(responseStatus) - .reasonPhrase(responseReasonPhrase) - .version(responseVersion) - .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - messageBuilderSupport.type(responseType); - httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); - var responseAction = httpClientResponseActionBuilder.build(); - - responseAction.execute(context); - - return responseAction; - } - - public @Nullable Message receiveResponse(TestContext context) { - var responseAction = recieveResponse(context); - - var messageStore = context.getMessageStore(); - return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); - } - - public void setSchemaValidation(boolean schemaValidation) { - this.schemaValidation = schemaValidation; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setResponseAcceptType(String responseAcceptType) { - this.responseAcceptType = responseAcceptType; - } - - public void setCookie(Map cookies) { - this.cookies = cookies; - } - - public void setHeader(Map headers) { - this.headers = headers; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResponseType(String responseType) { - this.responseType = responseType; - } - - public void setResponseStatus(int responseStatus) { - this.responseStatus = responseStatus; - } - - public void setResponseReasonPhrase(String responseReasonPhrase) { - this.responseReasonPhrase = responseReasonPhrase; - } - - public void setResponseVersion(String responseVersion) { - this.responseVersion = responseVersion; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, - TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - - httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, - httpClientRequestActionBuilder); - - httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); - - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); - } - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeByBeans( - GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, httpClientRequestActionBuilder); - } - } - return httpClientRequestActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java deleted file mode 100644 index a02a8d4639..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/sample/PetStoreAbstractSendActionBuilder.java +++ /dev/null @@ -1,234 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.sample; - -import static org.springframework.util.CollectionUtils.isEmpty; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.citrusframework.actions.SendMessageAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-20T08:47:39.378047600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public abstract class PetStoreAbstractSendAction extends SendMessageAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); - - @Autowired - @Qualifier("petStoreEndpoint") - protected HttpClient httpClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected boolean schemaValidation; - protected String schema; - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - protected String responseAcceptType = "*/*"; - protected String responseType = "json"; - protected int responseStatus = 200; - protected String responseReasonPhrase = "OK"; - protected String responseVersion = "HTTP/1.1"; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value - protected Map cookies; - protected Map headers; - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - } - - - public abstract void sendRequest(TestContext context); - - public void setSchemaValidation(boolean schemaValidation) { - this.schemaValidation = schemaValidation; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setResponseAcceptType(String responseAcceptType) { - this.responseAcceptType = responseAcceptType; - } - - public void setCookie(Map cookies) { - this.cookies = cookies; - } - - public void setHeader(Map headers) { - this.headers = headers; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, - TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - - httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, - httpClientRequestActionBuilder); - - httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); - - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); - } - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeByBeans( - GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, httpClientRequestActionBuilder); - } - } - return httpClientRequestActionBuilder; - } - - public static class Builder extends OpenApiClientRequestActionBuilder { - - // TODO: do we really need this? - protected OpenApiSpecification openApiSpec; - - private final String path; - - private final Map pathParameters = new HashMap<>(); - - private final MultiValueMap formData = new LinkedMultiValueMap<>(); - - // TODO: can we just pass in the operation? - public Builder(OpenApiSpecification openApiSpec, String method, String path, String operationName) { - super(openApiSpec, "%s_%s".formatted(method, path)); - name(String.format("%s:%s", "PetStore".toLowerCase(), operationName)); - getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); - getMessageBuilderSupport().header("citrus_open_api_method", method); - getMessageBuilderSupport().header("citrus_open_api_path", path); - - this.openApiSpec = openApiSpec; - this.path = path; - } - - protected void pathParameter(String name, String value) { - pathParameters.put(name, value); - } - - protected void formData(String name, String value) { - formData.add(name, value); - } - - protected String qualifiedPath(String path) { - - String qualifiedPath = path; - for (Entry entry : pathParameters.entrySet()) { - qualifiedPath = qualifiedPath.replace("{%s}".formatted(entry.getKey()), entry.getValue()); - } - return qualifiedPath; - } - - protected String toQueryParam(String...arrayElements) { - return String.join(",", arrayElements); - } - - @Override - public SendMessageAction doBuild() { - // TODO: register callback to modify builder - path(qualifiedPath(path)); - if (!formData.isEmpty()) { - // TODO: do we have to explicitly set the content type or is this done by citrus - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE); - getMessageBuilderSupport().body(formData); - } - return super.doBuild(); - } - - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java new file mode 100644 index 0000000000..6869b9ecea --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java @@ -0,0 +1,76 @@ +package org.citrusframework.openapi.generator.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.apache.commons.fileupload.MultipartStream; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.message.HttpMessage; + +/** + * Provides utility method to convert a multipart http message to a map for simplified assertion. + */ +public class MultipartConverter { + + private static final Pattern NAME_PATTERN = Pattern.compile("name=\"([^\"]+)\""); + + private static final Pattern CONTENT_PATTERN = Pattern.compile("Content-Type:\\s*([^\\s;]+)"); + + public static Map multipartMessageToMap(HttpMessage message) { + String contentType = message.getContentType(); + String boundary = contentType.substring(contentType.indexOf("=") + 1); + + Map partMap = new HashMap<>(); + ByteArrayInputStream inputStream = null; + try { + inputStream = new ByteArrayInputStream(message.getPayload(String.class).getBytes()); + MultipartStream multipartStream = new MultipartStream(inputStream, boundary.getBytes(), + 4096, null); + + boolean nextPart = multipartStream.skipPreamble(); + while (nextPart) { + String headers = multipartStream.readHeaders(); + String partName = getHeaderGroup(headers, NAME_PATTERN); + String partContentType = getHeaderGroup(headers, CONTENT_PATTERN); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + multipartStream.readBodyData(outputStream); + String rawBodyContent = outputStream.toString(); + + partMap.put(partName, convertContent(rawBodyContent, partContentType)); + nextPart = multipartStream.readBoundary(); + } + + return partMap; + } catch (IOException e) { + throw new CitrusRuntimeException("Unable to parse multipart data"); + } + + } + + private static String getHeaderGroup(String headers, Pattern groupPattern) { + + Matcher m = groupPattern.matcher(headers); + + if (m.find()) { + return m.group(1); + } else { + throw new CitrusRuntimeException( + "unable to determine header group name: " + groupPattern); + } + } + + private static Object convertContent(String rawContent, String contentType) { + if (contentType != null) { + if (contentType.contains("application/octet-stream")) { + return rawContent.getBytes(StandardCharsets.ISO_8859_1); + } + } + return rawContent; + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java deleted file mode 100644 index 1b0b8824a7..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/TestApiActionBuilderCustomizer.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.citrusframework.openapi.generator.util; - -import org.citrusframework.TestAction; -import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder; -import org.citrusframework.context.TestContext; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; - -public class TestApiActionBuilderCustomizer implements ApiActionBuilderCustomizerService { - - @Override - public > T build(GeneratedApi generatedApi, TestAction action, - TestContext context, T builder) { - - generatedApi.getApiInfoExtensions().forEach((key, value) -> { - builder.getMessageBuilderSupport().header(key, value); - }); - - return builder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService deleted file mode 100644 index ba96f521f6..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/services/org.citrusframework.testapi.ApiActionBuilderCustomizerService +++ /dev/null @@ -1 +0,0 @@ -org.citrusframework.openapi.generator.util.TestApiActionBuilderCustomizer \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers index 1f0c4bdb95..f1955af26b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.handlers @@ -1,3 +1,3 @@ -http\://www.citrusframework.org/citrus-test-schema/multiparttest-api=org.citrusframework.openapi.generator.rest.multiparttest.citrus.extension.MultipartTestNamespaceHandler -http\://www.citrusframework.org/citrus-test-schema/openapifromwsdl-api=org.citrusframework.openapi.generator.soap.bookservice.citrus.extension.OpenApiFromWsdlNamespaceHandler -http\://www.citrusframework.org/citrus-test-schema/petstore-api=org.citrusframework.openapi.generator.rest.petstore.citrus.extension.PetStoreNamespaceHandler +http\://www.citrusframework.org/citrus-test-schema/bookservice-api=org.citrusframework.openapi.generator.soap.bookservice.spring.BookServiceNamespaceHandler +http\://www.citrusframework.org/citrus-test-schema/petstore-api=org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreNamespaceHandler +http\://www.citrusframework.org/citrus-test-schema/extpetstore-api=org.citrusframework.openapi.generator.rest.extpetstore.spring.ExtPetStoreNamespaceHandler \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas index 0050010472..5b3c2539b9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/META-INF/spring.schemas @@ -1,3 +1,4 @@ -http\://www.citrusframework.org/citrus-test-schema/multiparttest-api/multiparttest-api.xsd=schema/xsd/multiparttest-api.xsd -http\://www.citrusframework.org/citrus-test-schema/openapifromwsdl-api/openapifromwsdl-api.xsd=schema/xsd/openapifromwsdl-api.xsd http\://www.citrusframework.org/citrus-test-schema/petstore-api/petstore-api.xsd=schema/xsd/petstore-api.xsd +http\://www.citrusframework.org/citrus-test-schema/extpetstore-api/extpetstore-api.xsd=schema/xsd/extpetstore-api.xsd +http\://www.citrusframework.org/citrus-test-schema/bookservice-api/bookservice-api.xsd=schema/xsd/bookservice-api.xsd +http\://www.citrusframework.org/bookstore/datatypes/BookDatatypes.xsd=schema/xsd/BookDatatypes.xsd diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/BookService-generated.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/BookService-generated.yaml new file mode 100644 index 0000000000..f70656312d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/BookService-generated.yaml @@ -0,0 +1,43 @@ +--- +info: + contact: + name: "org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer" + description: "This api has been generated from the following wsdl 'BookService.wsdl'.\ + \ It's purpose is solely to serve as input for SOAP API generation. Note that\ + \ only operations are extracted from the WSDL. No schema information whatsoever\ + \ is generated!" + title: "Generated api from wsdl" + version: "1.0.0" +openapi: "3.0.1" +paths: + /GetBook: + post: + description: "This operation retrieves details for a specific book identified\ + \ by its ID." + operationId: "GetBook" + responses: + default: + description: "Generic Response" + summary: "http://www.citrusframework.com/BookService/GetBook" + tags: + - "BookServiceSOAP" + /AddBook: + post: + description: "" + operationId: "AddBook" + responses: + default: + description: "Generic Response" + summary: "http://www.citrusframework.com/BookService/AddBook" + tags: + - "BookServiceSOAP" + /GetAllBooks: + post: + description: "" + operationId: "GetAllBooks" + responses: + default: + description: "Generic Response" + summary: "http://www.citrusframework.com/BookService/GetAllBooks" + tags: + - "BookServiceSOAP" \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml deleted file mode 100644 index cfac634788..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/multiparttest-rest-resource.yaml +++ /dev/null @@ -1,249 +0,0 @@ -openapi: 3.0.3 -info: - title: multiparttest API - version: 2.0.0 - description: | - The service to test mutlipart - x-citrus-app: MPT - x-citrus-api-name: multiparttest-rest-resource - contact: - name: Citrusframework Authors - email: citrus-dev@googlegroups.com - url: https://citrusframework.org -tags: - - name: multiparttest-controller -paths: - /api/v2/multitest-file/{bucket}/{filename}/random: - post: - tags: - - multiparttest-controller - operationId: postRandom - summary: Uploads random file. - parameters: - - name: bucket - description: The name of an existing s3 bucket. - in: path - required: true - schema: - type: string - - name: filename - description: The name under which to store the random file. - in: path - required: true - schema: - type: string - responses: - 200: - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/PutObjectResult' - 500: - description: Internal Server Error - /api/v2/multitest-file/{bucket}/{filename}: - post: - tags: - - multiparttest-controller - operationId: postFile - summary: Uploads file. - parameters: - - name: bucket - description: The name of an existing s3 bucket. - in: path - required: true - schema: - type: string - - name: filename - description: The name of the file which should be uploaded. It may override any existing file with the same name. - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - properties: - multipartFile: - type: string - format: binary - responses: - 200: - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/PutObjectResult' - 500: - description: Internal Server Error - delete: - tags: - - multiparttest-controller - operationId: deleteObject - summary: Delete file. - parameters: - - name: bucket - in: path - required: true - schema: - type: string - description: The name of an existing s3 bucket. - - name: filename - in: path - required: true - schema: - type: string - description: The name of the file which should be deleted. - responses: - 200: - description: OK - content: - application/json: - schema: - type: boolean - 500: - description: Internal Server Error - /api/v2/multitest-reportgeneration: - post: - tags: - - multiparttest-controller - operationId: generateReport - summary: summary - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - required: ['template'] - properties: - template: - description: | - Content of the template. - type: string - additionalData: - $ref: '#/components/schemas/AdditionalData' - schema: - description: | - An optional JSON schema to validate the created report against. - type: string - responses: - 200: - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/PutObjectResult' - 500: - description: Internal Server Error - /api/v2/multitest-multipledatatypes: - post: - tags: - - multiparttest-controller - operationId: multipleDatatypes - summary: summary - requestBody: - required: true - content: - multipart/form-data: - schema: - type: object - properties: - stringData: - type: string - booleanData: - type: boolean - integerData: - type: integer - - responses: - 200: - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/PutObjectResult' - 500: - description: Internal Server Error - /api/v2/multitest-file/{bucket}/{filename}/exists: - get: - tags: - - multiparttest-controller - operationId: fileExists - summary: Checks if file exist. - parameters: - - name: bucket - description: The name of an existing s3 bucket. - in: path - required: true - schema: - type: string - - name: filename - description: The name of the file on which the status should be checked. - in: path - required: true - schema: - type: string - responses: - 200: - description: OK - content: - application/json: - schema: - type: boolean - 500: - description: Internal Server Error -components: - schemas: - Metadata: - type: object - properties: - userMetadata: - type: object - additionalProperties: - type: string - rawMetadata: - type: object - additionalProperties: - type: string - httpExpiresDate: - type: string - format: date-time - expirationTime: - type: string - format: date-time - expirationTimeRuleId: - type: string - ongoingRestore: - type: boolean - restoreExpirationTime: - type: string - format: date-time - bucketKeyEnabled: - type: boolean - PutObjectResult: - type: object - properties: - versionId: - type: string - eTag: - type: string - expirationTime: - type: string - format: date-time - expirationTimeRuleId: - type: string - contentMd5: - type: string - metadata: - $ref: '#/components/schemas/Metadata' - isRequesterCharged: - type: boolean - AdditionalData: - description: | - Additional data provided to the report. For each dataset requested, provide a json - object with the name of the dataset. - type: string diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml new file mode 100644 index 0000000000..865466c524 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml @@ -0,0 +1,1230 @@ +openapi: 3.0.2 +info: + title: Extended Petstore API + description: | + This is an extended version of the Petstore API which includes additional operations, + such as updating a pet using form data and managing vaccination records. + version: 1.0.0 +servers: + - url: /api/v3/ext + +paths: + /pet/simple/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithSimpleStyleArray + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: simple + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/simple/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithSimpleStyleObject + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: simple + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/simple/exploded/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithSimpleStyleArrayExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: simple + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/simple/exploded/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithSimpleStyleObjectExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: simple + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/label/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithLabelStyleArray + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: label + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/label/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithLabelStyleObject + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: label + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/label/exploded/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithLabelStyleArrayExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: label + explode: true + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/label/exploded/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithLabelStyleObjectExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: label + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/matrix/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithMatrixStyleArray + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: matrix + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/matrix/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithMatrixStyleObject + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: matrix + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/matrix/exploded/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithMatrixStyleArrayExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: matrix + explode: true + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/matrix/exploded/object/{petId}: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in path parameter + operationId: getPetWithMatrixStyleObjectExploded + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: path + description: IDs of pet to return + required: true + style: matrix + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/header/simple: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithSimpleStyleHeader + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: header + description: IDs of pet to return + required: true + style: simple + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/header/simple/exploded: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithSimpleStyleExplodedHeader + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: header + description: IDs of pet to return + required: true + style: simple + explode: true + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/header/simple/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithSimpleStyleObjectHeader + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: header + description: IDs of pet to return + required: true + style: simple + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/header/simple/exploded/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithSimpleStyleExplodedObjectHeader + description: "Returns multiple pets by ID using multiple ids in header parameter." + parameters: + - name: petId + in: header + description: IDs of pet to return + required: true + style: simple + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/query/form: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithFormStyleQuery + description: "Returns multiple pets by ID using multiple ids in query parameter." + parameters: + - name: petId + in: query + description: IDs of pet to return + required: true + style: form + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/query/form/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithFormStyleObjectQuery + description: "Returns multiple pets by ID using multiple ids in query parameter." + parameters: + - name: petId + in: query + description: IDs of pet to return + required: true + style: form + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/query/form/exploded: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithFormStyleExplodedQuery + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: query + description: IDs of pet to return + required: true + style: form + explode: true + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/query/form/exploded/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithFormStyleExplodedObjectQuery + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: query + description: IDs of pet to return + required: true + style: form + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/query/deep/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in header parameter + operationId: getPetWithDeepObjectTypeQuery + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: query + description: IDs of pet to return + required: true + style: deepObject + explode: true + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/cookie/form: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in cookie parameter + operationId: getPetWithFormStyleCookie + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: cookie + description: IDs of pet to return + required: true + style: form + explode: false + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/cookie/form/object: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in cookie parameter + operationId: getPetWithFormObjectStyleCookie + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: petId + in: cookie + description: IDs of pet to return + required: true + style: form + explode: false + schema: + $ref: '#/components/schemas/PetIdentifier' + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/cookie/form/exploded: + get: + tags: + - extPet + summary: Get a pet by id supporting multiple ids in cookie parameter + operationId: getPetWithFormExplodedStyleCookie + description: "Returns multiple pets by ID using multiple ids in cookie parameter." + parameters: + - name: petId + in: cookie + description: IDs of pet to return + required: true + style: form + explode: true + schema: + type: array + items: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/{petId}: + get: + tags: + - extPet + summary: Get a pet using a session cookie + operationId: getPetWithCookie + description: "Returns a single pet by ID, using a session ID stored in a cookie." + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: session_id + in: cookie + required: true + schema: + type: string + description: The session ID cookie + - name: opt_trx_id + in: cookie + schema: + type: string + description: The optional transaction ID cookie + responses: + '200': + description: Successful operation + content: + application/xml: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + application/json: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + put: + tags: + - extPet + summary: Updates a pet in the store with query data. + description: "Update the name, status, tags and nicknames of an existing pet using query data." + operationId: updatePetWithArrayQueryData + parameters: + - name: petId + in: path + required: true + description: ID of the pet that needs to be updated + schema: + type: integer + format: int64 + - name: name + in: query + required: true + description: Updated name of the pet + schema: + type: string + - name: status + in: query + required: true + description: Updated status of the pet + schema: + type: string + - name: tags + in: query + required: true + description: Updated tags of the pet + schema: + type: array + items: + type: string + - name: nicknames + in: query + required: true + description: Updated nicknames of the pet + schema: + type: array + items: + type: string + - name: sampleStringHeader + in: header + required: true + description: A sample string header + schema: + type: string + - name: sampleIntHeader + in: header + description: A sample int header + schema: + type: integer + responses: + '200': + description: Pet successfully updated + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + /pet/form/{petId}: + put: + tags: + - extPet + summary: Updates a pet in the store with form data + description: "Update the name or status of an existing pet using url encoded form data." + operationId: updatePetWithFormUrlEncoded + parameters: + - name: petId + in: path + required: true + description: ID of the pet that needs to be updated + schema: + type: integer + format: int64 + requestBody: + required: true + content: + application/x-www-form-urlencoded: + schema: + type: object + required: [ "name", "status", "tags", "age" ] + properties: + name: + description: Updated name of the pet + type: string + status: + description: Updated status of the pet + type: string + age: + description: The age of the pet in years + type: integer + owners: + description: The number of pre owners + type: integer + tags: + type: array + items: + type: string + nicknames: + type: array + items: + type: string + responses: + '200': + description: Pet successfully updated + '400': + description: Invalid ID supplied + '404': + description: Pet not found + '405': + description: Validation exception + /secure-basic/pet/{petId}: + get: + tags: + - extPet + summary: Get a pet via basic authentication + description: "Returns a single pet by ID, requiring basic authentication." + operationId: getPetByIdWithBasicAuthentication + security: + - basicAuth: [ ] + + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: allDetails + in: query + description: Requests all details. + required: true + schema: + type: boolean + - name: details + in: query + description: A list with detail specifiers. + schema: + type: array + items: + type: string + - name: requesterInformation + in: query + description: A list of specific requester information. + schema: + type: array + items: + type: string + responses: + '200': + description: Successful operation + content: + application/xml: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + application/json: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /secure-bearer/pet/{petId}: + get: + tags: + - extPet + summary: Get a pet via basic authentication + description: "Returns a single pet by ID, requiring basic authentication." + operationId: getPetByIdWithBearerAuthentication + security: + - bearerAuth: [ ] + + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: allDetails + in: query + description: Requests all details. + required: true + schema: + type: boolean + - name: details + in: query + description: A list with detail specifiers. + schema: + type: array + items: + type: string + - name: requesterInformation + in: query + description: A list of specific requester information. + schema: + type: array + items: + type: string + responses: + '200': + description: Successful operation + content: + application/xml: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + application/json: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /secure-api-key/pet/{petId}: + get: + tags: + - extPet + summary: Get a pet via basic authentication + description: "Returns a single pet by ID, requiring basic authentication." + operationId: getPetByIdWithApiKeyAuthentication + security: + - api_key_header: [ ] + - api_key_query: [ ] + - api_key_cookie: [ ] + + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + - name: allDetails + in: query + description: Requests all details. + required: true + schema: + type: boolean + - name: details + in: query + description: A list with detail specifiers. + required: false + schema: + type: array + items: + type: string + - name: requesterInformation + in: query + description: A list of specific requester information. + schema: + type: array + items: + type: string + responses: + '200': + description: Successful operation + content: + application/xml: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + application/json: + schema: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found + /pet/vaccination/{bucket}/{filename}: + post: + tags: + - extPet + operationId: postVaccinationDocument + summary: Upload a pet vaccination document + description: "Uploads a vaccination document for a pet to a specified S3 bucket." + parameters: + - name: bucket + description: The name of an existing S3 bucket. + in: path + required: true + schema: + type: string + - name: filename + description: The name under which to store the vaccination document. + in: path + required: true + schema: + type: string + responses: + '201': + description: Document successfully uploaded + content: + application/json: + schema: + $ref: '#/components/schemas/VaccinationDocumentResult' + '400': + description: Bad Request - Invalid parameters supplied + '500': + description: Internal Server Error + /pet/vaccination/status-report: + post: + tags: + - extPet + operationId: generateVaccinationReport + summary: Generate a vaccination status report + description: "Generates a vaccination status report in PDF format based on the provided template and data." + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + required: [ 'template', "reqIntVal" ] + properties: + template: + description: | + Vaccination report template file. + type: string + format: binary + reqIntVal: + description: | + A required integer value. + type: integer + optIntVal: + description: | + An optional integer value. + type: integer + optBoolVal: + description: | + An optional boolean value. + type: boolean + optNumberVal: + description: | + An optional number value. + type: number + optStringVal: + description: | + An optional string value. + type: string + optDateVal: + description: | + An optional date value. + type: string + format: date + additionalData: + $ref: '#/components/schemas/HistoricalData' + schema: + description: | + An optional JSON schema file to validate the created report against. + type: string + format: binary + responses: + '200': + description: A vaccination report in PDF + content: + application/pdf: + schema: + type: string + format: binary + '422': + description: Unprocessable Entity - Validation error in the provided data + '500': + description: Internal Server Error + /pet/vaccination/form: + post: + tags: + - extPet + operationId: postVaccinationFormData + summary: Submit vaccination form data + description: "Submits vaccination details for a pet." + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + vaccine: + type: string + description: The name of the vaccine administered. + isFirstVaccination: + type: boolean + description: Indicates if this is the first vaccination or a repetition. + doseNumber: + type: integer + description: The dose number of the vaccine (e.g., 1 for first dose, 2 for second dose). + vaccinationDate: + type: string + format: date + description: The date when the vaccination was administered. + responses: + '201': + description: Form data successfully submitted + content: + application/json: + schema: + $ref: '#/components/schemas/VaccinationDocumentResult' + '400': + description: Bad Request - Invalid form data + '500': + description: Internal Server Error + +components: + securitySchemes: + basicAuth: + type: http + scheme: basic + bearerAuth: + type: http + scheme: bearer # Specifies Bearer token authentication + bearerFormat: JWT # Optional, specifies the format of the bearer token (e.g., JWT) + api_key_header: + type: apiKey + description: Header api key description + name: api_key_header + in: header + api_key_cookie: + type: apiKey + description: Cookie api key description + name: api_key_cookie + in: cookie + api_key_query: + type: apiKey + description: Query api key description + name: api_key_query + in: query + + schemas: + HistoricalData: + description: | + Additional historical data for a vaccination report, not contained in internal storage. + type: object + properties: + lastVaccinationDate: + type: string + format: date + description: The date of the last vaccination. + vaccinationCount: + type: integer + description: The number of vaccinations the pet has received. + VaccinationDocumentResult: + type: object + properties: + documentId: + type: string + description: The unique ID of the uploaded vaccination document. + example: "abc123" + PetIdentifier: + type: object + properties: + name: + type: string + alias: + type: string diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml new file mode 100644 index 0000000000..6e38ce59fc --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml @@ -0,0 +1,803 @@ +openapi: 3.0.2 +info: + title: Swagger Petstore - OpenAPI 3.0 + description: |- + This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about + Swagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach! + You can now help us improve the API whether it's by making changes to the definition itself or to the code. + That way, with time, we can improve the API in general, and expose some of the new features in OAS3. + + Some useful links: + - [The Pet Store repository](https://github.com/swagger-api/swagger-petstore) + - [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml) + termsOfService: http://swagger.io/terms/ + contact: + email: apiteam@swagger.io + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.0.19 +externalDocs: + description: Find out more about Swagger + url: http://swagger.io +servers: + - url: /api/v3 +tags: + - name: pet + description: Everything about your Pets + externalDocs: + description: Find out more + url: http://swagger.io + - name: store + description: Access to Petstore orders + externalDocs: + description: Find out more about our store + url: http://swagger.io + - name: user + description: Operations about user +paths: + /pet: + put: + tags: + - pet + summary: Update an existing pet + description: Update an existing pet by Id + operationId: updatePet + requestBody: + description: Update an existent pet in the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + "200": + description: Successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + "400": + description: Invalid ID supplied + "404": + description: Pet not found + "405": + description: Validation exception + security: + - petstore_auth: + - write:pets + - read:pets + post: + tags: + - pet + summary: Add a new pet to the store + description: Add a new pet to the store + operationId: addPet + requestBody: + description: Create a new pet in the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Pet' + required: true + responses: + "200": + description: Successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + "405": + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + /pet/findByStatus: + get: + tags: + - pet + summary: Finds Pets by status + description: Multiple status values can be provided with comma separated strings + operationId: findPetsByStatus + parameters: + - name: status + in: query + description: Status values that need to be considered for filter + required: false + explode: true + schema: + type: string + default: available + enum: + - available + - pending + - sold + responses: + "200": + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + "400": + description: Invalid status value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/findByTags: + get: + tags: + - pet + summary: Finds Pets by tags + description: "Multiple tags can be provided with comma separated strings. Use\ + \ tag1, tag2, tag3 for testing." + operationId: findPetsByTags + parameters: + - name: tags + in: query + description: Tags to filter by + required: false + explode: true + schema: + type: array + items: + type: string + responses: + "200": + description: successful operation + content: + application/xml: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pet' + "400": + description: Invalid tag value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/{petId}: + get: + tags: + - pet + summary: Find pet by ID + description: Returns a single pet + operationId: getPetById + parameters: + - name: petId + in: path + description: ID of pet to return + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Pet' + application/json: + schema: + $ref: '#/components/schemas/Pet' + "400": + description: Invalid ID supplied + "404": + description: Pet not found + security: + - api_key: [] + - petstore_auth: + - write:pets + - read:pets + post: + tags: + - pet + summary: Updates a pet in the store with form data + description: "" + operationId: updatePetWithForm + parameters: + - name: petId + in: path + description: ID of pet that needs to be updated + required: true + schema: + type: integer + format: int64 + - name: name + in: query + description: Name of pet that needs to be updated + schema: + type: string + - name: status + in: query + description: Status of pet that needs to be updated + schema: + type: string + responses: + "405": + description: Invalid input + security: + - petstore_auth: + - write:pets + - read:pets + delete: + tags: + - pet + summary: Deletes a pet + description: "" + operationId: deletePet + parameters: + - name: api_key + in: header + description: "" + required: false + schema: + type: string + - name: petId + in: path + description: Pet id to delete + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Invalid pet value + security: + - petstore_auth: + - write:pets + - read:pets + /pet/{petId}/uploadImage: + post: + tags: + - pet + summary: uploads an image + description: "" + operationId: uploadFile + parameters: + - name: petId + in: path + description: ID of pet to update + required: true + schema: + type: integer + format: int64 + - name: additionalMetadata + in: query + description: Additional Metadata + required: false + schema: + type: string + requestBody: + content: + application/octet-stream: + schema: + type: string + format: binary + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + security: + - petstore_auth: + - write:pets + - read:pets + /store/inventory: + get: + tags: + - store + summary: Returns pet inventories by status + description: Returns a map of status codes to quantities + operationId: getInventory + responses: + "200": + description: successful operation + content: + application/json: + schema: + type: object + additionalProperties: + type: integer + format: int32 + security: + - api_key: [] + /store/order: + post: + tags: + - store + summary: Place an order for a pet + description: Place a new order in the store + operationId: placeOrder + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Order' + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Order' + "405": + description: Invalid input + /store/order/{orderId}: + get: + tags: + - store + summary: Find purchase order by ID + description: For valid response try integer IDs with value <= 5 or > 10. Other + values will generate exceptions. + operationId: getOrderById + parameters: + - name: orderId + in: path + description: ID of order that needs to be fetched + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/Order' + application/json: + schema: + $ref: '#/components/schemas/Order' + "400": + description: Invalid ID supplied + "404": + description: Order not found + delete: + tags: + - store + summary: Delete purchase order by ID + description: For valid response try integer IDs with value < 1000. Anything + above 1000 or nonintegers will generate API errors + operationId: deleteOrder + parameters: + - name: orderId + in: path + description: ID of the order that needs to be deleted + required: true + schema: + type: integer + format: int64 + responses: + "400": + description: Invalid ID supplied + "404": + description: Order not found + /user: + post: + tags: + - user + summary: Create user + description: This can only be done by the logged in user. + operationId: createUser + requestBody: + description: Created user object + content: + application/json: + schema: + $ref: '#/components/schemas/User' + application/xml: + schema: + $ref: '#/components/schemas/User' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/User' + responses: + default: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/User' + application/xml: + schema: + $ref: '#/components/schemas/User' + /user/createWithList: + post: + tags: + - user + summary: Creates list of users with given input array + description: Creates list of users with given input array + operationId: createUsersWithListInput + requestBody: + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + responses: + "200": + description: Successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + default: + description: successful operation + /user/login: + get: + tags: + - user + summary: Logs user into the system + description: "" + operationId: loginUser + parameters: + - name: username + in: query + description: The user name for login + required: false + schema: + type: string + - name: password + in: query + description: The password for login in clear text + required: false + schema: + type: string + responses: + "200": + description: successful operation + headers: + X-Rate-Limit: + description: calls per hour allowed by the user + schema: + type: integer + format: int32 + X-Expires-After: + description: date in UTC when token expires + schema: + type: string + format: date-time + content: + application/xml: + schema: + type: string + application/json: + schema: + type: string + "400": + description: Invalid username/password supplied + /user/logout: + get: + tags: + - user + summary: Logs out current logged in user session + description: "" + operationId: logoutUser + parameters: [] + responses: + default: + description: successful operation + /user/{username}: + get: + tags: + - user + summary: Get user by user name + description: "" + operationId: getUserByName + parameters: + - name: username + in: path + description: 'The name that needs to be fetched. Use user1 for testing. ' + required: true + schema: + type: string + responses: + "200": + description: successful operation + content: + application/xml: + schema: + $ref: '#/components/schemas/User' + application/json: + schema: + $ref: '#/components/schemas/User' + "400": + description: Invalid username supplied + "404": + description: User not found + put: + tags: + - user + summary: Update user + description: This can only be done by the logged in user. + operationId: updateUser + parameters: + - name: username + in: path + description: name that needs to be updated + required: true + schema: + type: string + requestBody: + description: Update an existent user in the store + content: + application/json: + schema: + $ref: '#/components/schemas/User' + application/xml: + schema: + $ref: '#/components/schemas/User' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/User' + responses: + default: + description: successful operation + delete: + tags: + - user + summary: Delete user + description: This can only be done by the logged in user. + operationId: deleteUser + parameters: + - name: username + in: path + description: The name that needs to be deleted + required: true + schema: + type: string + responses: + "400": + description: Invalid username supplied + "404": + description: User not found +components: + schemas: + Order: + type: object + properties: + id: + type: integer + format: int64 + example: 10 + petId: + type: integer + format: int64 + example: 198772 + quantity: + type: integer + format: int32 + example: 7 + shipDate: + type: string + format: date-time + status: + type: string + description: Order Status + example: approved + enum: + - placed + - approved + - delivered + complete: + type: boolean + xml: + name: order + Customer: + type: object + properties: + id: + type: integer + format: int64 + example: 100000 + username: + type: string + example: fehguy + address: + type: array + xml: + name: addresses + wrapped: true + items: + $ref: '#/components/schemas/Address' + xml: + name: customer + Address: + type: object + properties: + street: + type: string + example: 437 Lytton + city: + type: string + example: Palo Alto + state: + type: string + example: CA + zip: + type: string + example: "94301" + xml: + name: address + Category: + type: object + properties: + id: + type: integer + format: int64 + example: 1 + name: + type: string + example: Dogs + xml: + name: category + User: + type: object + properties: + id: + type: integer + format: int64 + example: 10 + username: + type: string + example: theUser + firstName: + type: string + example: John + lastName: + type: string + example: James + email: + type: string + example: john@email.com + password: + type: string + example: "12345" + phone: + type: string + example: "12345" + userStatus: + type: integer + description: User Status + format: int32 + example: 1 + xml: + name: user + Tag: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + xml: + name: tag + Pet: + required: + - name + - photoUrls + type: object + properties: + id: + type: integer + format: int64 + example: 10 + name: + type: string + example: doggie + category: + $ref: '#/components/schemas/Category' + photoUrls: + type: array + xml: + wrapped: true + items: + type: string + xml: + name: photoUrl + tags: + type: array + xml: + wrapped: true + items: + $ref: '#/components/schemas/Tag' + status: + type: string + description: pet status in the store + enum: + - available + - pending + - sold + xml: + name: pet + ApiResponse: + type: object + properties: + code: + type: integer + format: int32 + type: + type: string + message: + type: string + xml: + name: '##default' + requestBodies: + Pet: + description: Pet object that needs to be added to the store + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + application/xml: + schema: + $ref: '#/components/schemas/Pet' + UserArray: + description: List of user object + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + securitySchemes: + petstore_auth: + type: oauth2 + flows: + implicit: + authorizationUrl: https://petstore3.swagger.io/oauth/authorize + scopes: + write:pets: modify pets in your account + read:pets: read your pets + api_key: + type: apiKey + name: api_key + in: header diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml deleted file mode 100644 index 79249f26ed..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore.yaml +++ /dev/null @@ -1,700 +0,0 @@ -swagger: '2.0' -info: - description: 'This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.' - version: 1.0.0 - x-citrus-app: PETS - x-citrus-api-name: petstore - title: OpenAPI Petstore - license: - name: Apache-2.0 - url: 'https://www.apache.org/licenses/LICENSE-2.0.html' -host: petstore.swagger.io -basePath: /v2 -tags: - - name: pet - description: Everything about your Pets - - name: store - description: Access to Petstore orders - - name: user - description: Operations about user -schemes: - - http -paths: - /pet: - post: - tags: - - pet - summary: Add a new pet to the store - description: '' - operationId: addPet - consumes: - - application/json - - application/xml - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: Pet object that needs to be added to the store - required: true - schema: - $ref: '#/definitions/Pet' - responses: - '405': - description: Invalid input - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - put: - tags: - - pet - summary: Update an existing pet - description: '' - operationId: updatePet - consumes: - - application/json - - application/xml - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: Pet object that needs to be added to the store - required: true - schema: - $ref: '#/definitions/Pet' - responses: - '400': - description: Invalid ID supplied - '404': - description: Pet not found - '405': - description: Validation exception - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - /pet/findByStatus: - get: - tags: - - pet - summary: Finds Pets by status - description: Multiple status values can be provided with comma separated strings - operationId: findPetsByStatus - produces: - - application/xml - - application/json - parameters: - - name: status - in: query - description: Status values that need to be considered for filter - required: true - type: array - items: - type: string - enum: - - available - - pending - - sold - default: available - collectionFormat: csv - responses: - '200': - description: successful operation - schema: - type: array - items: - $ref: '#/definitions/Pet' - '400': - description: Invalid status value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - /pet/findByTags: - get: - tags: - - pet - summary: Finds Pets by tags - description: 'Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.' - operationId: findPetsByTags - produces: - - application/xml - - application/json - parameters: - - name: tags - in: query - description: Tags to filter by - required: true - type: array - items: - type: string - collectionFormat: csv - responses: - '200': - description: successful operation - schema: - type: array - items: - $ref: '#/definitions/Pet' - '400': - description: Invalid tag value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - deprecated: true - '/pet/{petId}': - get: - tags: - - pet - summary: Find pet by ID - description: Returns a single pet - operationId: getPetById - produces: - - application/xml - - application/json - parameters: - - name: petId - in: path - description: ID of pet to return - required: true - type: integer - format: int64 - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/Pet' - '400': - description: Invalid ID supplied - '404': - description: Pet not found - security: - - api_key: [] - - basicAuth: [] - post: - tags: - - pet - summary: Updates a pet in the store with form data - description: '' - operationId: updatePetWithForm - consumes: - - application/x-www-form-urlencoded - produces: - - application/xml - - application/json - parameters: - - name: petId - in: path - description: ID of pet that needs to be updated - required: true - type: integer - format: int64 - - name: name - in: formData - description: Updated name of the pet - required: false - type: string - - name: status - in: formData - description: Updated status of the pet - required: false - type: string - responses: - '405': - description: Invalid input - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - delete: - tags: - - pet - summary: Deletes a pet - description: '' - operationId: deletePet - produces: - - application/xml - - application/json - parameters: - - name: api_key - in: header - required: false - type: string - - name: petId - in: path - description: Pet id to delete - required: true - type: integer - format: int64 - responses: - '400': - description: Invalid pet value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - '/pet/{petId}/uploadImage': - post: - tags: - - pet - summary: uploads an image - description: '' - operationId: uploadFile - consumes: - - multipart/form-data - produces: - - application/json - parameters: - - name: petId - in: path - description: ID of pet to update - required: true - type: integer - format: int64 - - name: additionalMetadata - in: formData - description: Additional data to pass to server - required: false - type: string - - name: file - in: formData - description: file to upload - required: false - type: file - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/ApiResponse' - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' - /store/inventory: - get: - tags: - - store - summary: Returns pet inventories by status - description: Returns a map of status codes to quantities - operationId: getInventory - produces: - - application/json - parameters: [] - responses: - '200': - description: successful operation - schema: - type: object - additionalProperties: - type: integer - format: int32 - security: - - api_key: [] - /store/order: - post: - tags: - - store - summary: Place an order for a pet - description: '' - operationId: placeOrder - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: order placed for purchasing the pet - required: true - schema: - $ref: '#/definitions/Order' - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/Order' - '400': - description: Invalid Order - '/store/order/{order_id}': - get: - tags: - - store - summary: Find purchase order by ID - description: 'For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions' - operationId: getOrderById - produces: - - application/xml - - application/json - parameters: - - name: order_id - in: path - description: ID of pet that needs to be fetched - required: true - type: integer - maximum: 5 - minimum: 1 - format: int64 - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/Order' - '400': - description: Invalid ID supplied - '404': - description: Order not found - delete: - tags: - - store - summary: Delete purchase order by ID - description: For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors - operationId: deleteOrder - produces: - - application/xml - - application/json - parameters: - - name: order_id - in: path - description: ID of the order that needs to be deleted - required: true - type: string - responses: - '400': - description: Invalid ID supplied - '404': - description: Order not found - /user: - post: - tags: - - user - summary: Create user - description: This can only be done by the logged in user. - operationId: createUser - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: Created user object - required: true - schema: - $ref: '#/definitions/User' - responses: - default: - description: successful operation - /user/createWithArray: - post: - tags: - - user - summary: Creates list of users with given input array - description: '' - operationId: createUsersWithArrayInput - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: List of user object - required: true - schema: - type: array - items: - $ref: '#/definitions/User' - responses: - default: - description: successful operation - /user/createWithList: - post: - tags: - - user - summary: Creates list of users with given input array - description: '' - operationId: createUsersWithListInput - produces: - - application/xml - - application/json - parameters: - - in: body - name: body - description: List of user object - required: true - schema: - type: array - items: - $ref: '#/definitions/User' - responses: - default: - description: successful operation - /user/login: - get: - tags: - - user - summary: Logs user into the system - description: '' - operationId: loginUser - produces: - - application/xml - - application/json - parameters: - - name: username - in: query - description: The user name for login - required: true - type: string - - name: password - in: query - description: The password for login in clear text - required: true - type: string - responses: - '200': - description: successful operation - schema: - type: string - headers: - X-Rate-Limit: - type: integer - format: int32 - description: calls per hour allowed by the user - X-Expires-After: - type: string - format: date-time - description: date in UTC when toekn expires - '400': - description: Invalid username/password supplied - /user/logout: - get: - tags: - - user - summary: Logs out current logged in user session - description: '' - operationId: logoutUser - produces: - - application/xml - - application/json - parameters: [] - responses: - default: - description: successful operation - '/user/{username}': - get: - tags: - - user - summary: Get user by user name - description: '' - operationId: getUserByName - produces: - - application/xml - - application/json - parameters: - - name: username - in: path - description: 'The name that needs to be fetched. Use user1 for testing.' - required: true - type: string - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/User' - '400': - description: Invalid username supplied - '404': - description: User not found - put: - tags: - - user - summary: Updated user - description: This can only be done by the logged in user. - operationId: updateUser - produces: - - application/xml - - application/json - parameters: - - name: username - in: path - description: name that need to be deleted - required: true - type: string - - in: body - name: body - description: Updated user object - required: true - schema: - $ref: '#/definitions/User' - responses: - '400': - description: Invalid user supplied - '404': - description: User not found - delete: - tags: - - user - summary: Delete user - description: This can only be done by the logged in user. - operationId: deleteUser - produces: - - application/xml - - application/json - parameters: - - name: username - in: path - description: The name that needs to be deleted - required: true - type: string - responses: - '400': - description: Invalid username supplied - '404': - description: User not found -securityDefinitions: - petstore_auth: - type: oauth2 - authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' - flow: implicit - scopes: - 'write:pets': modify pets in your account - 'read:pets': read your pets - api_key: - type: apiKey - name: api_key - in: header - basicAuth: - type: basic -definitions: - Order: - title: Pet Order - description: An order for a pets from the pet store - type: object - properties: - id: - type: integer - format: int64 - petId: - type: integer - format: int64 - quantity: - type: integer - format: int32 - shipDate: - type: string - format: date-time - status: - type: string - description: Order Status - enum: - - placed - - approved - - delivered - complete: - type: boolean - default: false - xml: - name: Order - Category: - title: Pet category - description: A category for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: Category - User: - title: a User - description: A User who is purchasing from the pet store - type: object - properties: - id: - type: integer - format: int64 - username: - type: string - firstName: - type: string - lastName: - type: string - email: - type: string - password: - type: string - phone: - type: string - userStatus: - type: integer - format: int32 - description: User Status - xml: - name: User - Tag: - title: Pet Tag - description: A tag for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: Tag - Pet: - title: a Pet - description: A pet for sale in the pet store - type: object - required: - - name - - photoUrls - properties: - id: - type: integer - format: int64 - category: - $ref: '#/definitions/Category' - name: - type: string - example: doggie - photoUrls: - type: array - xml: - name: photoUrl - wrapped: true - items: - type: string - tags: - type: array - xml: - name: tag - wrapped: true - items: - $ref: '#/definitions/Tag' - status: - type: string - description: pet status in the store - enum: - - available - - pending - - sold - xml: - name: Pet - ApiResponse: - title: An uploaded response - description: Describes the result of uploading an image resource - type: object - properties: - code: - type: integer - format: int32 - type: - type: string - message: - type: string diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml deleted file mode 100644 index 7175b75f0e..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore_reservedWords.yaml +++ /dev/null @@ -1,120 +0,0 @@ -swagger: '2.0' -info: - description: 'This is a modified Petstore server, that uses the reserved word "name" as parameter name. This should be renamed to "_name" in the generated code.' - version: 1.0.0 - title: OpenAPI Petstore - license: - name: Apache-2.0 - url: 'https://www.apache.org/licenses/LICENSE-2.0.html' -host: petstore.swagger.io -basePath: /v2 -tags: - - name: pet - description: Everything about your Pets -schemes: - - http -paths: - /pet/findByName: - get: - tags: - - pet - summary: Finds Pet by name - description: Name can be any text - operationId: findPetByName - produces: - - application/xml - - application/json - parameters: - # name is a reserved word and should be masked with an '_' in the generated api - - name: name - in: query - description: Name of the pet - required: true - type: string - responses: - '200': - description: successful operation - schema: - $ref: '#/definitions/Pet' - '400': - description: Invalid name value - security: - - petstore_auth: - - 'write:pets' - - 'read:pets' -securityDefinitions: - petstore_auth: - type: oauth2 - authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog' - flow: implicit - scopes: - 'write:pets': modify pets in your account - 'read:pets': read your pets - api_key: - type: apiKey - name: api_key - in: header -definitions: - Category: - title: Pet category - description: A category for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: Category - Tag: - title: Pet Tag - description: A tag for a pet - type: object - properties: - id: - type: integer - format: int64 - name: - type: string - xml: - name: Tag - Pet: - title: a Pet - description: A pet for sale in the pet store - type: object - required: - - name - - photoUrls - properties: - id: - type: integer - format: int64 - category: - $ref: '#/definitions/Category' - name: - type: string - example: doggie - photoUrls: - type: array - xml: - name: photoUrl - wrapped: true - items: - type: string - tags: - type: array - xml: - name: tag - wrapped: true - items: - $ref: '#/definitions/Tag' - status: - type: string - description: pet status in the store - enum: - - available - - pending - - sold - xml: - name: Pet diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java new file mode 100644 index 0000000000..b3ffdcb025 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java @@ -0,0 +1,11 @@ +package org.citrusframework.openapi.generator.rest.extpetstore; + +import java.net.URL; + +public class ExtPetStore { + + public static URL extPetStoreApi() { + return ExtPetStore.class.getResource("ExtPetStore_openApi.yaml"); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java new file mode 100644 index 0000000000..7f57903b45 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -0,0 +1,119 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * Category + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Category { + private Long id; + + private String _name; + + public Category() { + } + + public Category id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Category _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java new file mode 100644 index 0000000000..1763cfd8c5 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -0,0 +1,120 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.LocalDate; + +/** + * Additional historical data for a vaccination report, not contained in internal storage. + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class HistoricalData { + private LocalDate lastVaccinationDate; + + private Integer vaccinationCount; + + public HistoricalData() { + } + + public HistoricalData lastVaccinationDate(LocalDate lastVaccinationDate) { + + this.lastVaccinationDate = lastVaccinationDate; + return this; + } + + /** + * The date of the last vaccination. + * @return lastVaccinationDate + **/ + @jakarta.annotation.Nullable + + public LocalDate getLastVaccinationDate() { + return lastVaccinationDate; + } + + + public void setLastVaccinationDate(LocalDate lastVaccinationDate) { + this.lastVaccinationDate = lastVaccinationDate; + } + + + public HistoricalData vaccinationCount(Integer vaccinationCount) { + + this.vaccinationCount = vaccinationCount; + return this; + } + + /** + * The number of vaccinations the pet has received. + * @return vaccinationCount + **/ + @jakarta.annotation.Nullable + + public Integer getVaccinationCount() { + return vaccinationCount; + } + + + public void setVaccinationCount(Integer vaccinationCount) { + this.vaccinationCount = vaccinationCount; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HistoricalData historicalData = (HistoricalData) o; + return Objects.equals(this.lastVaccinationDate, historicalData.lastVaccinationDate) && + Objects.equals(this.vaccinationCount, historicalData.vaccinationCount); + } + + @Override + public int hashCode() { + return Objects.hash(lastVaccinationDate, vaccinationCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HistoricalData {\n"); + sb.append(" lastVaccinationDate: ").append(toIndentedString(lastVaccinationDate)).append("\n"); + sb.append(" vaccinationCount: ").append(toIndentedString(vaccinationCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java new file mode 100644 index 0000000000..82b87e69b6 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -0,0 +1,279 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.citrusframework.openapi.generator.rest.extpetstore.model.Category; +import org.citrusframework.openapi.generator.rest.extpetstore.model.Tag; + +/** + * Pet + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Pet { + private Long id; + + private String _name; + + private Category category; + + private List photoUrls = new ArrayList<>(); + + private List tags = new ArrayList<>(); + + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + + PENDING("pending"), + + SOLD("sold"); + + private String value; + + StatusEnum(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + @Override + public String toString() { + return String.valueOf(value); + } + + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } + } + + private StatusEnum status; + + public Pet() { + } + + public Pet id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Pet _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nonnull + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + + public Pet category(Category category) { + + this.category = category; + return this; + } + + /** + * Get category + * @return category + **/ + @jakarta.annotation.Nullable + + public Category getCategory() { + return category; + } + + + public void setCategory(Category category) { + this.category = category; + } + + + public Pet photoUrls(List photoUrls) { + + this.photoUrls = photoUrls; + return this; + } + + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); + } + this.photoUrls.add(photoUrlsItem); + return this; + } + + /** + * Get photoUrls + * @return photoUrls + **/ + @jakarta.annotation.Nonnull + + public List getPhotoUrls() { + return photoUrls; + } + + + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + + + public Pet tags(List tags) { + + this.tags = tags; + return this; + } + + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); + } + this.tags.add(tagsItem); + return this; + } + + /** + * Get tags + * @return tags + **/ + @jakarta.annotation.Nullable + + public List getTags() { + return tags; + } + + + public void setTags(List tags) { + this.tags = tags; + } + + + public Pet status(StatusEnum status) { + + this.status = status; + return this; + } + + /** + * pet status in the store + * @return status + **/ + @jakarta.annotation.Nullable + + public StatusEnum getStatus() { + return status; + } + + + public void setStatus(StatusEnum status) { + this.status = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name, category, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java new file mode 100644 index 0000000000..59471e20ad --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -0,0 +1,119 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * Tag + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Tag { + private Long id; + + private String _name; + + public Tag() { + } + + public Tag id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Tag _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java new file mode 100644 index 0000000000..5713e91f12 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -0,0 +1,93 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * VaccinationDocumentResult + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class VaccinationDocumentResult { + private String documentId; + + public VaccinationDocumentResult() { + } + + public VaccinationDocumentResult documentId(String documentId) { + + this.documentId = documentId; + return this; + } + + /** + * The unique ID of the uploaded vaccination document. + * @return documentId + **/ + @jakarta.annotation.Nullable + + public String getDocumentId() { + return documentId; + } + + + public void setDocumentId(String documentId) { + this.documentId = documentId; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VaccinationDocumentResult vaccinationDocumentResult = (VaccinationDocumentResult) o; + return Objects.equals(this.documentId, vaccinationDocumentResult.documentId); + } + + @Override + public int hashCode() { + return Objects.hash(documentId); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VaccinationDocumentResult {\n"); + sb.append(" documentId: ").append(toIndentedString(documentId)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java new file mode 100644 index 0000000000..e8fcfb646e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -0,0 +1,4081 @@ +package org.citrusframework.openapi.generator.rest.extpetstore.request; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.ParameterStyle; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; + +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; +import org.citrusframework.openapi.generator.rest.extpetstore.model.*; + +@SuppressWarnings("unused") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class ExtPetApi implements GeneratedApi +{ + + @Value("${" + "extpetstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "extpetstore.basic.username:#{null}}") + private String basicUsername; + + @Value("${" + "extpetstore.basic.password:#{null}}") + private String basicPassword; + + @Value("${" + "extpetstore.bearer.token:#{null}}") + private String basicAuthBearer; + + @Value("${" + "extpetstore.api-key-header:#{null}}") + private String defaultApiKeyHeader; + + @Value("${" + "extpetstore.api-key-cookie:#{null}}") + private String defaultApiKeyCookie; + + @Value("${" + "extpetstore.api-key-query:#{null}}") + private String defaultApiKeyQuery; + + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public ExtPetApi(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public ExtPetApi(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + + URL resource = ExtPetStore.class.getResource("ExtPetStore_openApi.yaml"); + if (resource == null) { + throw new IllegalStateException(format("Cannot find resource '%s'. This resource is typically created during API generation and should therefore be present. Check API generation.", "ExtPetStore_openApi.yaml")); + } + openApiSpecification = OpenApiSpecification.from(resource); + } + + public static ExtPetApi extPetApi(Endpoint endpoint) { + return new ExtPetApi(endpoint); + } + + @Override + public String getApiTitle() { + return "Extended Petstore API"; + } + + @Override + public String getApiVersion() { + return "1.0.0"; + } + + @Override + public String getApiPrefix() { + return "ExtPetStore"; + } + + @Override + public Map getApiInfoExtensions() { + return emptyMap(); + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + + /** + * Builder with type safe required parameters. + */ + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport(Resource template, Integer reqIntVal) { + return new GenerateVaccinationReportSendActionBuilder(this, openApiSpecification, template, reqIntVal); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport$(String templateExpression, String reqIntValExpression ) { + return new GenerateVaccinationReportSendActionBuilder(openApiSpecification, this, templateExpression, reqIntValExpression); + } + + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull HttpStatus statusCode) { + return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull String statusCode) { + return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKeyQuery(defaultApiKeyQuery); + builder.setApiKeyHeader(defaultApiKeyHeader); + builder.setApiKeyCookie(defaultApiKeyCookie); + return builder; + } + + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull HttpStatus statusCode) { + return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthUsername(basicUsername); + builder.setBasicAuthPassword(basicPassword); + return builder; + } + + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull HttpStatus statusCode) { + return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthBearer(basicAuthBearer); + return builder; + } + + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull HttpStatus statusCode) { + return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie(Long petId, String sessionId) { + return new GetPetWithCookieSendActionBuilder(this, openApiSpecification, petId, sessionId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie$(String petIdExpression, String sessionIdExpression ) { + return new GetPetWithCookieSendActionBuilder(openApiSpecification, this, petIdExpression, sessionIdExpression); + } + + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull HttpStatus statusCode) { + return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull String statusCode) { + return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery(PetIdentifier petId) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery$(String petIdExpression ) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull HttpStatus statusCode) { + return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull String statusCode) { + return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie(List petId) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie$(List petIdExpression ) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull HttpStatus statusCode) { + return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie(PetIdentifier petId) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie$(String petIdExpression ) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull HttpStatus statusCode) { + return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie(List petId) { + return new GetPetWithFormStyleCookieSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie$(List petIdExpression ) { + return new GetPetWithFormStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull HttpStatus statusCode) { + return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery$(String petIdExpression ) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull HttpStatus statusCode) { + return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery(List petId) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery$(List petIdExpression ) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull HttpStatus statusCode) { + return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery$(String petIdExpression ) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull HttpStatus statusCode) { + return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery(List petId) { + return new GetPetWithFormStyleQuerySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery$(List petIdExpression ) { + return new GetPetWithFormStyleQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull HttpStatus statusCode) { + return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray(List petId) { + return new GetPetWithLabelStyleArraySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray$(List petIdExpression ) { + return new GetPetWithLabelStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull HttpStatus statusCode) { + return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded(List petId) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject$(String petIdExpression ) { + return new GetPetWithLabelStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull HttpStatus statusCode) { + return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray(List petId) { + return new GetPetWithMatrixStyleArraySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray$(List petIdExpression ) { + return new GetPetWithMatrixStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull HttpStatus statusCode) { + return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded(List petId) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject$(String petIdExpression ) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull HttpStatus statusCode) { + return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray(List petId) { + return new GetPetWithSimpleStyleArraySendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray$(List petIdExpression ) { + return new GetPetWithSimpleStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded(List petId) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader(List petId) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader$(List petIdExpression ) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader$(String petIdExpression ) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader(List petId) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader$(List petIdExpression ) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull HttpStatus statusCode) { + return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public PostVaccinationDocumentSendActionBuilder sendPostVaccinationDocument(String bucket, String filename) { + return new PostVaccinationDocumentSendActionBuilder(this, openApiSpecification, bucket, filename); + } + + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull HttpStatus statusCode) { + return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull String statusCode) { + return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public PostVaccinationFormDataSendActionBuilder sendPostVaccinationFormData() { + return new PostVaccinationFormDataSendActionBuilder(this, openApiSpecification); + } + + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull HttpStatus statusCode) { + return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull String statusCode) { + return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData(Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(this, openApiSpecification, petId, _name, status, tags, nicknames, sampleStringHeader); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData$(String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression ) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, tagsExpression, nicknamesExpression, sampleStringHeaderExpression); + } + + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull HttpStatus statusCode) { + return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull String statusCode) { + return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded(Long petId, String _name, String status, Integer age, List tags) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(this, openApiSpecification, petId, _name, status, age, tags); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded$(String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression ) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, ageExpression, tagsExpression); + } + + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull HttpStatus statusCode) { + return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull String statusCode) { + return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + public static class GenerateVaccinationReportSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/status-report"; + + private static final String OPERATION_NAME = "generateVaccinationReport"; + + /** + * Constructor with type safe required parameters. + */ + public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Resource template, Integer reqIntVal) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + formParameter("template", toBinary(template) ); + formParameter("reqIntVal", reqIntVal); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String templateExpression, String reqIntValExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + formParameter("template", toBinary(templateExpression) ); + formParameter("reqIntVal", reqIntValExpression); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String templateExpression, String reqIntValExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + formParameter("template", toBinary(templateExpression) ); + formParameter("reqIntVal", reqIntValExpression); + } + + public GenerateVaccinationReportSendActionBuilder template(Resource template) { + formParameter("template", toBinary(template) ); + return this; + } + + public GenerateVaccinationReportSendActionBuilder template(String templateExpression) { + formParameter("template", toBinary(templateExpression) ); + return this; + } + + public GenerateVaccinationReportSendActionBuilder reqIntVal(Integer reqIntVal) { + formParameter("reqIntVal", reqIntVal); + return this; + } + + public GenerateVaccinationReportSendActionBuilder reqIntVal(String reqIntValExpression) { + formParameter("reqIntVal", reqIntValExpression); + return this; + } + + public GenerateVaccinationReportSendActionBuilder optIntVal(Integer optIntVal) { + formParameter("optIntVal", optIntVal); + return this; + } + + public void setOptIntVal(Integer optIntVal) { + formParameter("optIntVal", optIntVal); + } + + public GenerateVaccinationReportSendActionBuilder optIntVal(String optIntValExpression) { + formParameter("optIntVal", optIntValExpression); + return this; + } + + public void setOptIntVal(String optIntValExpression) { + formParameter("optIntVal", optIntValExpression); + } + + public GenerateVaccinationReportSendActionBuilder optBoolVal(Boolean optBoolVal) { + formParameter("optBoolVal", optBoolVal); + return this; + } + + public void setOptBoolVal(Boolean optBoolVal) { + formParameter("optBoolVal", optBoolVal); + } + + public GenerateVaccinationReportSendActionBuilder optBoolVal(String optBoolValExpression) { + formParameter("optBoolVal", optBoolValExpression); + return this; + } + + public void setOptBoolVal(String optBoolValExpression) { + formParameter("optBoolVal", optBoolValExpression); + } + + public GenerateVaccinationReportSendActionBuilder optNumberVal(BigDecimal optNumberVal) { + formParameter("optNumberVal", optNumberVal); + return this; + } + + public void setOptNumberVal(BigDecimal optNumberVal) { + formParameter("optNumberVal", optNumberVal); + } + + public GenerateVaccinationReportSendActionBuilder optNumberVal(String optNumberValExpression) { + formParameter("optNumberVal", optNumberValExpression); + return this; + } + + public void setOptNumberVal(String optNumberValExpression) { + formParameter("optNumberVal", optNumberValExpression); + } + + public GenerateVaccinationReportSendActionBuilder optStringVal(String optStringVal) { + formParameter("optStringVal", optStringVal); + return this; + } + + public void setOptStringVal(String optStringVal) { + formParameter("optStringVal", optStringVal); + } + + public GenerateVaccinationReportSendActionBuilder optDateVal(LocalDate optDateVal) { + formParameter("optDateVal", optDateVal); + return this; + } + + public void setOptDateVal(LocalDate optDateVal) { + formParameter("optDateVal", optDateVal); + } + + public GenerateVaccinationReportSendActionBuilder optDateVal(String optDateValExpression) { + formParameter("optDateVal", optDateValExpression); + return this; + } + + public void setOptDateVal(String optDateValExpression) { + formParameter("optDateVal", optDateValExpression); + } + + public GenerateVaccinationReportSendActionBuilder additionalData(HistoricalData additionalData) { + formParameter("additionalData", additionalData); + return this; + } + + public void setAdditionalData(HistoricalData additionalData) { + formParameter("additionalData", additionalData); + } + + public GenerateVaccinationReportSendActionBuilder additionalData(String additionalDataExpression) { + formParameter("additionalData", additionalDataExpression); + return this; + } + + public void setAdditionalData(String additionalDataExpression) { + formParameter("additionalData", additionalDataExpression); + } + + public GenerateVaccinationReportSendActionBuilder schema(Resource schema) { + formParameter("schema", toBinary(schema) ); + return this; + } + + public void setSchema(Resource schema) { + formParameter("schema", toBinary(schema) ); + } + + public GenerateVaccinationReportSendActionBuilder schema(String schemaExpression) { + formParameter("schema", toBinary(schemaExpression) ); + return this; + } + + public void setSchema(String schemaExpression) { + formParameter("schema", toBinary(schemaExpression) ); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GenerateVaccinationReportReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/status-report"; + + private static final String OPERATION_NAME = "generateVaccinationReport"; + + public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetByIdWithApiKeyAuthenticationSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-api-key/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithApiKeyAuthentication"; + + @Value("${" + "extpetstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "extpetstore.api-key-query:#{null}}") + private String defaultApiKeyQuery; + + private String apiKeyQuery; + + @Value("${" + "extpetstore.api-key-header:#{null}}") + private String defaultApiKeyHeader; + + private String apiKeyHeader; + + @Value("${" + "extpetstore.api-key-cookie:#{null}}") + private String defaultApiKeyCookie; + + private String apiKeyCookie; + + /** + * Constructor with type safe required parameters. + */ + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, Boolean allDetails) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(Boolean allDetails) { + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder details(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + return this; + } + + public void setDetails(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + return this; + } + + public void setRequesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + } + + public void setBase64EncodeApiKey(boolean encode) { + this.base64EncodeApiKey = encode; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder apiKeyQuery(String apiKeyQuery) { + this.apiKeyQuery = apiKeyQuery; + return this; + } + + public void setApiKeyQuery(String apiKeyQuery) { + this.apiKeyQuery = apiKeyQuery; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder apiKeyHeader(String apiKeyHeader) { + this.apiKeyHeader = apiKeyHeader; + return this; + } + + public void setApiKeyHeader(String apiKeyHeader) { + this.apiKeyHeader = apiKeyHeader; + } + + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder apiKeyCookie(String apiKeyCookie) { + this.apiKeyCookie = apiKeyCookie; + return this; + } + + public void setApiKeyCookie(String apiKeyCookie) { + this.apiKeyCookie = apiKeyCookie; + } + + @Override + public SendMessageAction doBuild() { + queryParameter("api_key_query", getOrDefault(apiKeyQuery, defaultApiKeyQuery, base64EncodeApiKey)); + headerParameter("api_key_header", getOrDefault(apiKeyHeader, defaultApiKeyHeader, base64EncodeApiKey)); + cookieParameter("api_key_cookie", getOrDefault(apiKeyCookie, defaultApiKeyCookie, base64EncodeApiKey)); + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-api-key/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithApiKeyAuthentication"; + + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetByIdWithBasicAuthenticationSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-basic/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithBasicAuthentication"; + + @Value("${" + "extpetstore.basic.username:#{null}}") + private String defaultBasicUsername; + + private String basicUsername; + + @Value("${" + "extpetstore.basic.password:#{null}}") + private String defaultBasicPassword; + + private String basicPassword; + + /** + * Constructor with type safe required parameters. + */ + public GetPetByIdWithBasicAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, Boolean allDetails) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBasicAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBasicAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(Boolean allDetails) { + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder details(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + return this; + } + + public void setDetails(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + return this; + } + + public void setRequesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder basicAuthUsername(String basicUsername) { + this.basicUsername = basicUsername; + return this; + } + + public void setBasicAuthUsername(String basicUsername) { + this.basicUsername = basicUsername; + } + + public GetPetByIdWithBasicAuthenticationSendActionBuilder basicAuthPassword(String password) { + this.basicPassword = password; + return this; + } + + public void setBasicAuthPassword(String password) { + this.basicPassword = password; + } + + protected void addBasicAuthHeader(String basicUsername, String basicPassword, + HttpMessageBuilderSupport messageBuilderSupport) { + TestApiUtils.addBasicAuthHeader( + isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, + isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, + messageBuilderSupport); + } + + @Override + public SendMessageAction doBuild() { + addBasicAuthHeader(basicUsername, basicPassword, getMessageBuilderSupport()); + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetByIdWithBasicAuthenticationReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-basic/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithBasicAuthentication"; + + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetByIdWithBearerAuthenticationSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-bearer/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithBearerAuthentication"; + + @Value("${" + "extpetstore.bearer.token:#{null}}") + private String defaultBasicAuthBearer; + + private String basicAuthBearer; + + /** + * Constructor with type safe required parameters. + */ + public GetPetByIdWithBearerAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, Boolean allDetails) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBearerAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdWithBearerAuthenticationSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(Boolean allDetails) { + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { + queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder details(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + return this; + } + + public void setDetails(String...details) { + queryParameter("details", details, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + return this; + } + + public void setRequesterInformation(String...requesterInformation) { + queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); + } + + public GetPetByIdWithBearerAuthenticationSendActionBuilder basicAuthBearer(String basicAuthBearer) { + this.basicAuthBearer = basicAuthBearer; + return this; + } + + public void setBasicAuthBearer(String basicAuthBearer) { + this.basicAuthBearer = basicAuthBearer; + } + + @Override + public SendMessageAction doBuild() { + if (!isEmpty(basicAuthBearer) || !isEmpty(defaultBasicAuthBearer)) { + headerParameter("Authorization", "Bearer " +getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); + } + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetByIdWithBearerAuthenticationReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/secure-bearer/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetByIdWithBearerAuthentication"; + + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithCookieSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetWithCookie"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, String sessionId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + cookieParameter("session_id", sessionId, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String sessionIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + cookieParameter("session_id", sessionIdExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String sessionIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + cookieParameter("session_id", sessionIdExpression, ParameterStyle.FORM, true, false); + } + + public GetPetWithCookieSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithCookieSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithCookieSendActionBuilder sessionId(String sessionId) { + cookieParameter("session_id", sessionId, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetWithCookieSendActionBuilder optTrxId(String optTrxId) { + cookieParameter("opt_trx_id", optTrxId, ParameterStyle.FORM, true, false); + return this; + } + + public void setOptTrxId(String optTrxId) { + cookieParameter("opt_trx_id", optTrxId, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithCookieReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetWithCookie"; + + public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithDeepObjectTypeQuerySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/deep/object"; + + private static final String OPERATION_NAME = "getPetWithDeepObjectTypeQuery"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithDeepObjectTypeQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.DEEPOBJECT, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithDeepObjectTypeQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithDeepObjectTypeQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); + } + + public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(PetIdentifier petId) { + queryParameter("petId", petId, ParameterStyle.DEEPOBJECT, true, true); + return this; + } + + public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(String petIdExpression) { + queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithDeepObjectTypeQueryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/deep/object"; + + private static final String OPERATION_NAME = "getPetWithDeepObjectTypeQuery"; + + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormExplodedStyleCookieSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form/exploded"; + + private static final String OPERATION_NAME = "getPetWithFormExplodedStyleCookie"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petId, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormExplodedStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petId, ParameterStyle.FORM, true, false); + } + + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(Integer...petId) { + cookieParameter("petId", petId, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String...petIdExpression) { + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormExplodedStyleCookieReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form/exploded"; + + private static final String OPERATION_NAME = "getPetWithFormExplodedStyleCookie"; + + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormObjectStyleCookieSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form/object"; + + private static final String OPERATION_NAME = "getPetWithFormObjectStyleCookie"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormObjectStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petId, ParameterStyle.FORM, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormObjectStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormObjectStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + } + + public GetPetWithFormObjectStyleCookieSendActionBuilder petId(PetIdentifier petId) { + cookieParameter("petId", petId, ParameterStyle.FORM, false, true); + return this; + } + + public GetPetWithFormObjectStyleCookieSendActionBuilder petId(String petIdExpression) { + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormObjectStyleCookieReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form/object"; + + private static final String OPERATION_NAME = "getPetWithFormObjectStyleCookie"; + + public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormStyleCookieSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form"; + + private static final String OPERATION_NAME = "getPetWithFormStyleCookie"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petId, ParameterStyle.FORM, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + cookieParameter("petId", petId, ParameterStyle.FORM, false, false); + } + + public GetPetWithFormStyleCookieSendActionBuilder petId(Integer...petId) { + cookieParameter("petId", petId, ParameterStyle.FORM, false, false); + return this; + } + + public GetPetWithFormStyleCookieSendActionBuilder petId(String...petIdExpression) { + cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormStyleCookieReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/cookie/form"; + + private static final String OPERATION_NAME = "getPetWithFormStyleCookie"; + + public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormStyleExplodedObjectQuerySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/exploded/object"; + + private static final String OPERATION_NAME = "getPetWithFormStyleExplodedObjectQuery"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); + } + + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(PetIdentifier petId) { + queryParameter("petId", petId, ParameterStyle.FORM, true, true); + return this; + } + + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(String petIdExpression) { + queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/exploded/object"; + + private static final String OPERATION_NAME = "getPetWithFormStyleExplodedObjectQuery"; + + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormStyleExplodedQuerySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/exploded"; + + private static final String OPERATION_NAME = "getPetWithFormStyleExplodedQuery"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, true, false); + } + + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(Integer...petId) { + queryParameter("petId", petId, ParameterStyle.FORM, true, false); + return this; + } + + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String...petIdExpression) { + queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormStyleExplodedQueryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/exploded"; + + private static final String OPERATION_NAME = "getPetWithFormStyleExplodedQuery"; + + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormStyleObjectQuerySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/object"; + + private static final String OPERATION_NAME = "getPetWithFormStyleObjectQuery"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormStyleObjectQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleObjectQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + } + + public GetPetWithFormStyleObjectQuerySendActionBuilder petId(PetIdentifier petId) { + queryParameter("petId", petId, ParameterStyle.FORM, false, true); + return this; + } + + public GetPetWithFormStyleObjectQuerySendActionBuilder petId(String petIdExpression) { + queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormStyleObjectQueryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form/object"; + + private static final String OPERATION_NAME = "getPetWithFormStyleObjectQuery"; + + public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithFormStyleQuerySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form"; + + private static final String OPERATION_NAME = "getPetWithFormStyleQuery"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + queryParameter("petId", petId, ParameterStyle.FORM, false, false); + } + + public GetPetWithFormStyleQuerySendActionBuilder petId(Integer...petId) { + queryParameter("petId", petId, ParameterStyle.FORM, false, false); + return this; + } + + public GetPetWithFormStyleQuerySendActionBuilder petId(String...petIdExpression) { + queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithFormStyleQueryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/query/form"; + + private static final String OPERATION_NAME = "getPetWithFormStyleQuery"; + + public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithLabelStyleArraySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleArray"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, false, false); + } + + public GetPetWithLabelStyleArraySendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.LABEL, false, false); + return this; + } + + public GetPetWithLabelStyleArraySendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithLabelStyleArrayReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleArray"; + + public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithLabelStyleArrayExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleArrayExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, true, false); + } + + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.LABEL, true, false); + return this; + } + + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithLabelStyleArrayExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleArrayExploded"; + + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithLabelStyleObjectSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleObject"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithLabelStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); + } + + public GetPetWithLabelStyleObjectSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.LABEL, false, true); + return this; + } + + public GetPetWithLabelStyleObjectSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithLabelStyleObjectReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleObject"; + + public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithLabelStyleObjectExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleObjectExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithLabelStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.LABEL, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithLabelStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); + } + + public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.LABEL, true, true); + return this; + } + + public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithLabelStyleObjectExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/label/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithLabelStyleObjectExploded"; + + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithMatrixStyleArraySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleArray"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); + } + + public GetPetWithMatrixStyleArraySendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); + return this; + } + + public GetPetWithMatrixStyleArraySendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithMatrixStyleArrayReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleArray"; + + public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithMatrixStyleArrayExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleArrayExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); + } + + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); + return this; + } + + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleArrayExploded"; + + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithMatrixStyleObjectSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleObject"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithMatrixStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); + } + + public GetPetWithMatrixStyleObjectSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.MATRIX, false, true); + return this; + } + + public GetPetWithMatrixStyleObjectSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithMatrixStyleObjectReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleObject"; + + public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithMatrixStyleObjectExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleObjectExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.MATRIX, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); + } + + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.MATRIX, true, true); + return this; + } + + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/matrix/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithMatrixStyleObjectExploded"; + + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleArraySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleArray"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + public GetPetWithSimpleStyleArraySendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithSimpleStyleArraySendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleArrayReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleArray"; + + public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleArrayExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleArrayExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/exploded/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleArrayExploded"; + + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleExplodedHeaderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/exploded"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedHeader"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); + } + + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(Integer...petId) { + headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); + return this; + } + + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String...petIdExpression) { + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/exploded"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedHeader"; + + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/exploded/object"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedObjectHeader"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + } + + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(PetIdentifier petId) { + headerParameter("petId", petId, ParameterStyle.SIMPLE, true, true); + return this; + } + + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(String petIdExpression) { + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/exploded/object"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedObjectHeader"; + + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleHeaderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleHeader"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, List petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, List petId) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(Integer...petId) { + headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String...petIdExpression) { + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleHeaderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleHeader"; + + public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleObjectSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObject"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + } + + public GetPetWithSimpleStyleObjectSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, true); + return this; + } + + public GetPetWithSimpleStyleObjectSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleObjectReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObject"; + + public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleObjectExplodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectExploded"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + } + + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(PetIdentifier petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, true, true); + return this; + } + + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/simple/exploded/object/{petId}"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectExploded"; + + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetWithSimpleStyleObjectHeaderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/object"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectHeader"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, PetIdentifier petId) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petId, ParameterStyle.SIMPLE, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + } + + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(PetIdentifier petId) { + headerParameter("petId", petId, ParameterStyle.SIMPLE, false, true); + return this; + } + + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(String petIdExpression) { + headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/header/simple/object"; + + private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectHeader"; + + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class PostVaccinationDocumentSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/{bucket}/{filename}"; + + private static final String OPERATION_NAME = "postVaccinationDocument"; + + /** + * Constructor with type safe required parameters. + */ + public PostVaccinationDocumentSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String bucket, String filename) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("bucket", bucket, ParameterStyle.SIMPLE, false, false); + pathParameter("filename", filename, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public PostVaccinationDocumentSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String bucketExpression, String filenameExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("bucket", bucketExpression, ParameterStyle.SIMPLE, false, false); + pathParameter("filename", filenameExpression, ParameterStyle.SIMPLE, false, false); + } + + public PostVaccinationDocumentSendActionBuilder bucket(String bucket) { + pathParameter("bucket", bucket, ParameterStyle.SIMPLE, false, false); + return this; + } + + public PostVaccinationDocumentSendActionBuilder filename(String filename) { + pathParameter("filename", filename, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class PostVaccinationDocumentReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/{bucket}/{filename}"; + + private static final String OPERATION_NAME = "postVaccinationDocument"; + + public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class PostVaccinationFormDataSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/form"; + + private static final String OPERATION_NAME = "postVaccinationFormData"; + + /** + * Constructor with type safe required parameters. + */ + public PostVaccinationFormDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public PostVaccinationFormDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public PostVaccinationFormDataSendActionBuilder vaccine(String vaccine) { + formParameter("vaccine", vaccine); + return this; + } + + public void setVaccine(String vaccine) { + formParameter("vaccine", vaccine); + } + + public PostVaccinationFormDataSendActionBuilder isFirstVaccination(Boolean isFirstVaccination) { + formParameter("isFirstVaccination", isFirstVaccination); + return this; + } + + public void setIsFirstVaccination(Boolean isFirstVaccination) { + formParameter("isFirstVaccination", isFirstVaccination); + } + + public PostVaccinationFormDataSendActionBuilder isFirstVaccination(String isFirstVaccinationExpression) { + formParameter("isFirstVaccination", isFirstVaccinationExpression); + return this; + } + + public void setIsFirstVaccination(String isFirstVaccinationExpression) { + formParameter("isFirstVaccination", isFirstVaccinationExpression); + } + + public PostVaccinationFormDataSendActionBuilder doseNumber(Integer doseNumber) { + formParameter("doseNumber", doseNumber); + return this; + } + + public void setDoseNumber(Integer doseNumber) { + formParameter("doseNumber", doseNumber); + } + + public PostVaccinationFormDataSendActionBuilder doseNumber(String doseNumberExpression) { + formParameter("doseNumber", doseNumberExpression); + return this; + } + + public void setDoseNumber(String doseNumberExpression) { + formParameter("doseNumber", doseNumberExpression); + } + + public PostVaccinationFormDataSendActionBuilder vaccinationDate(LocalDate vaccinationDate) { + formParameter("vaccinationDate", vaccinationDate); + return this; + } + + public void setVaccinationDate(LocalDate vaccinationDate) { + formParameter("vaccinationDate", vaccinationDate); + } + + public PostVaccinationFormDataSendActionBuilder vaccinationDate(String vaccinationDateExpression) { + formParameter("vaccinationDate", vaccinationDateExpression); + return this; + } + + public void setVaccinationDate(String vaccinationDateExpression) { + formParameter("vaccinationDate", vaccinationDateExpression); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class PostVaccinationFormDataReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/ext/pet/vaccination/form"; + + private static final String OPERATION_NAME = "postVaccinationFormData"; + + public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UpdatePetWithArrayQueryDataSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/ext/pet/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithArrayQueryData"; + + /** + * Constructor with type safe required parameters. + */ + public UpdatePetWithArrayQueryDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + queryParameter("name", _name, ParameterStyle.FORM, true, false); + queryParameter("status", status, ParameterStyle.FORM, true, false); + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); + headerParameter("sampleStringHeader", sampleStringHeader, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithArrayQueryDataSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("name", _nameExpression, ParameterStyle.FORM, true, false); + queryParameter("status", statusExpression, ParameterStyle.FORM, true, false); + queryParameter("tags", tagsExpression, ParameterStyle.FORM, true, false); + queryParameter("nicknames", nicknamesExpression, ParameterStyle.FORM, true, false); + headerParameter("sampleStringHeader", sampleStringHeaderExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithArrayQueryDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String _nameExpression, String statusExpression, List tags, List nicknames, String sampleStringHeaderExpression) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + queryParameter("name", _nameExpression, ParameterStyle.FORM, true, false); + queryParameter("status", statusExpression, ParameterStyle.FORM, true, false); + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); + headerParameter("sampleStringHeader", sampleStringHeaderExpression, ParameterStyle.SIMPLE, false, false); + } + + public UpdatePetWithArrayQueryDataSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder _name(String _name) { + queryParameter("name", _name, ParameterStyle.FORM, true, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder status(String status) { + queryParameter("status", status, ParameterStyle.FORM, true, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder tags(String...tags) { + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder nicknames(String...nicknames) { + queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder sampleStringHeader(String sampleStringHeader) { + headerParameter("sampleStringHeader", sampleStringHeader, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithArrayQueryDataSendActionBuilder sampleIntHeader(Integer sampleIntHeader) { + headerParameter("sampleIntHeader", sampleIntHeader, ParameterStyle.SIMPLE, false, false); + return this; + } + + public void setSampleIntHeader(Integer sampleIntHeader) { + headerParameter("sampleIntHeader", sampleIntHeader, ParameterStyle.SIMPLE, false, false); + } + + public UpdatePetWithArrayQueryDataSendActionBuilder sampleIntHeader(String sampleIntHeaderExpression) { + headerParameter("sampleIntHeader", sampleIntHeaderExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public void setSampleIntHeader(String sampleIntHeaderExpression) { + headerParameter("sampleIntHeader", sampleIntHeaderExpression, ParameterStyle.SIMPLE, false, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UpdatePetWithArrayQueryDataReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/ext/pet/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithArrayQueryData"; + + public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UpdatePetWithFormUrlEncodedSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/ext/pet/form/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithFormUrlEncoded"; + + /** + * Constructor with type safe required parameters. + */ + public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, String _name, String status, Integer age, List tags) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + formParameter("name", _name); + formParameter("status", status); + formParameter("age", age); + formParameter("tags", tags); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tagsExpression); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tags) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tags); + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder _name(String _name) { + formParameter("name", _name); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder status(String status) { + formParameter("status", status); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder age(Integer age) { + formParameter("age", age); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder age(String ageExpression) { + formParameter("age", ageExpression); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder tags(String...tags) { + formParameter("tags", tags); + return this; + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder owners(Integer owners) { + formParameter("owners", owners); + return this; + } + + public void setOwners(Integer owners) { + formParameter("owners", owners); + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder owners(String ownersExpression) { + formParameter("owners", ownersExpression); + return this; + } + + public void setOwners(String ownersExpression) { + formParameter("owners", ownersExpression); + } + + public UpdatePetWithFormUrlEncodedSendActionBuilder nicknames(String...nicknames) { + formParameter("nicknames", nicknames); + return this; + } + + public void setNicknames(String...nicknames) { + formParameter("nicknames", nicknames); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UpdatePetWithFormUrlEncodedReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/ext/pet/form/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithFormUrlEncoded"; + + public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java new file mode 100644 index 0000000000..3929d725f9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -0,0 +1,33 @@ +package org.citrusframework.openapi.generator.rest.extpetstore.spring; + +import java.util.List; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; + + +@Configuration +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class ExtPetStoreBeanConfiguration { + + @Bean + public OpenApiRepository extPetStoreOpenApiRepository() { + var openApiRepository = new OpenApiRepository(); + openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( + ExtPetStore.extPetStoreApi())); + return openApiRepository; + } + + @Bean(name="ExtPetApi") + public ExtPetApi extPetApi(@Qualifier("extpetstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new ExtPetApi(endpoint, customizers); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java new file mode 100644 index 0000000000..3676ef192e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -0,0 +1,242 @@ +package org.citrusframework.openapi.generator.rest.extpetstore.spring; + +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; +import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; +import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { + + private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( + ExtPetStore.extPetStoreApi()); + + @Override + public void init() { + + registerOperationParsers(ExtPetApi.class,"generate-vaccination-report", "generateVaccinationReport", "/pet/vaccination/status-report", + ExtPetApi.GenerateVaccinationReportSendActionBuilder.class, + ExtPetApi.GenerateVaccinationReportReceiveActionBuilder.class, + new String[]{ "template", "reqIntVal" }, + new String[]{ "optIntVal", "optBoolVal", "optNumberVal", "optStringVal", "optDateVal", "additionalData", "schema" }); + + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-api-key-authentication", "getPetByIdWithApiKeyAuthentication", "/secure-api-key/pet/{petId}", + ExtPetApi.GetPetByIdWithApiKeyAuthenticationSendActionBuilder.class, + ExtPetApi.GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder.class, + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "apiKeyQuery", "apiKeyHeader", "apiKeyCookie" }); + + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-basic-authentication", "getPetByIdWithBasicAuthentication", "/secure-basic/pet/{petId}", + ExtPetApi.GetPetByIdWithBasicAuthenticationSendActionBuilder.class, + ExtPetApi.GetPetByIdWithBasicAuthenticationReceiveActionBuilder.class, + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "basicAuthUsername", "basicAuthPassword" }); + + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-bearer-authentication", "getPetByIdWithBearerAuthentication", "/secure-bearer/pet/{petId}", + ExtPetApi.GetPetByIdWithBearerAuthenticationSendActionBuilder.class, + ExtPetApi.GetPetByIdWithBearerAuthenticationReceiveActionBuilder.class, + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "basicAuthBearer" }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-cookie", "getPetWithCookie", "/pet/{petId}", + ExtPetApi.GetPetWithCookieSendActionBuilder.class, + ExtPetApi.GetPetWithCookieReceiveActionBuilder.class, + new String[]{ "petId", "sessionId" }, + new String[]{ "optTrxId" }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-deep-object-type-query", "getPetWithDeepObjectTypeQuery", "/pet/query/deep/object", + ExtPetApi.GetPetWithDeepObjectTypeQuerySendActionBuilder.class, + ExtPetApi.GetPetWithDeepObjectTypeQueryReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-exploded-style-cookie", "getPetWithFormExplodedStyleCookie", "/pet/cookie/form/exploded", + ExtPetApi.GetPetWithFormExplodedStyleCookieSendActionBuilder.class, + ExtPetApi.GetPetWithFormExplodedStyleCookieReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-object-style-cookie", "getPetWithFormObjectStyleCookie", "/pet/cookie/form/object", + ExtPetApi.GetPetWithFormObjectStyleCookieSendActionBuilder.class, + ExtPetApi.GetPetWithFormObjectStyleCookieReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-cookie", "getPetWithFormStyleCookie", "/pet/cookie/form", + ExtPetApi.GetPetWithFormStyleCookieSendActionBuilder.class, + ExtPetApi.GetPetWithFormStyleCookieReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-object-query", "getPetWithFormStyleExplodedObjectQuery", "/pet/query/form/exploded/object", + ExtPetApi.GetPetWithFormStyleExplodedObjectQuerySendActionBuilder.class, + ExtPetApi.GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-query", "getPetWithFormStyleExplodedQuery", "/pet/query/form/exploded", + ExtPetApi.GetPetWithFormStyleExplodedQuerySendActionBuilder.class, + ExtPetApi.GetPetWithFormStyleExplodedQueryReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-object-query", "getPetWithFormStyleObjectQuery", "/pet/query/form/object", + ExtPetApi.GetPetWithFormStyleObjectQuerySendActionBuilder.class, + ExtPetApi.GetPetWithFormStyleObjectQueryReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-query", "getPetWithFormStyleQuery", "/pet/query/form", + ExtPetApi.GetPetWithFormStyleQuerySendActionBuilder.class, + ExtPetApi.GetPetWithFormStyleQueryReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array", "getPetWithLabelStyleArray", "/pet/label/{petId}", + ExtPetApi.GetPetWithLabelStyleArraySendActionBuilder.class, + ExtPetApi.GetPetWithLabelStyleArrayReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array-exploded", "getPetWithLabelStyleArrayExploded", "/pet/label/exploded/{petId}", + ExtPetApi.GetPetWithLabelStyleArrayExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithLabelStyleArrayExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object", "getPetWithLabelStyleObject", "/pet/label/object/{petId}", + ExtPetApi.GetPetWithLabelStyleObjectSendActionBuilder.class, + ExtPetApi.GetPetWithLabelStyleObjectReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object-exploded", "getPetWithLabelStyleObjectExploded", "/pet/label/exploded/object/{petId}", + ExtPetApi.GetPetWithLabelStyleObjectExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithLabelStyleObjectExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array", "getPetWithMatrixStyleArray", "/pet/matrix/{petId}", + ExtPetApi.GetPetWithMatrixStyleArraySendActionBuilder.class, + ExtPetApi.GetPetWithMatrixStyleArrayReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array-exploded", "getPetWithMatrixStyleArrayExploded", "/pet/matrix/exploded/{petId}", + ExtPetApi.GetPetWithMatrixStyleArrayExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object", "getPetWithMatrixStyleObject", "/pet/matrix/object/{petId}", + ExtPetApi.GetPetWithMatrixStyleObjectSendActionBuilder.class, + ExtPetApi.GetPetWithMatrixStyleObjectReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object-exploded", "getPetWithMatrixStyleObjectExploded", "/pet/matrix/exploded/object/{petId}", + ExtPetApi.GetPetWithMatrixStyleObjectExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", + ExtPetApi.GetPetWithSimpleStyleArraySendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleArrayReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array-exploded", "getPetWithSimpleStyleArrayExploded", "/pet/simple/exploded/{petId}", + ExtPetApi.GetPetWithSimpleStyleArrayExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-header", "getPetWithSimpleStyleExplodedHeader", "/pet/header/simple/exploded", + ExtPetApi.GetPetWithSimpleStyleExplodedHeaderSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-object-header", "getPetWithSimpleStyleExplodedObjectHeader", "/pet/header/simple/exploded/object", + ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-header", "getPetWithSimpleStyleHeader", "/pet/header/simple", + ExtPetApi.GetPetWithSimpleStyleHeaderSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleHeaderReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object", "getPetWithSimpleStyleObject", "/pet/simple/object/{petId}", + ExtPetApi.GetPetWithSimpleStyleObjectSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleObjectReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-exploded", "getPetWithSimpleStyleObjectExploded", "/pet/simple/exploded/object/{petId}", + ExtPetApi.GetPetWithSimpleStyleObjectExplodedSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-header", "getPetWithSimpleStyleObjectHeader", "/pet/header/simple/object", + ExtPetApi.GetPetWithSimpleStyleObjectHeaderSendActionBuilder.class, + ExtPetApi.GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}", + ExtPetApi.PostVaccinationDocumentSendActionBuilder.class, + ExtPetApi.PostVaccinationDocumentReceiveActionBuilder.class, + new String[]{ "bucket", "filename" }, + new String[]{ }); + + registerOperationParsers(ExtPetApi.class,"post-vaccination-form-data", "postVaccinationFormData", "/pet/vaccination/form", + ExtPetApi.PostVaccinationFormDataSendActionBuilder.class, + ExtPetApi.PostVaccinationFormDataReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "vaccine", "isFirstVaccination", "doseNumber", "vaccinationDate" }); + + registerOperationParsers(ExtPetApi.class,"update-pet-with-array-query-data", "updatePetWithArrayQueryData", "/pet/{petId}", + ExtPetApi.UpdatePetWithArrayQueryDataSendActionBuilder.class, + ExtPetApi.UpdatePetWithArrayQueryDataReceiveActionBuilder.class, + new String[]{ "petId", "_name", "status", "tags", "nicknames", "sampleStringHeader" }, + new String[]{ "sampleIntHeader" }); + + registerOperationParsers(ExtPetApi.class,"update-pet-with-form-url-encoded", "updatePetWithFormUrlEncoded", "/pet/form/{petId}", + ExtPetApi.UpdatePetWithFormUrlEncodedSendActionBuilder.class, + ExtPetApi.UpdatePetWithFormUrlEncodedReceiveActionBuilder.class, + new String[]{ "petId", "_name", "status", "age", "tags" }, + new String[]{ "owners", "nicknames" }); + } + + private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { + + RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "extpetstore.endpoint"); + sendParser.setConstructorParameters(constructorParameters); + sendParser.setNonConstructorParameters(nonConstructorParameters); + registerBeanDefinitionParser("send-"+elementName, sendParser); + + RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, + operationName, apiClass, receiveBeanClass, "extpetstore.endpoint"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java new file mode 100644 index 0000000000..6c18492c1d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java @@ -0,0 +1,11 @@ +package org.citrusframework.openapi.generator.rest.petstore; + +import java.net.URL; + +public class PetStore { + + public static URL petStoreApi() { + return PetStore.class.getResource("petStore_openApi.yaml"); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java new file mode 100644 index 0000000000..dd280d1b47 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -0,0 +1,171 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * Address + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Address { + private String street; + + private String city; + + private String state; + + private String zip; + + public Address() { + } + + public Address street(String street) { + + this.street = street; + return this; + } + + /** + * Get street + * @return street + **/ + @jakarta.annotation.Nullable + + public String getStreet() { + return street; + } + + + public void setStreet(String street) { + this.street = street; + } + + + public Address city(String city) { + + this.city = city; + return this; + } + + /** + * Get city + * @return city + **/ + @jakarta.annotation.Nullable + + public String getCity() { + return city; + } + + + public void setCity(String city) { + this.city = city; + } + + + public Address state(String state) { + + this.state = state; + return this; + } + + /** + * Get state + * @return state + **/ + @jakarta.annotation.Nullable + + public String getState() { + return state; + } + + + public void setState(String state) { + this.state = state; + } + + + public Address zip(String zip) { + + this.zip = zip; + return this; + } + + /** + * Get zip + * @return zip + **/ + @jakarta.annotation.Nullable + + public String getZip() { + return zip; + } + + + public void setZip(String zip) { + this.zip = zip; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Address address = (Address) o; + return Objects.equals(this.street, address.street) && + Objects.equals(this.city, address.city) && + Objects.equals(this.state, address.state) && + Objects.equals(this.zip, address.zip); + } + + @Override + public int hashCode() { + return Objects.hash(street, city, state, zip); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Address {\n"); + sb.append(" street: ").append(toIndentedString(street)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" zip: ").append(toIndentedString(zip)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java similarity index 94% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index e53e2d9247..15ad5a078c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -22,9 +22,9 @@ import io.swagger.annotations.ApiModelProperty; /** - * A category for a pet + * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java new file mode 100644 index 0000000000..6e9a6cb7ca --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -0,0 +1,157 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.petstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.citrusframework.openapi.generator.rest.petstore.model.Address; + +/** + * Customer + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class Customer { + private Long id; + + private String username; + + private List
      address = new ArrayList<>(); + + public Customer() { + } + + public Customer id(Long id) { + + this.id = id; + return this; + } + + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } + + + public void setId(Long id) { + this.id = id; + } + + + public Customer username(String username) { + + this.username = username; + return this; + } + + /** + * Get username + * @return username + **/ + @jakarta.annotation.Nullable + + public String getUsername() { + return username; + } + + + public void setUsername(String username) { + this.username = username; + } + + + public Customer address(List
      address) { + + this.address = address; + return this; + } + + public Customer addAddressItem(Address addressItem) { + if (this.address == null) { + this.address = new ArrayList<>(); + } + this.address.add(addressItem); + return this; + } + + /** + * Get address + * @return address + **/ + @jakarta.annotation.Nullable + + public List
      getAddress() { + return address; + } + + + public void setAddress(List
      address) { + this.address = address; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Customer customer = (Customer) o; + return Objects.equals(this.id, customer.id) && + Objects.equals(this.username, customer.username) && + Objects.equals(this.address, customer.address); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, address); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Customer {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" address: ").append(toIndentedString(address)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java similarity index 71% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index c75502f466..9d60ff92ad 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -22,15 +22,15 @@ import io.swagger.annotations.ApiModelProperty; /** - * Describes the result of uploading an image resource + * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ModelApiResponse { private Integer code; - private String _type; + private String type; - private String message; + private String _message; public ModelApiResponse() { } @@ -57,47 +57,47 @@ public void setCode(Integer code) { } - public ModelApiResponse _type(String _type) { + public ModelApiResponse type(String type) { - this._type = _type; + this.type = type; return this; } /** - * Get _type - * @return _type + * Get type + * @return type **/ @jakarta.annotation.Nullable public String getType() { - return _type; + return type; } - public void setType(String _type) { - this._type = _type; + public void setType(String type) { + this.type = type; } - public ModelApiResponse message(String message) { + public ModelApiResponse _message(String _message) { - this.message = message; + this._message = _message; return this; } /** - * Get message - * @return message + * Get _message + * @return _message **/ @jakarta.annotation.Nullable public String getMessage() { - return message; + return _message; } - public void setMessage(String message) { - this.message = message; + public void setMessage(String _message) { + this._message = _message; } @Override @@ -110,13 +110,13 @@ public boolean equals(Object o) { } ModelApiResponse _apiResponse = (ModelApiResponse) o; return Objects.equals(this.code, _apiResponse.code) && - Objects.equals(this._type, _apiResponse._type) && - Objects.equals(this.message, _apiResponse.message); + Objects.equals(this.type, _apiResponse.type) && + Objects.equals(this._message, _apiResponse._message); } @Override public int hashCode() { - return Objects.hash(code, _type, message); + return Objects.hash(code, type, _message); } @Override @@ -124,8 +124,8 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class ModelApiResponse {\n"); sb.append(" code: ").append(toIndentedString(code)).append("\n"); - sb.append(" _type: ").append(toIndentedString(_type)).append("\n"); - sb.append(" message: ").append(toIndentedString(message)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" _message: ").append(toIndentedString(_message)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java similarity index 96% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index e35a75223b..b97c340cc5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -23,9 +23,9 @@ import java.time.OffsetDateTime; /** - * An order for a pets from the pet store + * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Order { private Long id; @@ -72,7 +72,7 @@ public static StatusEnum fromValue(String value) { private StatusEnum status; - private Boolean complete = false; + private Boolean complete; public Order() { } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java similarity index 96% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index ae8a438c5a..1bd1bebb69 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -27,16 +27,16 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Tag; /** - * A pet for sale in the pet store + * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Pet { private Long id; - private Category category; - private String _name; + private Category category; + private List photoUrls = new ArrayList<>(); private List tags = new ArrayList<>(); @@ -103,47 +103,47 @@ public void setId(Long id) { } - public Pet category(Category category) { + public Pet _name(String _name) { - this.category = category; + this._name = _name; return this; } /** - * Get category - * @return category + * Get _name + * @return _name **/ - @jakarta.annotation.Nullable + @jakarta.annotation.Nonnull - public Category getCategory() { - return category; + public String getName() { + return _name; } - public void setCategory(Category category) { - this.category = category; + public void setName(String _name) { + this._name = _name; } - public Pet _name(String _name) { + public Pet category(Category category) { - this._name = _name; + this.category = category; return this; } /** - * Get _name - * @return _name + * Get category + * @return category **/ - @jakarta.annotation.Nonnull + @jakarta.annotation.Nullable - public String getName() { - return _name; + public Category getCategory() { + return category; } - public void setName(String _name) { - this._name = _name; + public void setCategory(Category category) { + this.category = category; } @@ -238,8 +238,8 @@ public boolean equals(Object o) { } Pet pet = (Pet) o; return Objects.equals(this.id, pet.id) && - Objects.equals(this.category, pet.category) && Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && Objects.equals(this.photoUrls, pet.photoUrls) && Objects.equals(this.tags, pet.tags) && Objects.equals(this.status, pet.status); @@ -247,7 +247,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(id, category, _name, photoUrls, tags, status); + return Objects.hash(id, _name, category, photoUrls, tags, status); } @Override @@ -255,8 +255,8 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class Pet {\n"); sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" category: ").append(toIndentedString(category)).append("\n"); sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); sb.append(" status: ").append(toIndentedString(status)).append("\n"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java similarity index 94% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index aefcc664e3..90947c523b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -22,9 +22,9 @@ import io.swagger.annotations.ApiModelProperty; /** - * A tag for a pet + * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java similarity index 96% rename from test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java rename to test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index 3581497dda..ae722fc9d2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -22,9 +22,9 @@ import io.swagger.annotations.ApiModelProperty; /** - * A User who is purchasing from the pet store + * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class User { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java new file mode 100644 index 0000000000..7f10ddeb85 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -0,0 +1,914 @@ +package org.citrusframework.openapi.generator.rest.petstore.request; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.ParameterStyle; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; + +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; + +@SuppressWarnings("unused") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetApi implements GeneratedApi +{ + + @Value("${" + "petstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "petstore.api-key:#{null}}") + private String defaultApiKey; + + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public PetApi(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public PetApi(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + + URL resource = PetStore.class.getResource("petStore_openApi.yaml"); + if (resource == null) { + throw new IllegalStateException(format("Cannot find resource '%s'. This resource is typically created during API generation and should therefore be present. Check API generation.", "petStore_openApi.yaml")); + } + openApiSpecification = OpenApiSpecification.from(resource); + } + + public static PetApi petApi(Endpoint endpoint) { + return new PetApi(endpoint); + } + + @Override + public String getApiTitle() { + return "Swagger Petstore - OpenAPI 3.0"; + } + + @Override + public String getApiVersion() { + return "1.0.19"; + } + + @Override + public String getApiPrefix() { + return "petStore"; + } + + @Override + public Map getApiInfoExtensions() { + return emptyMap(); + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + + /** + * Builder with type safe required parameters. + */ + public AddPetSendActionBuilder sendAddPet() { + return new AddPetSendActionBuilder(this, openApiSpecification); + } + + public AddPetReceiveActionBuilder receiveAddPet(@NotNull HttpStatus statusCode) { + return new AddPetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public AddPetReceiveActionBuilder receiveAddPet(@NotNull String statusCode) { + return new AddPetReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public DeletePetSendActionBuilder sendDeletePet(Long petId) { + return new DeletePetSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public DeletePetSendActionBuilder sendDeletePet$(String petIdExpression ) { + return new DeletePetSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull HttpStatus statusCode) { + return new DeletePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull String statusCode) { + return new DeletePetReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public FindPetsByStatusSendActionBuilder sendFindPetsByStatus() { + return new FindPetsByStatusSendActionBuilder(this, openApiSpecification); + } + + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull HttpStatus statusCode) { + return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull String statusCode) { + return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public FindPetsByTagsSendActionBuilder sendFindPetsByTags() { + return new FindPetsByTagsSendActionBuilder(this, openApiSpecification); + } + + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull HttpStatus statusCode) { + return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull String statusCode) { + return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetPetByIdSendActionBuilder sendGetPetById(Long petId) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(this, openApiSpecification, petId); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetPetByIdSendActionBuilder sendGetPetById$(String petIdExpression ) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(openApiSpecification, this, petIdExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKey(defaultApiKey); + return builder; + } + + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull HttpStatus statusCode) { + return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull String statusCode) { + return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UpdatePetSendActionBuilder sendUpdatePet() { + return new UpdatePetSendActionBuilder(this, openApiSpecification); + } + + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull HttpStatus statusCode) { + return new UpdatePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull String statusCode) { + return new UpdatePetReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm(Long petId) { + return new UpdatePetWithFormSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm$(String petIdExpression ) { + return new UpdatePetWithFormSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull HttpStatus statusCode) { + return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull String statusCode) { + return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UploadFileSendActionBuilder sendUploadFile(Long petId) { + return new UploadFileSendActionBuilder(this, openApiSpecification, petId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public UploadFileSendActionBuilder sendUploadFile$(String petIdExpression ) { + return new UploadFileSendActionBuilder(openApiSpecification, this, petIdExpression); + } + + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull HttpStatus statusCode) { + return new UploadFileReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull String statusCode) { + return new UploadFileReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + public static class AddPetSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet"; + + private static final String OPERATION_NAME = "addPet"; + + /** + * Constructor with type safe required parameters. + */ + public AddPetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public AddPetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class AddPetReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet"; + + private static final String OPERATION_NAME = "addPet"; + + public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class DeletePetSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "deletePet"; + + /** + * Constructor with type safe required parameters. + */ + public DeletePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, Long petId) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public DeletePetSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public DeletePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public DeletePetSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public DeletePetSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public DeletePetSendActionBuilder apiKey(String apiKey) { + headerParameter("api_key", apiKey, ParameterStyle.SIMPLE, false, false); + return this; + } + + public void setApiKey(String apiKey) { + headerParameter("api_key", apiKey, ParameterStyle.SIMPLE, false, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class DeletePetReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "deletePet"; + + public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class FindPetsByStatusSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/findByStatus"; + + private static final String OPERATION_NAME = "findPetsByStatus"; + + /** + * Constructor with type safe required parameters. + */ + public FindPetsByStatusSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetsByStatusSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetsByStatusSendActionBuilder status(String status) { + queryParameter("status", status, ParameterStyle.FORM, true, false); + return this; + } + + public void setStatus(String status) { + queryParameter("status", status, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class FindPetsByStatusReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/findByStatus"; + + private static final String OPERATION_NAME = "findPetsByStatus"; + + public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class FindPetsByTagsSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/findByTags"; + + private static final String OPERATION_NAME = "findPetsByTags"; + + /** + * Constructor with type safe required parameters. + */ + public FindPetsByTagsSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetsByTagsSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public FindPetsByTagsSendActionBuilder tags(String...tags) { + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + return this; + } + + public void setTags(String...tags) { + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class FindPetsByTagsReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/findByTags"; + + private static final String OPERATION_NAME = "findPetsByTags"; + + public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetPetByIdSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetById"; + + @Value("${" + "petstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "petstore.api-key:#{null}}") + private String defaultApiKey; + + private String apiKey; + + /** + * Constructor with type safe required parameters. + */ + public GetPetByIdSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, Long petId) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetByIdSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public GetPetByIdSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetByIdSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public void setBase64EncodeApiKey(boolean encode) { + this.base64EncodeApiKey = encode; + } + + public GetPetByIdSendActionBuilder apiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + @Override + public SendMessageAction doBuild() { + headerParameter("api_key", getOrDefault(apiKey, defaultApiKey, base64EncodeApiKey)); + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetPetByIdReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "getPetById"; + + public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UpdatePetSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/pet"; + + private static final String OPERATION_NAME = "updatePet"; + + /** + * Constructor with type safe required parameters. + */ + public UpdatePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public UpdatePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UpdatePetReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/pet"; + + private static final String OPERATION_NAME = "updatePet"; + + public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UpdatePetWithFormSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithForm"; + + /** + * Constructor with type safe required parameters. + */ + public UpdatePetWithFormSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, Long petId) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdatePetWithFormSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public UpdatePetWithFormSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithFormSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdatePetWithFormSendActionBuilder _name(String _name) { + queryParameter("name", _name, ParameterStyle.FORM, true, false); + return this; + } + + public void set_name(String _name) { + queryParameter("name", _name, ParameterStyle.FORM, true, false); + } + + public UpdatePetWithFormSendActionBuilder status(String status) { + queryParameter("status", status, ParameterStyle.FORM, true, false); + return this; + } + + public void setStatus(String status) { + queryParameter("status", status, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UpdatePetWithFormReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}"; + + private static final String OPERATION_NAME = "updatePetWithForm"; + + public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UploadFileSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}/uploadImage"; + + private static final String OPERATION_NAME = "uploadFile"; + + /** + * Constructor with type safe required parameters. + */ + public UploadFileSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, Long petId) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UploadFileSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UploadFileSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public UploadFileSendActionBuilder petId(Long petId) { + pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UploadFileSendActionBuilder petId(String petIdExpression) { + pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UploadFileSendActionBuilder additionalMetadata(String additionalMetadata) { + queryParameter("additionalMetadata", additionalMetadata, ParameterStyle.FORM, true, false); + return this; + } + + public void setAdditionalMetadata(String additionalMetadata) { + queryParameter("additionalMetadata", additionalMetadata, ParameterStyle.FORM, true, false); + } + + public UploadFileSendActionBuilder body(Resource body) { + return this; + } + + public void setBody(Resource body) { + } + + public UploadFileSendActionBuilder body(String bodyExpression) { + return this; + } + + public void setBody(String bodyExpression) { + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UploadFileReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/pet/{petId}/uploadImage"; + + private static final String OPERATION_NAME = "uploadFile"; + + public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java new file mode 100644 index 0000000000..449c9b4189 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -0,0 +1,497 @@ +package org.citrusframework.openapi.generator.rest.petstore.request; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.ParameterStyle; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; + +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; + +@SuppressWarnings("unused") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class StoreApi implements GeneratedApi +{ + + @Value("${" + "petstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "petstore.api-key:#{null}}") + private String defaultApiKey; + + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public StoreApi(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public StoreApi(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + + URL resource = PetStore.class.getResource("petStore_openApi.yaml"); + if (resource == null) { + throw new IllegalStateException(format("Cannot find resource '%s'. This resource is typically created during API generation and should therefore be present. Check API generation.", "petStore_openApi.yaml")); + } + openApiSpecification = OpenApiSpecification.from(resource); + } + + public static StoreApi storeApi(Endpoint endpoint) { + return new StoreApi(endpoint); + } + + @Override + public String getApiTitle() { + return "Swagger Petstore - OpenAPI 3.0"; + } + + @Override + public String getApiVersion() { + return "1.0.19"; + } + + @Override + public String getApiPrefix() { + return "petStore"; + } + + @Override + public Map getApiInfoExtensions() { + return emptyMap(); + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + + /** + * Builder with type safe required parameters. + */ + public DeleteOrderSendActionBuilder sendDeleteOrder(Long orderId) { + return new DeleteOrderSendActionBuilder(this, openApiSpecification, orderId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public DeleteOrderSendActionBuilder sendDeleteOrder$(String orderIdExpression ) { + return new DeleteOrderSendActionBuilder(openApiSpecification, this, orderIdExpression); + } + + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull HttpStatus statusCode) { + return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull String statusCode) { + return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetInventorySendActionBuilder sendGetInventory() { + GetInventorySendActionBuilder builder = new GetInventorySendActionBuilder(this, openApiSpecification); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; + } + + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull HttpStatus statusCode) { + return new GetInventoryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull String statusCode) { + return new GetInventoryReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetOrderByIdSendActionBuilder sendGetOrderById(Long orderId) { + return new GetOrderByIdSendActionBuilder(this, openApiSpecification, orderId); + } + + /** + * Builder with required parameters as string to allow for dynamic content. + */ + public GetOrderByIdSendActionBuilder sendGetOrderById$(String orderIdExpression ) { + return new GetOrderByIdSendActionBuilder(openApiSpecification, this, orderIdExpression); + } + + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull HttpStatus statusCode) { + return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull String statusCode) { + return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public PlaceOrderSendActionBuilder sendPlaceOrder() { + return new PlaceOrderSendActionBuilder(this, openApiSpecification); + } + + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull HttpStatus statusCode) { + return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull String statusCode) { + return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + public static class DeleteOrderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/store/order/{orderId}"; + + private static final String OPERATION_NAME = "deleteOrder"; + + /** + * Constructor with type safe required parameters. + */ + public DeleteOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, Long orderId) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public DeleteOrderSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public DeleteOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String orderIdExpression) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public DeleteOrderSendActionBuilder orderId(Long orderId) { + pathParameter("orderId", orderId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public DeleteOrderSendActionBuilder orderId(String orderIdExpression) { + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class DeleteOrderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/store/order/{orderId}"; + + private static final String OPERATION_NAME = "deleteOrder"; + + public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetInventorySendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/store/inventory"; + + private static final String OPERATION_NAME = "getInventory"; + + @Value("${" + "petstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "petstore.api-key:#{null}}") + private String defaultApiKey; + + private String apiKey; + + /** + * Constructor with type safe required parameters. + */ + public GetInventorySendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public GetInventorySendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public void setBase64EncodeApiKey(boolean encode) { + this.base64EncodeApiKey = encode; + } + + public GetInventorySendActionBuilder apiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + @Override + public SendMessageAction doBuild() { + headerParameter("api_key", getOrDefault(apiKey, defaultApiKey, base64EncodeApiKey)); + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetInventoryReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/store/inventory"; + + private static final String OPERATION_NAME = "getInventory"; + + public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetOrderByIdSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/store/order/{orderId}"; + + private static final String OPERATION_NAME = "getOrderById"; + + /** + * Constructor with type safe required parameters. + */ + public GetOrderByIdSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, Long orderId) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderId, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetOrderByIdSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetOrderByIdSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String orderIdExpression) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + } + + public GetOrderByIdSendActionBuilder orderId(Long orderId) { + pathParameter("orderId", orderId, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetOrderByIdSendActionBuilder orderId(String orderIdExpression) { + pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetOrderByIdReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/store/order/{orderId}"; + + private static final String OPERATION_NAME = "getOrderById"; + + public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class PlaceOrderSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/store/order"; + + private static final String OPERATION_NAME = "placeOrder"; + + /** + * Constructor with type safe required parameters. + */ + public PlaceOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public PlaceOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public PlaceOrderSendActionBuilder order(Order order) { + return this; + } + + public void setOrder(Order order) { + } + + public PlaceOrderSendActionBuilder order(String orderExpression) { + return this; + } + + public void setOrder(String orderExpression) { + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class PlaceOrderReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/store/order"; + + private static final String OPERATION_NAME = "placeOrder"; + + public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(storeApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java new file mode 100644 index 0000000000..2814877653 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -0,0 +1,714 @@ +package org.citrusframework.openapi.generator.rest.petstore.request; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + +import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.ParameterStyle; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; + +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; + +@SuppressWarnings("unused") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class UserApi implements GeneratedApi +{ + + @Value("${" + "petstore.base64-encode-api-key:#{false}}") + private boolean base64EncodeApiKey; + + @Value("${" + "petstore.api-key:#{null}}") + private String defaultApiKey; + + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public UserApi(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public UserApi(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + + URL resource = PetStore.class.getResource("petStore_openApi.yaml"); + if (resource == null) { + throw new IllegalStateException(format("Cannot find resource '%s'. This resource is typically created during API generation and should therefore be present. Check API generation.", "petStore_openApi.yaml")); + } + openApiSpecification = OpenApiSpecification.from(resource); + } + + public static UserApi userApi(Endpoint endpoint) { + return new UserApi(endpoint); + } + + @Override + public String getApiTitle() { + return "Swagger Petstore - OpenAPI 3.0"; + } + + @Override + public String getApiVersion() { + return "1.0.19"; + } + + @Override + public String getApiPrefix() { + return "petStore"; + } + + @Override + public Map getApiInfoExtensions() { + return emptyMap(); + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + + /** + * Builder with type safe required parameters. + */ + public CreateUserSendActionBuilder sendCreateUser() { + return new CreateUserSendActionBuilder(this, openApiSpecification); + } + + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull HttpStatus statusCode) { + return new CreateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull String statusCode) { + return new CreateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public CreateUsersWithListInputSendActionBuilder sendCreateUsersWithListInput() { + return new CreateUsersWithListInputSendActionBuilder(this, openApiSpecification); + } + + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull HttpStatus statusCode) { + return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull String statusCode) { + return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public DeleteUserSendActionBuilder sendDeleteUser(String username) { + return new DeleteUserSendActionBuilder(this, openApiSpecification, username); + } + + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull HttpStatus statusCode) { + return new DeleteUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull String statusCode) { + return new DeleteUserReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public GetUserByNameSendActionBuilder sendGetUserByName(String username) { + return new GetUserByNameSendActionBuilder(this, openApiSpecification, username); + } + + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull HttpStatus statusCode) { + return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull String statusCode) { + return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public LoginUserSendActionBuilder sendLoginUser() { + return new LoginUserSendActionBuilder(this, openApiSpecification); + } + + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull HttpStatus statusCode) { + return new LoginUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull String statusCode) { + return new LoginUserReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public LogoutUserSendActionBuilder sendLogoutUser() { + return new LogoutUserSendActionBuilder(this, openApiSpecification); + } + + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull HttpStatus statusCode) { + return new LogoutUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull String statusCode) { + return new LogoutUserReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + /** + * Builder with type safe required parameters. + */ + public UpdateUserSendActionBuilder sendUpdateUser(String username) { + return new UpdateUserSendActionBuilder(this, openApiSpecification, username); + } + + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull HttpStatus statusCode) { + return new UpdateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); + } + + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull String statusCode) { + return new UpdateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + } + + public static class CreateUserSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/user"; + + private static final String OPERATION_NAME = "createUser"; + + /** + * Constructor with type safe required parameters. + */ + public CreateUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public CreateUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public CreateUserSendActionBuilder user(User user) { + return this; + } + + public void setUser(User user) { + } + + public CreateUserSendActionBuilder user(String userExpression) { + return this; + } + + public void setUser(String userExpression) { + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class CreateUserReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/user"; + + private static final String OPERATION_NAME = "createUser"; + + public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class CreateUsersWithListInputSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/user/createWithList"; + + private static final String OPERATION_NAME = "createUsersWithListInput"; + + /** + * Constructor with type safe required parameters. + */ + public CreateUsersWithListInputSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public CreateUsersWithListInputSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public CreateUsersWithListInputSendActionBuilder user(User...user) { + return this; + } + + public void setUser(User...user) { + } + + public CreateUsersWithListInputSendActionBuilder user(String...userExpression) { + return this; + } + + public void setUser(String...userExpression) { + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class CreateUsersWithListInputReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "POST"; + + private static final String ENDPOINT = "/api/v3/user/createWithList"; + + private static final String OPERATION_NAME = "createUsersWithListInput"; + + public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class DeleteUserSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "deleteUser"; + + /** + * Constructor with type safe required parameters. + */ + public DeleteUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String username) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public DeleteUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String usernameExpression) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", usernameExpression, ParameterStyle.SIMPLE, false, false); + } + + public DeleteUserSendActionBuilder username(String username) { + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class DeleteUserReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "DELETE"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "deleteUser"; + + public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetUserByNameSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "getUserByName"; + + /** + * Constructor with type safe required parameters. + */ + public GetUserByNameSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String username) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetUserByNameSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String usernameExpression) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", usernameExpression, ParameterStyle.SIMPLE, false, false); + } + + public GetUserByNameSendActionBuilder username(String username) { + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + return this; + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetUserByNameReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "getUserByName"; + + public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class LoginUserSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/login"; + + private static final String OPERATION_NAME = "loginUser"; + + /** + * Constructor with type safe required parameters. + */ + public LoginUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public LoginUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + public LoginUserSendActionBuilder username(String username) { + queryParameter("username", username, ParameterStyle.FORM, true, false); + return this; + } + + public void setUsername(String username) { + queryParameter("username", username, ParameterStyle.FORM, true, false); + } + + public LoginUserSendActionBuilder password(String password) { + queryParameter("password", password, ParameterStyle.FORM, true, false); + return this; + } + + public void setPassword(String password) { + queryParameter("password", password, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class LoginUserReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/login"; + + private static final String OPERATION_NAME = "loginUser"; + + public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class LogoutUserSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/logout"; + + private static final String OPERATION_NAME = "logoutUser"; + + /** + * Constructor with type safe required parameters. + */ + public LogoutUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + } + + public LogoutUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class LogoutUserReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/user/logout"; + + private static final String OPERATION_NAME = "logoutUser"; + + public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class UpdateUserSendActionBuilder extends + RestApiSendMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "updateUser"; + + /** + * Constructor with type safe required parameters. + */ + public UpdateUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String username) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public UpdateUserSendActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String usernameExpression) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("username", usernameExpression, ParameterStyle.SIMPLE, false, false); + } + + public UpdateUserSendActionBuilder username(String username) { + pathParameter("username", username, ParameterStyle.SIMPLE, false, false); + return this; + } + + public UpdateUserSendActionBuilder user(User user) { + return this; + } + + public void setUser(User user) { + } + + public UpdateUserSendActionBuilder user(String userExpression) { + return this; + } + + public void setUser(String userExpression) { + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class UpdateUserReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder { + + private static final String METHOD = "PUT"; + + private static final String ENDPOINT = "/api/v3/user/{username}"; + + private static final String OPERATION_NAME = "updateUser"; + + public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, OpenApiClientResponseMessageBuilder messageBuilder) { + super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java new file mode 100644 index 0000000000..7dcb02ad39 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -0,0 +1,45 @@ +package org.citrusframework.openapi.generator.rest.petstore.spring; + +import java.util.List; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; +import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; + + +@Configuration +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetStoreBeanConfiguration { + + @Bean + public OpenApiRepository petStoreOpenApiRepository() { + var openApiRepository = new OpenApiRepository(); + openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( + PetStore.petStoreApi())); + return openApiRepository; + } + + @Bean(name="PetApi") + public PetApi petApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new PetApi(endpoint, customizers); + } + + @Bean(name="StoreApi") + public StoreApi storeApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new StoreApi(endpoint, customizers); + } + + @Bean(name="UserApi") + public UserApi userApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new UserApi(endpoint, customizers); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java new file mode 100644 index 0000000000..db8d84d5bc --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -0,0 +1,160 @@ +package org.citrusframework.openapi.generator.rest.petstore.spring; + +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; +import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; +import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; +import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { + + private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( + PetStore.petStoreApi()); + + @Override + public void init() { + + registerOperationParsers(PetApi.class,"add-pet", "addPet", "/pet", + PetApi.AddPetSendActionBuilder.class, + PetApi.AddPetReceiveActionBuilder.class, + new String[]{ }, + new String[]{ }); + + registerOperationParsers(PetApi.class,"delete-pet", "deletePet", "/pet/{petId}", + PetApi.DeletePetSendActionBuilder.class, + PetApi.DeletePetReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ "apiKey" }); + + registerOperationParsers(PetApi.class,"find-pets-by-status", "findPetsByStatus", "/pet/findByStatus", + PetApi.FindPetsByStatusSendActionBuilder.class, + PetApi.FindPetsByStatusReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "status" }); + + registerOperationParsers(PetApi.class,"find-pets-by-tags", "findPetsByTags", "/pet/findByTags", + PetApi.FindPetsByTagsSendActionBuilder.class, + PetApi.FindPetsByTagsReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "tags" }); + + registerOperationParsers(PetApi.class,"get-pet-by-id", "getPetById", "/pet/{petId}", + PetApi.GetPetByIdSendActionBuilder.class, + PetApi.GetPetByIdReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ "apiKey" }); + + registerOperationParsers(PetApi.class,"update-pet", "updatePet", "/pet", + PetApi.UpdatePetSendActionBuilder.class, + PetApi.UpdatePetReceiveActionBuilder.class, + new String[]{ }, + new String[]{ }); + + registerOperationParsers(PetApi.class,"update-pet-with-form", "updatePetWithForm", "/pet/{petId}", + PetApi.UpdatePetWithFormSendActionBuilder.class, + PetApi.UpdatePetWithFormReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ "_name", "status" }); + + registerOperationParsers(PetApi.class,"upload-file", "uploadFile", "/pet/{petId}/uploadImage", + PetApi.UploadFileSendActionBuilder.class, + PetApi.UploadFileReceiveActionBuilder.class, + new String[]{ "petId" }, + new String[]{ "additionalMetadata", "ERROR_UNKNOWN" }); + + registerOperationParsers(StoreApi.class,"delete-order", "deleteOrder", "/store/order/{orderId}", + StoreApi.DeleteOrderSendActionBuilder.class, + StoreApi.DeleteOrderReceiveActionBuilder.class, + new String[]{ "orderId" }, + new String[]{ }); + + registerOperationParsers(StoreApi.class,"get-inventory", "getInventory", "/store/inventory", + StoreApi.GetInventorySendActionBuilder.class, + StoreApi.GetInventoryReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "apiKey" }); + + registerOperationParsers(StoreApi.class,"get-order-by-id", "getOrderById", "/store/order/{orderId}", + StoreApi.GetOrderByIdSendActionBuilder.class, + StoreApi.GetOrderByIdReceiveActionBuilder.class, + new String[]{ "orderId" }, + new String[]{ }); + + registerOperationParsers(StoreApi.class,"place-order", "placeOrder", "/store/order", + StoreApi.PlaceOrderSendActionBuilder.class, + StoreApi.PlaceOrderReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "ERROR_UNKNOWN" }); + + registerOperationParsers(UserApi.class,"create-user", "createUser", "/user", + UserApi.CreateUserSendActionBuilder.class, + UserApi.CreateUserReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "ERROR_UNKNOWN" }); + + registerOperationParsers(UserApi.class,"create-users-with-list-input", "createUsersWithListInput", "/user/createWithList", + UserApi.CreateUsersWithListInputSendActionBuilder.class, + UserApi.CreateUsersWithListInputReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "user" }); + + registerOperationParsers(UserApi.class,"delete-user", "deleteUser", "/user/{username}", + UserApi.DeleteUserSendActionBuilder.class, + UserApi.DeleteUserReceiveActionBuilder.class, + new String[]{ "username" }, + new String[]{ }); + + registerOperationParsers(UserApi.class,"get-user-by-name", "getUserByName", "/user/{username}", + UserApi.GetUserByNameSendActionBuilder.class, + UserApi.GetUserByNameReceiveActionBuilder.class, + new String[]{ "username" }, + new String[]{ }); + + registerOperationParsers(UserApi.class,"login-user", "loginUser", "/user/login", + UserApi.LoginUserSendActionBuilder.class, + UserApi.LoginUserReceiveActionBuilder.class, + new String[]{ }, + new String[]{ "username", "password" }); + + registerOperationParsers(UserApi.class,"logout-user", "logoutUser", "/user/logout", + UserApi.LogoutUserSendActionBuilder.class, + UserApi.LogoutUserReceiveActionBuilder.class, + new String[]{ }, + new String[]{ }); + + registerOperationParsers(UserApi.class,"update-user", "updateUser", "/user/{username}", + UserApi.UpdateUserSendActionBuilder.class, + UserApi.UpdateUserReceiveActionBuilder.class, + new String[]{ "username" }, + new String[]{ "ERROR_UNKNOWN" }); + } + + private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { + + RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "petstore.endpoint"); + sendParser.setConstructorParameters(constructorParameters); + sendParser.setNonConstructorParameters(nonConstructorParameters); + registerBeanDefinitionParser("send-"+elementName, sendParser); + + RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, + operationName, apiClass, receiveBeanClass, "petstore.endpoint"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java new file mode 100644 index 0000000000..9fa4b1a025 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -0,0 +1,209 @@ +package org.citrusframework.openapi.generator.soap.bookservice.request; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; + +@SuppressWarnings("unused") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.419751700+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class BookServiceSoapApi implements GeneratedApi +{ + + private final Endpoint endpoint; + + private final List customizers; + + public BookServiceSoapApi(Endpoint endpoint) { + this(endpoint, emptyList()); + } + + public BookServiceSoapApi(Endpoint endpoint, List customizers) { + this.endpoint = endpoint; + this.customizers = customizers; + } + + public static BookServiceSoapApi bookServiceSoapApi(Endpoint endpoint) { + return new BookServiceSoapApi(endpoint); + } + + @Override + public String getApiTitle() { + return "Generated api from wsdl"; + } + + @Override + public String getApiVersion() { + return "1.0.0"; + } + + @Override + public String getApiPrefix() { + return "BookService"; + } + + @Override + public Map getApiInfoExtensions() { + return emptyMap(); + } + + @Override + public Endpoint getEndpoint() { + return endpoint; + } + + @Override + public List getCustomizers() { + return customizers; + } + + public AddBookSendActionBuilder sendAddBook() { + return new AddBookSendActionBuilder(this); + } + + public AddBookReceiveActionBuilder receiveAddBook() { + return new AddBookReceiveActionBuilder(this); + } + + public GetAllBooksSendActionBuilder sendGetAllBooks() { + return new GetAllBooksSendActionBuilder(this); + } + + public GetAllBooksReceiveActionBuilder receiveGetAllBooks() { + return new GetAllBooksReceiveActionBuilder(this); + } + + public GetBookSendActionBuilder sendGetBook() { + return new GetBookSendActionBuilder(this); + } + + public GetBookReceiveActionBuilder receiveGetBook() { + return new GetBookReceiveActionBuilder(this); + } + + public static class AddBookSendActionBuilder extends SoapApiSendMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/AddBook"; + + public AddBookSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public SendSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class AddBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/AddBook"; + + public AddBookReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public ReceiveSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetAllBooksSendActionBuilder extends SoapApiSendMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetAllBooks"; + + public GetAllBooksSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public SendSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetAllBooksReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetAllBooks"; + + public GetAllBooksReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public ReceiveSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } + + public static class GetBookSendActionBuilder extends SoapApiSendMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetBook"; + + public GetBookSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public SendSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + } + + public static class GetBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + + private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetBook"; + + public GetBookReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { + super(bookServiceSoapApi, SOAP_ACTION); + } + + @Override + public ReceiveSoapMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + } + + return super.doBuild(); + } + + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml deleted file mode 100644 index 1784d89782..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/defaultOas3SchemaValidationTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml deleted file mode 100644 index 60f8dc25d0..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnReasonPhraseTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml deleted file mode 100644 index ca47b78103..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnStatusTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml deleted file mode 100644 index 5047fc38a0..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/failOnVersionTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml deleted file mode 100644 index c6f1afc8b5..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/getPetByIdRequestTest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml deleted file mode 100644 index 7f4b46ed43..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonDeactivatedSchemaValidationTest.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml deleted file mode 100644 index efb6b3e5a8..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml deleted file mode 100644 index 2ead5c459b..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathExtractionTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml deleted file mode 100644 index 4d4bff102f..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationFailureTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml deleted file mode 100644 index 320e32fcd9..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonPathValidationTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml deleted file mode 100644 index 3aeb456f25..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationFailureTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml deleted file mode 100644 index 50f146bc18..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/jsonSchemaValidationTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml deleted file mode 100644 index 4e24ad3e06..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithFileAttributesTest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml deleted file mode 100644 index a727b3bd06..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithMultipleDatatypesTest.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - Test - true - 1 - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml deleted file mode 100644 index a3082ee857..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/multipartWithPlainTextTest.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - ]]> - - - {"data1":"value1"} - - - {"schema":"mySchema"} - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/findPetsByStatus_response.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/findPetsByStatus_response.json new file mode 100644 index 0000000000..4e3176fe31 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/findPetsByStatus_response.json @@ -0,0 +1,38 @@ +[ + { + "id": 1, + "name": "hasso", + "category": { + "id": 2, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": 3, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" + }, + { + "id": 4, + "name": "fluffy", + "category": { + "id": 5, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": 6, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" + } +] \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json new file mode 100644 index 0000000000..53fb68a708 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json @@ -0,0 +1,18 @@ +{ + "id": ${petId}, + "name": "citrus:randomEnumValue('hasso','cutie','fluffy')", + "category": { + "id": ${petId}, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json new file mode 100644 index 0000000000..38b4703838 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json @@ -0,0 +1,18 @@ +{ + "id": ${petId}, + "name": "@matches('hasso|cutie|fluffy')@", + "category": { + "id": ${petId}, + "name": "@matches('dog|cat|fish')@" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "@matches('available|pending|sold')@" +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json new file mode 100644 index 0000000000..c1657e0b6f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json @@ -0,0 +1,14 @@ +{ + "category": { + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" +} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/pet.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/pet.json new file mode 100644 index 0000000000..0d4e504a8f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/pet.json @@ -0,0 +1,16 @@ +{ + "id": ${petId}, + "name": "citrus:randomEnumValue('hasso','cutie','fluffy')", + "category": { + "id": ${petId}, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ "http://localhost:8080/photos/${petId}" ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json new file mode 100644 index 0000000000..9414dcaab0 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json @@ -0,0 +1 @@ +{"description": "this ain't no ped"} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json new file mode 100644 index 0000000000..c1bc78ed04 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json @@ -0,0 +1 @@ +{"lastVaccinationDate": "2024-04-02","vaccinationCount": 5} \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf new file mode 100644 index 0000000000000000000000000000000000000000..fe879fe28c4057e6b081ef4d6ad0951036b44639 GIT binary patch literal 93378 zcmaI6V{~O*(>B_%(XrD>I=1aj(y?vZ=8o;&v2EM7ZQHiKzVGLK&-a}3|e!C2oKmX8nC@ju_(($Br21QeH^zTB@!^?wq<=!bj{r5Kf1rhpx_ z%MSI0rIIkBmK3l@!fQ|}tMF8+ux?mY324Nqs8cyB&ug%-E^CNh4cBnRANgue^5xL1 z_@ebstr9u2!lec3>HPkdE z<+oB1YeR!Q6=vKg5N&&OUvcZSWzLtpK`>h|-f|MT5UMpYSL-{?EErF}q-H`r1HmES zzKbGiMkDCYK#=9}3$(O(jPq*I&6x+avSPy79Mquwdra0VfH3AlI&@Z|4@s zwX6|_g=A;Tb0?DA8l#l4F(Q>}v{_sh*!+_&h}!D`a37;lmMb1^9+76NR<*LR92_lM z=!IP0eRkcSh%;9bY}SvWyIkG1RQ?VEcR=z?ZSQpH585PG8F%CZjhNFOvV zH8~u-q4zXJRkhc(rfLO~TxZX>o3uC6B#ax`nbEp2G4~3*EfN-eGrzN1hk|C+*SdIQO)i{ zdddm9ldqyWPC2L|!;ohO?>=3*xvJ+2{@35cm43Z=YUS-1HSym33V25zZC@Geq#k2Z z*MP z$J-=cuuFT{vxJ`u!rTc5h0k$HA48@q?43@?&3fHup(~~tEcloBHV5{XT>7_Hke)B> znx&coAp+_wiq z%E%i&M2M8#tSkA+{=?DNcbgyH;2Sh_CJDu*MqEb*T933NSaLv+AQFaNnAJ!Pa^NsA zGWMlER(WiNfI%}DN-VLYU@#4sWuJ95B(4$X5Sw0%6&zx)rruBuF9$KVFKR6b2ks{* zxt*YjFLf<*Gf|uGtR1RW5B>@QPi(^UupQVs=i@h7BXkx~8*u4Z-kvc#d>moLeX?oz z6}WbUrEJRQAM9ZKMz+`NS`dVCByawZD@dTRADk+}u{*G4Kd?Bz3B`gDp>aa@!Y2`7 z^~MQjb2?D``VnG}he(S65OOpNS_dVLBgt;qL8%X98?N{P$%$eRmlsPfWEm=K17;nU zmxJ#BU(c@Pt9I;*2X!-SokQZleQZ=5^f-;(0``-5NEmZJdiW>@^(PUz0IY-QadT%dQf(Man$mVbfUXdVSALlWM#(pN=lfP7-Z7ibt za0d}?3(`K;q!8pju_X~<3;j^aG!iG=EAFHK8yfMEz;_2aG?F91upO5DzHj?Ja^dTQ zqp@&$**j=xy+8Jeqa$)aTfl>VAPIb;OXy=cU=JNI;JN>ZWJnJbWI$;F6(vCu{e%b> zAib4~4(Z|8-(etd2bW?<_l>*8xur-B<-yTm#|vSU3(|u56Fbyvv~Pc1xMPYHS&2Qe47<%>Q1N3U>4EE&Eob}Nu`SW%DeR%zex8e?482ltRf zHUMIHPCsV{Dj6gq*0i^6xK5Ap*2-j!->`tVhc#Qsyx>NT%d_YI0#P&=9m2_V!9I+$UEt|*yiYss$KUrf>nTRTvMOxux=mG zKK^xwKK*%M-*DSD^sNm?csrC2!?|C_HOVbI-c>+W>{H)V@P^$tnID9Ky0KkBe}=bu zs)Ducpk;^vNJVi-ec1aXc8k@h(Y?0A{M}c>L)%FEgmJFjvT_mc%vu6`lQ%HUM$b4t ze*AH=z36=|&k1{qcIYoGTEcu_OL0@Z()(MnO+B2=LGRq_qMreKcXmtH=<^O3499gS|4C#5x7le{AK`AZTvWON4qwpb%{p_7A&K zgy}P{7vv9nL?ZydcfeJx3_%NXh8kH7|eeB_~FKf z3^TFfIZ~wdr^Qp;ac&IUCBu}x=;0~;J;~cv?2;4)`XABZj8*(B19zYozrMYOZ|sE! zKRk~M`M3@&;PhbJ)s5awdgp`(1@%vY`TK~#b^8yD6tDr$R8R5mlII!u105WHttL6! z*t4;-174ou(|^+6I+1+)PjB@ zDWl*yjwQ|46&UkD_-~n8d%a)&2#;pSNm$Loz%l@zAQj zt6iHMBjTSn{69GSf%V(vpXkU3k`nQ_(NkL4(Nlug{YCbv_lk7HHR)e)p)=WsDZi9K zTatddxw}DX>ce0NInL#&2=TP4#e0hXh1C@5@7xbJomkC?<$rTkp>6;$QtHE1sLDt1C zD{xH+`Er5{>VE{GiA$XgE_;V*ihn9FlnWTJljX84Z8n}ywP@E!R*MDQQ_XJTrl9|)xIPw2L1sK=-2 zkZp6>PT0t_46LlKrheptw=1<@dx|su%M4^>9^HQn1^a*Ej`izL-RQ28xm_GEB|FgsSrwHj^sCpp(t(Oa(*~Uv91$|S?sPF%>X*)&G zM=$X&qk0q%zSSShm5)#*;$0uO(N98_U#v_}J{?$ddwRyUpHHDW#J3O6A-qVF{#)Jt zM+moFqa6~}V1JuKkZCo#%a5j{6ar`G{=5jd-M`%fuX{4=U&L?iTx$EEHLF7a zV7H!k|1vSFpX_fDUEkS5XuPvn)*?w(>b>TOli>ACrfj4;MAX&Q!Kr*9oRwq4@h*|`-47c0UuE#g#>O+_JgRg%h_fIk zhKd#l2F&Am!h-*Xv_IDGC4zLsti}BP`uoW*^OO0uNtE0|M%hl`9krd=9N*4r+;kl0tzD(5~c9 z7h*a3B~=R3H2=gBP;%&L(T_*R^iQ$|g1o*tm)}!>I*La<1w$Ic_W~Suw5*Gg=>}%B!Drgtgwv4Ldzn=+$;g^tNcf z!ucv$u9xK5lAM8BVk<5}aaUFT-siuTNt}?=7G%-W5@K*BMw^S~Bt@fIsmp-M;w7~L z_YOisXD&|S6&M<#Ww~{sX)49us3oOYI^4^Q(%{Av` zS#+mS@b|?Aa<<9DT}cXt%RD9eDBFh4d@VDkXhP(niz(Paa))QR^;~Yk>KAn_779^l zuO@C0wMy!%Iwf495!j`EH<1&PGn_-@kKGjIu)5gp5{+$!90uI7*l9)Oy$osWVCsLj zEU(@->h3Gp=L|VaN{q=S-!ooQ-%NrgakdPdnQSw#>cT=Y6&RFj5MLzN)RZ4m6`G(2 ztYc3nnGivt&^oA8f*SPoYd%)1wRd&5tk=z~vId-G=5aL&Y@D`y25X8kl-NHv%JR8p zoL$fH&k4QaJ*V?W%Oicthd=7Am<``3%QlA(Q@O${aiUd?t-7!t2lzts2wQjOcohuq zlxm)+`h)XAZoID5U0pNs*x&S&m1(GR+29J;!y{py_Dzohd((v6bDiZW*KzahynR_k z%?)Rzmxq>tk;(Neu7+KPDj6w9mR|e`wc)fg=SD8= z1Ed3I``RA08>mI&b2w2V`J=p2J9Ls|V}G8TjplgzzQ^okW|%6^-ch7M)5Z&752YsI z)WgDNuta7QQiv}pr9-8xCm%o`i7{bR>Y2j+ImAxOvQj{f7M=6eztF){q`}y|oSe*I zx5&+=hjhwo%g5=HI4)CzkpJ9VcEz?DJ#0l=tF#(DZUw#$F)J;rBHoMum4{s6LQ@17-YF^T^6&^H>y^}YZ_6l^0}yl#8zretxCz0M*WQ#}y z##YL~=1#0uiRK`~qn=J{3^7VU6N*@OW976^bVPb|ychXBb)s?TAT&Sv@J3(nR!e7KcR_Hu)Dn zU!V!2NW8}L>v`}tT8mAVL5&$y#wHShN`Df2(F)c37Z)Bs$KRJFX31z zlC+W689B>+E{pO{ciYdxnS$3msBs|Icw^T)>9FNcCDc7tN}4|dDK8`XKBJgKbMUcq zutqD%Sr!U4M5NCZ@I|DhF5|+fwbB|Cz8&-f=apGR#7yhO%WMKqN-Ptav3Cv3*%G6S zz$Dnd-Jm5lhqE2sQZI^vL>?-*Yk^}k+E4R(q~9}DaZyzOWbXMf3|BV37c-Z?^A3N%4^g1 z?+nQS#Gj2C6bLcv0u4Q}fffi6#f$O=uZIY$Z>!3kPYbv_ zws!0q;d9Iqac0IdTqi!JNGEA!k#@4bWsOyI)-9U-D2=f4=bP>oS|zP5E>g0 zYZJg%!$GZRSsFnbX!mU4d>U;kM3hXghcKm`vv+$iP)eeUH&9B2f&9)VvLiteDo2(T zue#ZRm>OE4UDpFaYnacylDzaC_9u^|o9=_#i_KvPs;J_IegRJ!R3W2L@sg?TnlEmW zJW482N+_!A)CFlq_yq;83Z(Mhzfek~jPxndV8+Kq;A7}P!!cm6px9whN1RNencIWx z@XR0%h+P;QQPw0b1{Qg6Yr6bz!^|*t&}TSuP3T?06IRy_k9*yTTE??Hl`>S@i~a<%n~~D<`C%PT*cy5H~vtj z=uv{uibo5)GE0oIg_r)n{RVr~`N+^Y$>6S`RkAsu!}qOUvIe^qj>@pqH2{?2N(^Ll z^lD)#`<97hK}4@Q@=swop88RC#IFn<8YlGzh_bBye6|}d$93%#^2d435{7CpFd{7E zlGSZ>ARzOji|E;LMV6R|o5wAi%|~d&ZgDucDGmTO&CaT|cN^fd(Xoz|IClZxAcgWq z`BV6UpBo`9O^1i=8aq80OzWOX@s=kUCSnH}-qQ*s$xdUaS1~{$Czldo;NuBP$&$+d zw(==NQNpc_FN@b$1V#WUX$LRex9`~puCJ?G`WeLs@T;d4(iyn(t|;HMji?2n*rIb1 zfRIyo#vtqci3PH!|Lv8&FD2O6?!Yd~BR4W@yV7@R#}EtFP%4a2C~<@xJ+WJK+*E|M zuQPTgN?_1;hj@6Kr##@r4rOjD_{-BMCjy|AtKO+2+>nj){&djZ@dK5{Kx|qYYysAp z4}Yz{?`h_m+M*WZp7Rx4XS?HS7ssMRMTvYA`wl8t?Z-;d`x`PwL*&Bt<59B{*XC39ppoeA+8TLr_a^Ih3RMmdy$WZpLNl#j#tEbnLO0!x^dr^2-+N38idP=m_#~gN7#ob!pkc3w3yE3Jnz<+(7BeI<*b}7OXM>u}tFJ~>YJ3UD z5O}8N75nGVE0#qEU$jPuY1)%LIZ?NE45&~pFv?oU>Xu$J2Xwvo$i`r>$1K0H$K z+ZaVXD#z;ma-CoeY&Mq#mXoweF1ot5*E$NAOIaG%YhZ+?CP8aXWJrmbnnqo3et0O8 zC`4|Z8kaIu)S5}+Nwyq7I@z+pu&5C)6mAfH&m=tzAljxg>G$f zHoB}>+x_hkNrKA9^<#f8+UL`+a^nHlESvU2foheSq!-lsiY^_9iTwb_nyrot7-}1O zc6<=t6FYFKK2U!Z?QdnyCPbd89r6Gsd?<4BgRBvOO9LfQiO@&o^aWrh%z|@xe|$S0 zl!6up3&jSgX9GOAp2ajmLU0!>{X8n>$oU0rD*&2T0uQr&^TusRTakg3G|uE13{Wu;TBq8gYHbuzvn@7+Km{V&LpbeyAnjhS zYf8dk6E1yR=)vxaxkJe>GpM};VCq6mTfez~3&5JAtX5+lJ6n_p89fz;)b-D^Br$0Q zsrS!;c=>qB_#l)BClMSDth!&L<$dxSo4&xxMY)bSqKyq+HBvcu7Q{pk56BXpaerYU z&;%x*>Xh!qK{|#Xft;oM{bL)fdn7z0YZWi=0c=H{ik9~wOA}Es64WV=H?<>5%=}YG zaP)5ACwpDt&ebK*Vfcd<&G?NTOiQQL6snq*Tv8umACir zf(0ws!esP0KUMFQy3^_(qq7wkn~@4TA0M^;DA5&TV=oJPC{bKfW>bF8nlioiZTvB@ zIlAs6$lbunOg*taIcnmPn!utU00R!R@}JePme$ndURB%+{2b&|q!t#MsL_txw@uZ; zVO<*lwq8HgNVF?{1J5`pgQs{2Ab4i-;U0vNlu zwkY5%!|bFWg1{k{S5~3-%OP&1#z(}@<1_H9zQV(|X)jUN8pUE7FFZCbCk%(i-0BCs zIV;R^(SSh}1;6_LT$|*J=QBj-?i1hHOTaZiSoOLCN8Yu+1?PX4DD- zR{dP;?9kQb_JEP8IoORmAkMSvxY>xs7P89PV>J;4^`ildh?9Dh7D20nd-Dv}ZB;Rw zyv>ce;#2&rq;k5r`6}?D{8oqZX+p^jNN$tdETVU|mW@OFvV5 zp;^s5i>Yy3CRqB3?uLo->4kf> zeHZkZxdn%$?rw-b-m7SkI2L;_2JAiqvou{&$_&$@j+#cQI!vI6iGPZ@2@1>5CkJXj zXike!dc2tNwS*fBQUx<251z-#r*orRaC9BXU=ZX$?~3o@FUmh9{$K&T#(s@dDF~}5 zuL|o%AEl&{#TcfOk+9Gh?h3pm!bd)*Ia}^BTdr{t;+XRo1aF)uZ4}>)BP`!I^6(G2 zK+_`2D!3bhEQ!;)2yGczv$|l#5}koT-x}}Hu4&kq*WEe*GIH(5mnGJ@Z7v72GVn2> zSIfB~pl@D89ZB*xs@unA7{*2M;1Xt|z46~~%H6I>Mbsn4yXvp2(m*`Ht_fFfoFt4> zzfoD?aDQSirMO#KhZsVuYeZ zVrbsb{L*DI_^P_}2`b?JIIhQ3HFWO_i$upmj0%H6h=^Xq&9zuY7|Vmw&$?~{!WBOoI`sV+A2&qJWxudhgP5ghv>CKW!g|5O#jX@JV*ws zhD0B{G@1So$`#H8EH9E*$wQ%E{Cn7A=7@aw1s^jk`AZfkEg=}rEIU6;PE1PLTND?1 zWW`2?j;iutVWQsG_EwURrRRB< z6@*uw4JH7k9NeXn$Q}m9o~Y6Vl)7%vyK8%6pwRvLvNGCAiWTzQ<4YsOySeLotpKG= z069wA&0EL|*gKddSpGTUjOam+k56IPiMEYL6MM%}K^iY|;V0R~_~mEy5!k`f!jM-H zBCLX}>4|7IncQ6H!-+5$au&D+i=Pw9m}|x|w1<`VW*haqAP7hlg|u93@N25{{FA{8 zWSS?}nV|`B31dD#9#%1DG>8R;M{7+1f^aSy_%qa&bx0?+g)?#mi}7q)&Jp`#O`hQC z5B_`K9=RsA8PMb5i<1d^eDz_t{_hk4iSh=c<630fHz4~we2T*8BI+1pqC1`HgP3rg z+4USd&q|1w6C_}qa}qCgSIf$N7Sf8PVQttp4}n0!g1*ydCgsM`cLsJRNe&fZaODk`+eIm?p|(v_ zg%8BkCC1msUy~V4P*%uF`9q64la+fuokK>0hF5)myG-ZTjm5Zf!S-DSz1tzph7W@1 zMW`%>H#XQ8tb9zT)IjNc>ANIt5@x2==jNI@49W9?y|*Dm0W9tIuA^&pzwQk>l?Vt7o8L1x5ROTV!EnI&OD&U1f z8*zUfIa{c%4&WyEp)hb#_#xNJs~jHkWTGtdgZiuKjf8cpt3}|Ha*TG?`8uFJ!>Pcs z!MG`c!$Dv|z}o~rm%Fiqn~sE;qs4G*CO9bIAfYuASAT?-#f>m>x(XjByizLFexh2S z&|e?><%xAuAU%MM_W2sndff3TE1-!~8A3s8y8IkyNMU~9Kkmxc&{x@0eBYWb^ADT~ zOr)cGloNi4sJ-6aquZF9S&T*qOL(;KT+O6+)<5UPv!J-3A~M$Pi{f;dUI|fjhV#_Z z`*C?_OrWf}K0N>$am?G%)W^ z&b?_dZP|c}iC0dq14Kib4S^O0cB~P=l|tJXeQUO?MfAeM70zWOg=_=&?cN~=U%F!Z zVo+sSc&tHB_Tf!SbY+Dz{3WscS*SpcHa}<)G$&)2LpSi@t{~?)-K9BfR{|R;y}Z~* zsd_x4NwZ5a%kaozk^$c4&#EG-F`deB5zh%C9SBNNChfft&^)GNP-c@evUOzAAf30J zmcw&@8>V8(ADlc=tpukcwUjGow?s)AZ-vr`XyOV~v#PKt@_R1(ttAt1zII3E?{kWgN4}eAB<-(kAz92&&u;KCv6j2XsMrJ?WEA=E zy3O~bjARsD;;=b<-Ty3H?|O?xyb*4Fea%V;ph(4?T10Na09X1fQYeW^?(M-d zCMrm%PaWJdLQrnjpeYnND-qI@OJQMeY<3jeNER_Kd3B^`Z@TUui)wi)q1Q~H8^v4p zS!JP;2*g`(7^x4X7>i*fMR!Nu;t3^Asdb{-79!oJ=<@jTMV4&~2snX_= zgk%G$H6{DdO2g{R%&b0`a$v@&OGQDAC8uBS8EL%zk<=u?E90h8pCac##;EWz*mv7< zpIfw$!6=*+82M#mr3TY9og7+4?|Zr)d+j~$P3y&V;aqy55&-rB< zMteWCI@pUIqDc!eA3Bkj8MNv0OQT5Ktt{EQ7l~j4EJwKTE`l~S-&rQn4T#}#N}Ix> zz1fo~0*eiGkbsR8;n#~-`iHd?WvN|!{6EjsmZ$Q<6riDk_{N5lq0(>aFjEMU>_r3P zt*gb<7tu@Dpui$nxC$sJJ+RjxPm{Szgwu2IpjUiq4Smna+l znKlk+eCML{NulyIO3vGy1#kewf_Wj?*{(Jb^v%&tWdm_gB`uWe?I$-+a z6R-pBa~urEmV6^EWA0!$@tEqFdX&2sd|CJ+4fi1FWF1Np&9VF6!=*9z3QQmZXF>w|4@RS3@r^=dK|8chWut9Ajl1UElT~ZgKu( zK_T9frf)?i=yq=Hi=`aka&~bJM(lT`z4O>55bnHVEbBqNwvO1&2h9BMHD$TYe%f>V z-xua$(-P>z_K&KvC0MTHU0QWsHwtN=`G62cozR;_0(mliBpml=d!O&rMPi8~F}3bL z?R}^tlRTtYUfj2L7(?$QTO4Yod>Zi#eK^ZxV-CppPv;ETj+%D%UuO4B4`%FrG$WgG zaQ_BnW;L6JpY)YKGIhxQ7(|k$E0Xq}ytRjNq{?!vD-!VOyz}bXH8S;BRYSP3{7yyx zhw!fKoC8482vBAue8@Ysyv_4b3QONgqBdKobwK>RVhRGi)#BWxr<+?CoT4$2-y`6OI;BOTx08&vZJ+%ejfZJk}&Q zq<)vh0~60qe(rL^3ePGR!Bw_eSiEY3Xf9e3K76)9`NPl%q$<#`VarshFXC{dDSBbzq2pbiZyJnq-J{?}-4vP~AN}~&eW(4?@oW?mPnivFv_)gSRwVVopgrf3 zW6Hzcvpj8a*@u3M1`8ILm1Lwf<$olybUt_`FUjRF7m9S0i zYr>)`m|meA9LLO*)y&U4>MHTrOhHUr2>C^$Fq((wnV%%8(uiKjXpkBbx$_QF+R;;174nI>a>}piVCoD)iabMYY>A}TnRTSS$PXoU zi`tfls&1pVtEfxz3Q6a@+Z#*NHOH_A=A!bR&EDm$LHStg(lN7;2&s?DzJ`|hdXxDJ znA_%=Ov}@wR(mTvRno$bh?-ynnuTUjw1pTn+I7t|!g^EsZ2D8y{DW1U@eh8oRgX7) ztpdngn@GoBo?8+_lV*F#H>H1WZoDHt_uo`a&o2rQoPYxrOb|~iDIsgmfwux9QErbd zt?Mz3Hhf5GOYj(DzrDwv6y2BM5FBF#A9Bn<&lsk`| z5bJJZmesvD1(#zZ@zxq8kc&^o!kPx>!T`mXB>TGjY@Og%ckeH?*CP$<=3ZRQ6}y5K zfYjF9FNmU{UeoiT)&<{<74#IAKN|x6G|?+uS0@F8hr?FYE^(K-&YI4-tr$UltQOIIrzarJt@@jI4cR; z-UlUD8+?n9msSVM^qR<@`{3|J_H1;BK&@ni0mDylnh0+;428ej>6&^YI#U!?7xKu9 z(5sq4uXEHHtU2_)@-A9ah^PnBZN_ZNz;VIHEktTQryUvIgZ=#Q%&*AP->RU&N{Tu z$xzdP6J|N}L&}=<(C}ey0@(ZbomyAS=}BWDbxx35Ce`ybV({q~FrBuGwy;*V&YjDl z!)$yd*fZ0bWNkHC>sY5Ok{5lVA$WnRECB1?wO4h`V}sP*3P@TaX#R9o$(`gwpH$;r zA&oa-UdfEf^eD=LDY5e!F8#pxV2rX94P|*T8P%^wr)pU_F!Dh1Ga9!;^yEyms3v+6 z;V0wb(4)1m`l)EcEsSHonuNB8s-i4^Ii|{41!qRJ1L@Mzdvp9s%geR5I4EY{r1l~e zPkJUO7$u`dkYmj6h&`IAyuFo=BVo$%UnXF8=yfnHsp-E*!qA4p?g2Z$EZT{F7R{>O zDOsHJIxvxvEB-UgK~->aW^4kuD&`P5bK+5{ICDO)GURBp>_k~B4UmfJ+JqKC5q2N7 z4$NQ(Cg&2@9)R}LlANa6gw8g+As9vcT0`-Z`kx_=PJ5X?9G&>4Wso@y?oJ+k7(BTq znYdNxRS@*4n7wd&A~zbhyY4$N6r`CIL9^NDUP?HYI}&oQVnA8(ou7F^)Sna^=xL7| zkvCmC3_r6wywE7d^`k#XpqK+detuuQ1+`9bkaICt_pz6kjIrZy2w^H}E^hy=nY=Me z!pYsl(Prtn#Wnz;PEbKCQD1kPc!Y z)g9m(0yhu`%og?4=&g(}10Yina#cmFoIqjDk zE2e^j_8FP5=uDh=oj;Q6{<}diwdmq^BbQ9qfqTKqiqC)u7+l(`-FMCbFv%;pBcxXP z4BSlwlJMIIDQu~az*!#gci)f!z-idv;#+S&U^ZQuzjP?z461kT(ao=9s3wpczD{fr zJKtxJ%klIS-edONTd815iKJ||iyadrruZ@rV~Iix}=jQBP8=lX8A@YFGqb#Z!#L#?+?7W%}~pIZx@!vW6c{Py&XlBsbV`L81D z!w%Xb)KhtOw38Nb!fCl@U-G1}=o(LV;jGS#!Hq{$XKc4Dx`0p7yPc;4L{E>f)hl}5^?Sf+IKPV~Vc$p(=YEiera@H)|m zgiK{)Ffa_p=PN>J_)5T!-Y&r)ig@vO=r1VQ`N467-a?uRDRTGlw@!jiCFN(E_fFhm zs)dBoIM4_a)K%$bqQdcGk%Ur%$WvKGplB`z91Rm$eO@g#f%J_auYleOZMK_|F@^LE zhH+_wMHVFEWQ4XDw=nn-m*Z0Fz&fGEGCx?o0X{*?6@6?G57)Yk&g-U+Fp~O}-yZvw znN^$9Su&XWq`Ng-lMS@a(@e5R!Y<>fM5mzkNV<0aG@A6-%GYJk$;AoJ&;{=jPNg}# zW_bw&5cvSFvHQTI|O(HNuSxpOA zV6V(w$C&7_Ci9X~Fkn2uc`$msI~%{NVC~Mww^LvIEo7!qdcVn9n?qo*$fyd?eZO(pPc1+3P;Zd)B&Eo$q7HZA@?z4WB!EcfJLyFg5`i zeN5jAcLK;FDJlq9WIYS1$_&@pEfHC>lo%_Bm%Kky3H&#$$+aRl^lBv69j;0pugDPj z7;JXMse1P&M^g?xXOFBZKlTC$>b5!?NvLvkS4Oh{w1ltLSJ(nzS-2_iuR~n6e_w93q=#`J%a^!KE8=NpzV!Pz~B2$X8}EFyk{*M`?_a zt3eZb19f{V^&8FZPxO++S0(^LmlW|YFXMqIiU6)S>BO7Wvb9davgkz?Wp;gTF$&eq zv-C-`)aFV`MKZ*3I$C-avIA2L%kz0QE0sDRb^c28wGUbh2;I8 z))33(wOu8-TC@fbNs2%}v9cY%k#VJ2G@ABCW_3JD8!sRG@$WZ&K`G1-H*u96jS!tr zpNswpHfbf!0HZ8jWQqiukLDv++(L_sDT_%P>-UqPrBtsqo7KQDkF)KjS{}svC+nM> zn2Y;DC}Gn~7`D*P6{6}o&FSJ-qi0Ev*BQbxkPmR0@lNY zYITm`vAJ`!n%5}>TeJ`LnGPn?p0^7%yt%9i{CL<+1{IUm+YM)QB(1|jY44Bf*Ucd8 zt@OI~XAdCUri5D4B$m^I;+kU1kDh0;X=O<p2{YMvhb10~ZmBb9ZSU>3D#oLD3o=MlJ^CPTHU5`q!{WMkOfQ2$TdYCnQ9`~2?dQo}S3CAt= zv%24ad=bwV>lyln-rkz9EiIgd(|-B8EwUC@vyX!*K>NxaXx&0V@v)SIos7+iUD4K` zN>49koE9N%b2hXjzs^C@ZUsx$hwPiTRV0m1MpWHUbCEu4mI~>s0&;XrLo&Rr7tWWI z<|>s&0<}z4tyEpU{Y~O*`H<2+(D|O7Q#&niP@(2*(FsW1S7K#x{&u|Sa|eMv2Vcj_ zJjo`Bf=Qn&JW356$_upm%iC0?ryy&ziPx;NxaM|Iew= z4$%TlB=5+^dFFQ)XS+n|RZ;1gGsSub{*QN42M>I1UOKl_l35khF?4r2jPnKuJ1ORE zOzF=@4v-%hvGdETU*}?nVQ(r!UYS1o)chvfV(zLgm^$X0XWDIL_GdDI#@<>$bRM^n zT&b|DCiyv=&)2$?XSpgO!g^Z|m3I5Mc7wh9L`>VS(+%O%#geq8-JAmQ@-)C^=TqG3 z>T%N`0e+*!GWfuZ%EF&nfM>@YN72~TYf(n(YOkw^-f82M<_TD*_C$TTPQ&d*bsW?d z_Jt#D&YI?BPo`#HM6D=kRT}+EzdWnW(}MGO;0XJx)@oM0`Rx7DqOA-4)A`1X4QAt&Q3!!&DETRE>K)=#VFws^a+g7E^2BVYE^%>LB zSH#P@QNa4n<(;Q>>GkbvU87yu5?U6ed`?EwI}_jGLlq5|&D&*w+1D*Ld$-Tp1&wr8hPh^xo%R9sh(8TJ zq^Eg^=cvftv@RXEG%n(&znp~v1}Z21V6=HsZ=jCStH!7g!&dD_r4$e_Yx5pfc#ys@ zo-!IP#5pg_0JXQbDk{_mQjC{t--WDCV#ni|y4r7roRz#m>bZtl1x`TmTll|f0Hx=B z-sQc|jOj#JRLtH26m6e|3O*7^Vilb&N#tG(Z@)&7$-8W0fJYwVsFT2t_?O3YHfAwA zJmS<=(zci^*|IcENhGxB1>4B?2?x~(Y3rm8SJE%FL$a7{B$EQum^7~4sOJ7kv0t`G z{KsflUZlAbxZ-clu5VwfqvKU4?aZ|3gkDc6k^}eGe~xNh2J7*7l$=HQ3`XW}YyMPS z+DHwtzST;+4!n&$=ejqzH{HIQ&{$xslmjf@q}U_ga|!B9GjTkf?|{_yoBUhmH2~r3 z0pcn2B2~7MjjuWMvINI=lZi{C1qHX2_lK*EMo5nI_WFsZv`jcYYeJirjoYz{ta6Ty z(__Z9Fl__HK2S&&dmLr&hLMRZ?^NnL(<%v1-l}4^lcNL8yk~z>CFUxXgt%K7&fbYK zZtXYYQHmpjweK~OP#Mt{i65Jb_xYWujjcw(jYaQH8BlMp9$qipZ9wukH zo~aXniiB(-I{`V~=?RlOmA91w!X|1r+?b}%)zP!wsg=(oQ*A)g(m2WWN1HwFY~}cC zH*sf%)1+C`$F!5?Lpu_&A+=UO6QNeS+s?-m6POgySbBV zj4RX_=z55bm9;v)`&%FHRgtZ`>u&ocSSx9L#KyYGQM({7tyt3;z;(En78e%o?Lvy` zPecgW<$}`cqmt^X%Mf#p$9QB?haK-D`0}=1i`h8r;VXFD5k>+kP+2pTaTC$&3o^E%m!`GS?XkxJKC+_dsx z6rgBov8_L@i(0mvaW1Z#IX}83#>?^r?C370K*nG(0WaELO^-m;$>SU>7Dt=uv#SE* z4n|LtvqU&uW=t|D=a=I zJ3EuzWOruX9T_gj?aS90!f+kR4zdx|C<0B}k%+ua-rF0?k;8YrY^(9#l2hrQo^)?NHGTfuyumMR$9WGYGcr zPzd-9N(!L2UzeP|a=_$I6e0V8{uUBvTF&?Pt}NwdSM3FBj~a-x`YS;zL5(c!#*5pd zv0)GBWOO0nO6dEY6taRCoiGU1y@^$CD6Husg)pyt~`3kLJ!SE8Cl3urXNztx)m+ zB@SSI`$Os4c2A9-$%Co_sg>Q8U0MKcergLfSX;a!d6HjSszPDKK}RPkmX%Vtc=AHD zxTYMQ40f_Gg+Byh&(a)NA#MqYyO6mlm~Ce)d%3ktR7zaE+Vt{AzrHhE;dR_g+_Rx& zj@Cygj1stzXrowmw{>vWNj@5j$DC>zvs|qXgL8yd&kpw|GOrFLu}!(*YWb<2A3f)e zd3);GTgW%jn~R%?-SRT0pBfSo3oMq}ezd2fu6c8Qb6&hk^O?D6&A8+C0^{VEuDP%F zqxZ3%!m@{Xg>yDj5%*Opo)zb?sicc~?QLuuWQV1pR^j=_kUR>C(l$>1<*Rxtkvhbw zs>bXA7B(<1hzFt59tZW7jc-h&xc? zwm?(um<9U4P|T>J4_C{1^(mDn$Bv_TuL*vt15J)TBqjH(_L?r591flr=q7DB>&fAS zF6v@~9oirmpIlGIVy8DEB@e0FFfS77n_X-9OBR2yV2!lI@6@Y)f%mnVHI+^!gS&v)S>~0LIO}Ou_nS%K zQy!l~nLE?PsAI--{S5P82`84z3eI&N6|2$QWbbriMD9+0Dv*7;E!`UBWl`05jheGA zThjakL^K&$?Q;Hj@bSm^anbaz25t)^v4B9WE<$Sz)XI)z>!in#Z%j@&6&0~+TpC$m z>TH+8nLqb?2#Ct>5Mj`d!IOHcke!~p^ZB}qnoEdicKzVVk;edc<159@8NfPc7nB73 zCcUe6zsAxfa%(g)Z1Y>LM2NujkJJj=v&otmFpG+toz9J3srw^*b|HGcxky>^v!&z` zbgB*)skbr7%4v0~l8LYgyjsx$djRD;?V4}!z|~TP z{IV{nT#lzlGE2~kpTiKX#$8ya$>-j*_Q4rtrt6_E=Bwa{+Z*h)6i&Q8!%ik9XMXu4yLMv(9r zSnamq1B7q+d0ui0a8yQIZ(ZV6Q}Cssff%$4Jd5OhI5gq4rYW5Ut)itZ=lQo9QItePFmV3+9}A!X&V9mE`DWeira za@kQ$;u66Eo|9}ch88F`VgFRYGEed)D`#(oVfmop$PtQ5e+*AlD3PBAVq{8u|XPL2f% z?B_6n{X!eEA9h^A#J($)UEhb?f*T2KGapwrLbdZGhYomLj(>Irf`=X4{ZS;XcZv|4DWR%G|BZUoQ$4LYev37eN6;EZJ62JO-H ztjm>R`MS~hcb%U@PZe8pGQgYkq37nXIY!kN&@>CR9CjacIk)M74S(y@xVSeAX@F(? zsz|J572#OCx*DKGLX@WKEgob~bR&ABV{m%Mfw+if&ep}r@5 zLLl3#Z<=k$57DODwkmOw+r37?4B&JSuJJShmE1H@e2Mm11P+cuaTm40+R}b`<-f%m ztFMOL9v=l17}d3mCWl^l+c5;Y8d+1C09VU43c7ZDjeHTkdKZ%OTP}nv+MH&ko~I24IkpVCE%0BB@Yo|k^C z7tgf_QR4*YbBx#>nhe?7xL|XOeGTlhxUBm9FcBcsIuXG*y?tODIo~|!2D_j7A%Pt_ z6iJLcEWFzVJ_~^))m)tdj{-w8Ds%ZnwF{8TEH3*5Zl}edBAl@O{k!p7dLY~y{%%JQ zma+ZY*X&~Ha4N@b@eCiF$z{FZ&S&`(K75mx5lk~XhK?dq>+7U8t8x=%HtJC!2FpdR zWN_*`z&@?w%X~!4xsg&e!_z9c*1RXHFB?U=N30*E!6+qMiIGI3(F9AOS(lDp=ao{k z!EVxts%W(;U62naK5nnEmkE7pwDH-hov6Ww>QlTuduJ-1e{4oE_f2XKMlJN+KrcN; zbI6@aM4#7y&4%FnY`|$_g`z&|HF~%5mP)s4dy8&3?D3xJ%rTqZtsd}@W;dxduD4uS z4f6W-bkz?Y{fmyxdki=2TJ$}9biCJ!U?o6CU0>^yw)~JZR# zK0RkXtb-P|os0fq!&e=4gznjMJX_xn!%L9`BbeCQ`s$VdpG{@Zju4=m(7I;0_0`Qy zVRoVS`k7&&Y!EEznmJzYc3@-Z2ezLG+@-_}@!O5j7Q2~jR^D&x_|K84@~M7#k=Ul? zy=y~>@F81;dqh33C!k^qz0N#&QGbD;WnE!$KG9F^nyR0%&uk(3cltWVH|}AKR4?=3 z)#%|=(Kzks=332rjbi)pl;QMl_~rbXXLD;J>`G4p5~7B}>?WwXzIRZ+H;X;AdOzej zLtk8WF;ZL6L3Yq$t|GDp*WrL}+1zM@?~Hs6hIGtb#2Y9e8EcFQ85)6-v(F>vR9 zAj`RSL*Zmal8nVncrT?C{=nX$b3TeYB=+dtLA$F@$@{uy4Xp#4$Z3cX!@T`M3znF=hnOfvsP_}~;DIgU3H1{`2uask)<$n2sjrlK#qfMM(E(d9n4^b=8v^#+gS#THSj6e*&oO8R)d1inngVUNE>rriBxqTX-4 z@AO4*>Jjghb|3!ZAoszyA7>whGH5C$m^9yaXj=WNhJXgG^62#Z#hZ%|-Ses1p^L{q z$<2dBk7bmtR=c)D%==u{Q=spjhFz0WehvG?lobo^({>WAB|pm-6c8d6G6Z!cdX4)k z`|}#6)eqIj!C!*)@mBy-=ytd(!Jdo9byJH$F*&{(*Iy0M!2FM15ZXbq3F4l`;{iW?qZ0NmwyB~;)e(mEH z9NBj??eO_x(Ic?kPgxPmJ@MA+xq$eynV#ty-T46932qMIUGjb0z$4t}qH&^ee}6a` z1dFI24!89-^H%>_9M$`4+k-wcxFOsh^SthgTb=UI3WT<2zHMI6m-)cIz;-*qHpuq6 zvAyzhj2We|&y<7e3*KnHXk`{7Z)BZJB9uKqz=LU*F=h;943A*+ecifS|3q+pzY3-z z<>L$p>5vQ4&hmUO{bW1V^tpbx$nZK!z$?-u5!9|=6 zki~P&aNhp%+y3&lAgfPY%fmX~8Nomt_GtFJ6jrK$ji?o$!%@x0Gw8X8)6PYlVpo1O zG|7Wup4OrxH_>Nn1GWx>=NNfDSq^}}?p;;{TJliV_Mr-ZDETc~7iVo^wFZ*FZ- zNH|SyRFQy$%DB3AB!FPL_O@yJtww~ai*;F_EB%s-HJ?Ux80+{!u2&9_vM;K!n(OYS zyvR4P&EK4PAsza@d`d}&nqOx_@bPQeW~4;~#hX=gtz0NQ69bS@r$s44?Hj7qyb{EU z+}B{-dtMph4;YzntW8RdO(3iqbww*=3WlMQY)BC{L3)2ihPqOc!oty1$<8Y|HHCr?-kP z-PM5cX+o4Xnzpt!#iGF?(W3Jr)gr+nq>gh@s*c5Gb?(zwlBSvFqLqyA^cO-Gtrt$n zv@gnEGh#ONwvCY+D}rd}RSx$qNxgnie-HHuG)|9D8j1uDy)}dhMG(mE3 z*7|DHUmk1x%m0_Im{c(H>*cq%3cGP*6Jym1$<_JQAx^PQzn#LJ+Rl`BI7Vzn@OGGY zfFsl+-*&W;A=4AnU0nTK6I?x9s~3M@#IxKQ;a15oj#(UyB3S7n)OPP^oqUUYFKZ(U z?mLBu^hy`#X@wwC??RiWe7J}3XV^=n=5j!BhAN%gAwusiBb6RYeoTR0tw#g35PtYr z_o5XyqbhCe#=ll3?I4AL@5=!K5BI)%xp;#(yPjyQD2!v3vTAvae-GacO(#9RLfz#kdoOO|<9LF5`Fx zIvg8FjYsBI5?bZ>`V*+-i7f^j3%sWi6w@Xm`}|E*-bDx)aC*LeTSHV1&x% z4X_Nm`*{S?Q_JxUB%H}NE+q7lw=J0ss;V4uLp2HnEe1K-P7PA%wbQF&=tE{|dTpYt z0M51zdRWs*^Lbb$XNRV}B5n!vQJ0Ps?9jI=y(trOV&&sTN3JSu7Ba?!jVose`icBn)*h)m#s>NJX%C&dgDLY+<}8g-9i1)yGz_4lg2l-Q68(=f(l zp!M@QCGCd8ciLXsJlZ0QpO1zmQ@GvbEDp{}Smd9!493|ZLk$#`W-@t)V)bbg*Q39* z3OLDq={gdm3pn2in;e|RHm*<_Cx?vO4tA{h%7SB-jQpZOwgaIj4=$hi^Kx&c|QoR5)s_?c30Y|-$ijW?(vKwewhB;u%n&U zc_=p{rs5a>y)zxv25J zewnM~t7=AR<2|CRHmQC}@Zk=yb9Z;a1xJaFDXJCxHFMexfW*}%6;1)N09GDmWzY~y zrqPPpmOnG6RRBoskxO(%acxV}jH6r`w9k^MZx-PDwDYA5x?{;?S5|v(R0jPGfGk=u z(ar)^l&$#kXB;idpgdMg@Y320b*p(5tD8&!1U?N|QM0<~0zi(JtFu2re&Szz+7Cf- z#cZLZWBp^H)R#jNfQlmV0!(@zgplpC?Awdo7z_S|n>oCM=p5lb)~Wp{m^&^OHJD~& zp}umuIU}$rx6fMKRfi?OkLr3beNqq&aXNr(~Yxu4{vMkLCMKnDxN;m0yS=smBqW7gX&mB@VOkUx?Ir{ zoLrGU?{|xtXFKN|@76AlOy2Cls$GZuX^U~uBKZN9I>T`|^Lb=owTuCkhx~qHEgme> zusI$Y)^&*q=l1?$-qjHmqS)#b-kEvg)*ExZU0&p7Lrh%2S~b6{zuFYQZtXmn!e`v} z&P&qJe)A*{jsO@=Y{tLF=iP~jSCEVjT_Q~-@o;tA83?4QNV%Wb>WnjV>n%A`5Y}>$ zL~)t^q+07Z_;VoWN?*jLzlM@JU0y(_QAxLAKdlX>rd#rQ(%4Ml8zRMHd&J#Ey|x~p zfl_iJu$c!s|%qbS4j18U&--^ zsa(zVP>jY%N6fX5oe5`L?X?&e3xgN$CC=(c9<5KqZ%onCm>OIob3QHwnJv{m3tA8;kQ$m~>oW>BR;a+#6Yw^fTL`nNFI#TA+-kC#iPE_uh4NGy z-g8CUv|Mg2#8Y<}g_L4O>*6(kDKoTKZrU+&tDva%g{}3%^nJbiHnV#!!WTPN3mxt@ zD#8>aU>D*FIu*16!Z$1N6upODmOGP>tdV)v(^OkairS0R4u@9q)yfB`lV65m#0^Xh zQ9pWBZ)h?t+$Pd$BYUx0xNVmWUuY9qB{mn8S`IG;WBd520oDC#ljb_W@6QtYidn||!PT~W2t^u*ozkg+mlGnpeV_UEMD zqO;&*y55Rv-F%$Ar_*)8t8_Ahbw^3>&h~Qe&^2QFT8n)?FaAic%!q1^BM<+j9`TuzgZzO2<2rZXWU5X(eZnAkw2yJeR^tEsrQ@k^DI;n%@y$*#_L+Bi*5BbZ+$g0af>KI zex?;gP`!Lc4mC}>B{vn2Rz!RBws}i#-Jy-n7T-t0ivi$VKNImwJ-h)~{QLU8pC9UG zJA-w_?|U3g^>DnLtc%c6?0}+>?~6rF8CygHY>r4NhELssOJk5T#0mm%)oYlhWGcCk zD44f(Ny)=GJe9%=*HF7wm9dH z()&F=VGZ~h3d3{FbnvvuYe<^tn3Z76l=c7Av)!S@H8Ux+={T886Ov0h3vVbXe#>0i_g{(rH_{Nq9d!Sz?WaeYoap4TA_VM*A} zCbdM68G#5`0{wgR0~{t3Asj|n;0)F0I+S{q7(C|Qt{(RW&>?J#eWs6<8#YgXmR0b8 z@%4>7XuM#~NTqzUmx1K_Ob&G_A%QyjGVFydSrULLegShOq=q;2i^q{lqd6NP({`=|KG13WNu%nZss&^QoQL)qo~1ttX1YlyO{ymB8PP{v z$$@Tl(glDWYRz{#%`bS2l&_QCpvZ;>d}Q_J#(?{;SC8M9fRtz$6X*#*m@{vb4RACu zl32gU_SDWT@K*jbozoOYCeji_;&xghd5?cD8j~w^KwvCR({H%EV?ekmG0PQLGn`5g)5Hy>c!pcWi!q)~u{ z+Ch=fIcebb8+pf28a`Hw5!0v7$5cFcMNa`A$O6kc4LN=LO`>C{44-&DY3?_ygEZvk z?e=oMG+ja**j;$tU|nTMbfmS$7#S)|Y##f(Ui~dR5iBIpa`iOY*5D&DDEMuup}3|%?c|_Af zk-OyARP$RHt3NrsWk-&g_`2%1Fgzk1x#M`_;zoY>d3Az?h);yJusojfYZN2T%aT8e z?dvZI&FtR=cJh~9^rLkcxhipOM2TAw{o%rxdWUL>iCi1(4}irTNzXt1B`sA8?UxV+ zpHfhnxqt5a)$AH>m=s6HFXKOQ6eEw#edgSwU~yYh+%bYGYtrYsmWspjLGeZfKlwNE zjsD2Q7bbM7hUcqpt6CZrUeR_du#m0`-~BYV=T1-R3oB<;cC+538IPWUhgek`{>C7p zN0uD?9>;F*7X!(A#`Ac2c}cKFf&;79*R21=RCa>`j1+ogv%&9An1?Y(hs-_rJ?bx3 zhFQ^8K1Npq$K^=V!U7Z5tY&}#j7eAD;bk(KbhxO4KYZ8?v*l{=&_jTEMVh>VB-~Fm z2X@0exfD8Fo1V_Sd5|K_LHw&blTP8(IpdE9@nQ1nf6??Wn&BFz%cao7H>|!s?0t(? zHEz%7@Sdb@-~*bu1lCwMX%7B7#qTyPps3{QwV;1O<&>9Q?uJBM?_NbpBIU)kn}1;a z2ZuI;JX%;|2)9o<1@%(;AaoyDWnM*oL&De!@^4{{B}6^#{H#aRkB;nN_@2d~_umj> z%TyJYXgUlOF?&;)NZn+ZT-3{4Vtx9a+hc0ZG>2 zHT+qf+cRx}?`4O5Gga%I><5QVoKDY%Nxz@9^=xAqIL*)LaB~;(9&20Mif~^sao1D) zn*fDt2sQ-NJi6Y^ZVh*;@pxuK9t0l*HI9yND`!f_QHF8T5c0mfD`8|LkrZ)bIU_r% z#MH1tOG0+p!H4j>)aM`7aPJ))#J1&ukVD$4l}?WCoBjFL{+8OBt7Ldxo;@JFN>w*h zbWrK9+#t12fPhPrcCs)gUH^?(;TeTq8`^n!LaK#l`UATnhl$m<~5H!hPRntjQZgT1xt6g-ZiLyfSNFR@jKX{rVO|M1JU@d z#MTU135Sr+I*>+c--!E57_e!6X-*DjWj}kF!U`x|<7dzUzZMUiUc))2o7F=$Y6pOx zlPo*eA(5Q6>l!zp$>CJ6Q3;sO!fHOEv~<*|9-~G3MF@j2SAGpQ&t3UkF5A=^bpzH- zVJB4=b6IGMX9iy6CtTiFnB?w1BTobvhy~=juxP_5H2s2aW2Q#G0cJi}JG{*zM#GNo z64+epaG2ZvVD0p_j!&AqiU2~BLr?C>1sN`?e^xeE&m}lR;B3%{yNmRwi*5^CR2p$Y z>l3#hddd1W5-CrMC)n|+$~t(GfJ;Z+BhFqQW@3xGK5oJnb2bcIM5<%@9hs{$)Rdp$ zMLeq`E%Z(hX{>B}v6i$x`mRKC@Z#W#*CsSCvd}xgNpOG<@6pzvd1Eaq;h0rDlaa@1 zsan0tCKey<>_gB4rm7~}uT>TG0C3F!{!cfjoZS8R?>>f4I%?VDWnuB~>GLZZjd17YZO%H3RBRjWfUEtlb;*jPb=&2|KGix|U>rCtX<~KHkj?gdV8J`|d z(Jq6K?>ha_*4qP@)`J{+n2y&(-H+dEtUSZc@<&rlDMSjtGwbjfx7X)fBE*E3g? ztdeVxgZeJ6g9_I`-n@)BSh7F5-mZhhc^N7G;_3e&)f(s}FC!AxB65gnry;(*CKajr z^N^37hN-s}5uU#A%}P0UMqF~pkG=+t^`;o7<)`Y{AT95aG=s8G6x--ceW$!$13j7T z>EBQq8oOs7PiTAk?%(|Zbe^Imb~4*UhcTS4iLYx$(5u2`fASZGDw9AsFhouYcY zUrqJ2E4Rxu&(upj7-m}VtyW&6<##<9`q9y#?V^14v4npkeqxai37lBZapt8X!;%RJ zbX?0J<)uTz+Q9+YL7&O>Z0BoQvi~-2wTti_D`MTpBR_7n^Y9(Z zV|m9Tul|FWS9UdiZ2UT%e5xZYuPgLoG%ET^WRLgX3N8fh)U`XQ94`sEACU{XVP`d? z#ViNb7waqph7=!Aqm0URaHt#);R$m5gI8;*UdKa1?%U*oPT2EOujZw21#9Xr#}Z4m zQF1#hk6+G-Cna{DusGO4gDN`Sw|OrI(iR^W#ay;uY59$y3%URDG>Z=jfv)R%xF>s} zrU$v1Zs=;=rW&!rzI?~k!7LWsb*;lT^?Cu5{2ph3M}*w#|LXnE=4*O`PnzwH37)rw z@RTahgIuYItWaS0=^4l!dqyubh|s7fNYnn8@6YW5>u2wj?J&~57pz&1VQ>Pq(Z>FL z#tiq6GmZvAJwPpA7%SdD7`jhiSC)S%EqMd`)Lr$uGWHAO?>FemEr-gATSR+bB>6Rj zmT6dQls0wI-QY%{zOxgGLMLX~sR`8`j_wZCO@Y7|9y*ojWv>g4guLTr)rc?sT+sHX^$ z?wC1a^n*$iS6q0qRO$t{xS6;n!$z*z5JUL1{+1%QVpiTfH zo@{N+i$oIL9!w2dN1j-PRu3k*X=5EM`0I{#mIJ5Vji3?C+Vaj}?Bk{-Va&=;2^u~sZ(E4w zdH`6-?qWJ0@<5Mtxe&=Gkz}OM52b3d{?KI2`4n5Oym=PmhqT?dLD}N#w941g z3IC>%y8Bj*p~(bSmz#b6=2{VtIy(ki0!NoSZMSOrpR;*7p}(>nCZ6j-#YQGO(ASqM z=R9wj8*y6io*NOeyFuCHe%$&W{Ee$CC{Bny-XrFGvX*@Egl)u%&L?kl1#ijOh}506 z&`+k_sUp$*qG&taLs`kGgK@dBVRo>Ho?n zGUVkZ<-b|}7p}#)UsIDmg#P~{@WCHE_-9j|n+2e?GqRFgQ;mFar^_0;_>c;dW}l5W zDW@IKQQW62HnI5S7Ib$NdI2T$Q)d*Z!7R z%J3!qGT)sQO|TfT|hs*2baMV=#^vDRlF?pM>io69^&6k$oq<;Izwj|R9G^AP`#%eTLbe%pszU2sgX zBI;=4%mpMxURg5O7WC{tGTVGS!ow`$>t0?XAD3Q=kbEj+H7TU|@Coz>A0U5N2(|l7 z@=7+L3L_T;U!T@}dvw3aG-rNb)TxRxr(E<8o1*pq%7#CzAW^LXb)2bCOAE^6`6Hm{ zGW#kEs!6h76Y46k3qZFVp2jsSe~a41om09$tW?t9vP>V48e#A>gQ9Dpj$E*WkDXJv z!5kG)-OFI60ObgSDJr7cmy&-mR5Z}AkBX?`SrWtd_1E_+y?E{BC?HLLYvV+S>-&J) ze`;CA?Yykd8J{T|@ZAXwG!{z+--j%qTE_M2MTa-{@35G12=Lu9MN8*-r?Y2n3WK8c z+JmDF#riNC^sBR1 zCH`*=D=RlKVW^xvoU`J*Y$EfDD)*JT=bF8dY)yU|wk6O=p{Wkv+V`X=TjAfQzb-4Yz30$-mJ;JtXT$#Rhd+o`}8k{k~lqqWgXx{(m&QI6DeFS76hZ34yr zaH!Nc`o5_8PI&OkCv$w;6=4g}kB|uzj#A6bBr94~adRTa&iYPCg4 z(h&!L+SNco6zAyUpO*yqs*SO@_!S??Gk{z#+L}Ti)L4_$SWoYB^v7HbF~R~yTF z4bT&XFqnIwFjeG0@oQQFk~GFn|5cuApNs5XAraT`2dZcPng*I*5Ce3jtr#q9K9-gJ zt_7O!5d#3yvJ6jm$)sa&Qr55h!Mc&L367fMNOLL3sfCs>6Qt1eriL*)2};u3{~w&J z@&+U+{>QF%(@Q>RA>TOjOVRD&Qps2A(!TZ2XlshtsE2>8|E(Iq6LO)5gWt7!qYvLWz*D8n zTg2fbn3}lw0HbApN)@e7{k4HpN4?&24%=Gsmucrf2mm)y-Q3hR8Yt3Rz&5 z#o?;<+_dk{>3y+gp{z@OvnZRfpPB!NBgF!HNq=O@lAjm6OIHJs`lV_3nmpkPqg?=3 z!J4!-s11*iImkf{m@%cY@9dlzT|UXzr)yM@b;YMrI$q7c_>y)A?0blCgsxSDcZ`lRA%ytagC^-|NVtfhHn+xHUlU?R z?*;`b8jFTjnhSM^loeFJ$GZ|sr_b&i)t;zlyA|4(Pv8msI=9Q4+U?etzv0}>O{HK3D0mTC&^^boCL zkk7ZqYK`jW0$svIAjMB^Cxe7LYY|SzPZJevka{~{weg~v$poc-Gb~U|p~wG=Q_Y2Z z*SnbPVmd)?{RXU2r8-CMd3HDH``Yy{+j!t)B9ePwlU?EWeRWSfr2lw`=n#K4UuOh6yFW zznQJ23LzvtT8Y;;Bkey>lMcL$FAIESz3A*3MGO^}qic!_d?eKucTy}#bOZIpiAdz9xQn;#ZdU3|NVKCas;B4pZ7#5c+-Q`+49aln zDS@BFa|SkEYOQ=mKHmykAEGW2zv~TBlq#0b9gWs3Kj*TpA4Cdf%@wN*U*Hy0SUmY{ zDWI|o}yWqIz*wbYOxi4~$50FMa&+;Ev8Z+BIVdJ)u9`i}e1xctd+=B*FtW+X)Kmf{=yZgdn$dbS%H8m93gL>AobVXB#y^A(g?RYVC z?FIYctL`0qTI%veghYKbDE*sV5fHi02tnJwrw}`t`MyvfQeR-ThMk)sm_ZN2`*pGZCIY zSerhBO@gs~A`Fx2ot5HxY1{_t{hB1v1`X@?HjEn5{$P_PSkDLhiFe;=O?Fck%gVl% z6VWejijZ}f&%~f?c3`lHj&`e8gOV#pU)NP2m2~924{iVvlvbneYRxOEtUk+nP9lml z_kz0`!P-YbxhV9BX5#kiIXh0P+y{l1iB`{=dOg675`&r%keS!_s;$g_6ge=o@c|N|7l%}B_b+NmOs0ViTTkc z2Tt!8T<~eORvnNs3ZOwoI*Oe@Bc!DqXt1G<+n=De52Y-xV6vUJj+JdXr7VOnNY7tf z;@__AcItaGN+u>qkVKW%t%_BPu0dBGH6Y<4lX;f@a-AOVB#z7j|`)zor zc_QK<23vLMaf`N+w#~$iT4r0qe~h<;4Yq_?sjr?>&q_uuJr<1{(v;(_0srkANa^hD7uHw`Hoii82W9JZw|_F>D<) zThzdIrZw)IEWgP755l>rgJ)Sma=>K_R$RenX8!YQ?AdWS`GfC9aW5ZbvuKC5NBAea z#l|P$B;m^LfS7-lFZ-9Q8J+qDf^{4uKi_ z+Le9V&cXX#{?n0iC*__TOy#(#??Zfq(eB!PqaTq-pFJ*uf4x+z=3u^F7GL*Rl^-%) z7G%{IY90p{?WLDw0JlF;usbFCjK)1mI3->*Pj#3;%FH{SS7t0&P5HpTp*?Q76+Ntq zllL`EfG&{dJhM_pPBB0OgX~Vu(GhsZ%vqHruz?p^jPU2+bDlVnvBCTrM}o4*9+uOS z2yX;JhhosToyY1ozT2D0f!e(Of25l=(@rW(dG6MnHTYI@&>>-yo>o)4M|^NEBU#`X zht&st!F~^NB<#S(bKfj{+HDp6zwa~gG+z(|LaDx#u8}enRUnNUaJjz_9K7Xvk6Mb7 zUdnfE)b@2lheeCJyTp8fNBaZ8VedxX&GjEo!Z)U75g4B*k;j}F)1rHL&Q6BCy*VBS zt>d279eGe(sa0)lwlvDZY56KXRC@8ipVPajvD#b$@u5ZJdfXMS=(a|>wcfLMxp7G} zjAr3ue&1j_CFhNdBwBfAaLBbd1gN;*R!#FR|{`=cd$!WhaI=)!!5IJuI`1Ir2LY%y;gq)!l7$keAjwd zZOMV~B99inYk4f+_`IEE=3G^{PO;f5weY*r3E82y#ds8BosjI0QxsU>47>hmj3_Km zvtg!g5OU<>^E08j=Nlu>H=@ILuk6T;>Ds|hOYT7 zR2ZoaQ^}6&H|jTv-GPr2?-JwgO{LhE@4rZ_j}i?yOR{Ii$pJr1!q%$K{3_mKlFLr6 z2DydgdF!ZmhbF!gF1h6v9ELC2_n0bgYpC9XF&}3UdL3M53j3(>nRvSF0`nH828!C1 zh1Lfa4D&Md^D=v;qi@ype`EJ9fP4N*v+<#+rWY~)(`>!@6f)A1qNq*T7|tTZyE`U1 zXhVd1ri9m22q*U8(E&~o+R6J2xihDh91Iq^F7&~ERuLZk-^qr56PO1d67JhsJz&OcmhF;?uWaT#V3rrDZB(w|a1-5+xTSIL z;^h>66{YxPGyXU-)7<;#D&a+Z_kZ0r_D4?oQ?%(U`|&*{3rZIda*oCs>*M!3zW+8A zOajm72{oySeo04;eULPNOU)_mrwo>Jrm9b&Q@4NkZzmM*qt$K4mVCXzqlNnc?-`d* z)=k>VRm6Kc5EK5r|K@7$svV5hePG+_R`5*V6V5c4;AdA`cA(GN;Ox0ZTLJi#3nB8r z)tWY$E%)Ho9gCpDuF0jCqKFo)m|8U{IP{vsuy3qct)^mo+EdBWMzwa3pl z!cY+_1wUin>SxUJSQPGS$fF{M+KYlZDk)1T=f^N z0JEKspZh*g_L%^@ObITY9Mi}2*O6yOrrD(X*(yhQOW1@yq8{I&EMbypMLXX{^X>=J z%&EQHn0v62{GkRYny=LT%|Y)L-G7`agHXG_*BX$8nl2hAz&bYHVutE1OQOxuXOfSOAuexh68h^0z6pY6 zv-{UqD#N#!2Ng?^0D6)U5OXbJ4f>KZMvrYqkJ^!+b|Y2E)p$-xMkC*bw8DcjmHB(< zGL3#Hu<;j;Jh{m@vpvbvt;krzrG zW{1~KlYj)BlS7V9$8^b?AYyL&dy)iYkX)D48s_*J(}^ZIK(aJ!s-k%N*R0@qT8Q4+ zm{nF|32~6`*_a*q?XVcwW0z<2oJOVPhufd4H=pWHgiuCufm*x5ir{#q#%Oqn@dYPu zgr1r1O=7g{y-Y|G%Vi3jX!P1gx;Tp}V;s&-sFd|ceuk0f9IVXWMVD!qF!I;Vij*4p zd0XUAp!bMMRebu^b9txPMnd0#VbPY5*@3npgz3r%IlkS8QR=N?Vb$ulqwVC%mW+H% zMzwkDt7DV6K#6zI#RTEIo9{Dz$JlsSk69 zYF6U)919TYD=1)|Vir9dtg3l~qCwR)99{8Pr=r~ho#*QQTn1$Bq}B$dWc;%#9(ro7 zuD|YWLtlRPnQ}{G8i4ENK7{AD4b5vJsYD>CGVlrhX7VlHE)`r@U$`tyX&%@{mtLIfAY$TMZh$rS(E zpNu=Xvqp})?&pB74;gZ!^*=?t`m=?$M#)ci+#PpJ9Dy;hr?_lb&1bF84;0J5vWG`x9L;2|em8MeZ9VGnmQgb4DoYgV zr?tI0Qk|ylzJT&S&dKYuOZY7u{#qV*nn2cAd$1vCA_T9uHX+Y$E2{_-akBf+5_kbF zIothq6fZ-(`t8>F>y-uewWfYi{e6NX3*_&E6y5$A=?jmwr=>R87|g80_uQ}$BZhJ< zP4INh`qWbo2DH@&DZ#-j7yZn4;9U)$i<+60f(p|76{WPBxBHL7N=^hrf+(Cx{=MvD zny3qde=Y;uK-X7V+ec_jCI(P}@oqg%5Mjwk`%hfZ+6&IL9surGK=R6tK~#{YG19wZ zBmbZ+#)`4%qnfr5@_5FgB$W;di$w*OY!rc_taX8f@=c}-kx;z!m92?%ow<{x%!`?9 z2ViFJ^dz$bkW31^X|9}B$K|4dh;{)S<(B#YGewJzR)lXwTtj?-7YCmy+^}YswEhoG z?*R?h^Zt*&Q$++3LG&P^F3~$l^d6nn5}hS_Z;29RmFUq{?=8C3CHi9ZW!EmETddwz z`TKr;=YP&K&wcL9GiT13Gxy%P&&<4DClYEw^_x6HMMDd`t2xKIJjq=-Nz>-_RJ3GHi=zG47M}znWW9H5~s9cKCis zf4l^@kA_bRygs>7JTRb;;V>H(%4(QaQ6$(p7Ro*?AyRHL*|%54PWx&Ct{{fb(?$gz zTn8+X)Ay-{$IdcpYZA!?#&J(*GPS=}yoL+rGc`iaJ$T0njvLKZ+l?~(F(t>YSTjSe zbda@c759{J-y5UWW@xf65F9=8cQBCllm41YG}Qlvr~h~9Tt*+p0A_L5{`+Hw-RVz7 zRqu81KKDZI-$MW<{jH`>1263(EJm2C4SE}+!|M0kCllcf`b3-NWE(scu6s-3@kkIb z_q1i&J#BJ(gJ+v?(ri~E@V(4vlfPcrNF>xk%5Q1F73% z-{fDxAtuWb!!qD^zR`!z6wLsn=GYIm=AIgc&-rPC&XAEpn_D$EHi{=aMEQwajKg^0|qJfU?-=1UDjoGz& z)TN#Y{zq)&O<^r+*W1*eto~kS+rUz5l%wW5k@4?pR=Y>QP+>=q>O4t9NeMl>1dz)q zd#;PU_1m4%Y5`c0=^0{_5#kh24SB@6b!^>;LU(7?$}aB6iEj;T_UkTH=an z7AuLk%rQJ8@u6xbxS`##z~hs*mL81ZnXDgQwWCx*u)4iSYkDg|lH8LAcGv$QrN0$N zk1LUNbYw74xX)Nr>yPL~i}{Ny>RXow{{;qjBgg8z1-J`D_|_kts@#{ZV4u}L;BmD` z(;Gp9XQSnhdq9!Pi@)ztxaz9OcMa!^hFuK3f-*T~Ibe__^$ux^KyS~ufqg9O4R7SZxT?F6R zLOVwNV?~ig47R_`yBA=NYFvu(ck0oP0?5Vm@~Ap$OrU0e`mt=Qe-PMd5wli3#mdc7 zc>JwytJieqicR%tY%-T)LA`$g)1&dz1C_a-C>0uQ2ZyQ__i@?PBGP+07UkNV-eQEw zcr!~oc1jzS{pSclPce;Asm0C)yZV%vPC0D9m>UQLq6J+kmPVG>t%T(pHGww$>C>K%Tl-rm{mI)81i;S%71J3VS5QL zCdr!R#lH{#&j)+g1uWg<1)g;?~f>309W8%Z`QxY73wb|Ut_ z?(IGrJdh;t#_B&Y^8XbX1XJB84rebdoGlyIQu3M=aKELm8R`SM9sDwpd`lI7aEG3W zKe#guJS1_L->2EbUk+ngsKZX4wm-P;(Hg6B-4*42Y%q1zY3aehSPDYdS1qME>nNFS^u2Wa z$OHqSz&YBLLEogZi$Q&5FaVk2rF3^3`Ks^x}v-;t$yL{987J!_Z5S<7` zo0QevvCP5JWViL6xqV&7^PgV};-_9>&nBJF8tKo>D99Sx(ilt1PB%nv<;*cf&7IQ6 zFPIEB2!Z-x;gDP*`G(>rs#0H=;jWb@4=r_m@W76F6>lW>^aC$*R&o6^^-pIid&--u zhXsf>H?%6W{Wo0$@DI5U>0!Y(avEBkHBzIO0x{1ZVD$Ru0_!eDn9q=C%LesI2P z7)!j{z^=p!aO~G0^^p|^tfcfdb~k0I!6sQ{tdolL<{>=r>9y5Tm1bV%GmoV2X8hyI zkHv?&|3dh0!S?s7lyWHu8<=}=!F+(inj7dq4)g)^(@kDolsk}kD!q?3c|*{svZ~*f zug}6Y+ntDKV{1Un#(!RJRMg{;zt!hr0dZ1^5Vp+jWUmkdz%?zJY-VA%x?b2ve(qzf zMm&#GRZlIUVLUaoSb4YDF zt8=FrB{Vq9$VovooD+`JH)r^&EJusa5$vYrpI8Yds%cIM2{>;=4{=6(p-wIKw9d~S zD=dc)UdWJ&b7z1$Wu6*SY2C(Y#|sqk4rp1TO%7yM&?fS9m2JP64ut z)`nK;QOTVCoKp$>CIhkP_oLKeTHWN z>D!n|*u1L0`F0w#m!5gGs-)$e%w8GyqGn4;E7CeSO5wJ!9uf0Fd+jmve=zoNdQDx| z_EN>&2ar79M3azi%!kw>B8huGMkk zZP|qW8G-8dkFV!%Jnb0Qq4hJiXwb=RbdQ}?){12zaglqW_{LRk@=?6qCs{C){u1pR=v`yE zHlHP8iZ!SK*%mmR9bc7r1GeGnT$L4h=CDAnxtfq`&dp{2-XZSOn$MsYQhI78J$w|s zt(8PF59BmUL|b28>ly*eejb8O!V9YeRuDR|SXMw0Q-S|-!Y;r@*Y+L>WhEq8?NP*e8(9$3}@e4 zTBw;`oxV)TaI<}I7kd4V{%+lY+T)(*t%^Fdo_CX=`hiI3|80(;-M_xeai@DldUMgG zty7&NK~)fL;g@B04Q9USdNq06E*6)T!FZ~(E>sRRGno2eg8T_%-`Kv*bB{q{>zAKBmkM*7wGuZ#GM~)XvNJ{IV9uD&tvS3ev5U7=b+JT&wcbpbVv919pn!Sr zt&1NW4x=KK7Zgk3fkmgzYr3~ywU^?bP$k28etefA&js9TztN6I*M)eT_`f#%a9{st z97Un!qb(kkFnu#Eml7cSzhbSqGuh+d1?H|+CR*O$BCK-dv2{1-I}MaN`Oa$q80z zddB;q9wpsaBaKnp#PHXKI@+oo1+F`Dj|k{WIyRBC`+r@gtXd4XNtFy=!4c^62)>K( zl6rC%Uac^;pDoV#-#HHi26WYYZqSC>I~F?Cd%RksE`3rB}h zG+l=M{41L4o>AOG&^i+gkqG{Vk+z#t1 z)$YXBl^N+FfxQJuY^C^h!?JmH=-6nbf9l#scywHam^pW(WtB6|;*|4_LQv{Y`4N~? zy?oVdkNj_qgGLP+dX z)I|7`@|#7t_vWI_*fO117E8p+bX!3=m%b@0M%(=&TFkf>LY&Y&`;h(?bBM0dhf^s{ zb-{LK+#h~a&k+KLgp({;;d6p@XNaK;7D*ZskGSWe|_fVTkkZfW1u%w^mMA zb)ADbuE9EUCOUXECMoB)2 zEQpg}&SsfBA#?sc<}Fv{)8KO=@H(kGE5wUvji( zSHsvfCXqecd#e6#pupeYT@it+R-nLN22eAoaJ2=<6*C*g^_)Gx2M0Jrq*Lb1lo z{Chn0>e0ky)9(-d6MA!7=9=xz@vq+e*&6*cp&%EzoS)sI8uOCA&yJ6Qt1aTjgG%Qd z%T){}kdxsv9w8HnO!-IVn&cDGW!(F=mOA!Iqg~Fq=}1JbompFKMdQ*t%}22v2KAbN z*IG0Wu2vfT`)@;Pc#&JHchS)`t4l2ZR~JE_vf%#DbF(bUqdw{{QSx<=O19LY%eqcO zo=~fwhD^JYtop<6sNdc(ch}`bCd68?)anZ-0Q$t|fnJoF!_{>aKKfos9lh>#@jGlm z0O#Zfz2HMH-?sCrc3Bc~}F#Ua6q&hz@K z_cl?uHHM2QQLg$mSB^D8BhJjBu0w?WO>CFfq5nmJqcgcMM@{2Q{Y)C#>4R|Ejy32r z=q`pWR40@ug3Or97|e7uKmiBuHO)2&AL<)R7!!!i%?{1#VZLH*uz-m9OXTHHo71(^ z^_m@Ov?+7#*ZAT1l$+ybd|qnSYJ-^Z(9jskn6XvEk?@9-8(83vn0Dt99oB@YSL$%4<1LK~Fbi4^=t*ZM6*c$h zWIxJ6W$_NxWTCQ$>bft=kAyB71^UvN??3^!0(2lQdmf!E;OyJo1=ibtYTiNYx7!Q5 z3jkQQ(HQrI2vg04nlaXJxyNGc+E=bM(8h;%nGmJc(Qm&0e$m{Ax6#x`cit{0Q4e%| zR*J0Ho}+;U8C2ru+&A9YCZ2v4yO){Qn`55T{4m%dwz;3c7IYDwO3-kn4J!aLOdYnQ z_5p)R)^ZxTXAXIRsrDBJfEn-Enn$;$2u+YZhkY9Gu>*CX_3uAm7+jK!anMHCNz|Szyx)2no7FSQ!I) zP1IGSA{_4EQ@#U9CJ*%i&QlxIm210xqn`k{asH36FF+E6TNuW@u=;MbtuQsIF)M#f z7hr2ArUN5r$f{a10c_Y)7g@)oVjE%*hlGHf=|g*fh}}g@Dy=8&3y;A1RJg-MRw^6> zm4{IsLyQ}*VpCBKSJ|nk#w%Wc`3%0Rc#Q<0(-5EoYi>NYyI=z>P8^y77N-uo8W)Pz z@W5iw#rIT3hxEL)uYrB>9_WfS27t`0HVSHrf(GWK;u|GPt*cXgfk8!UOaM|)dd(Uc zfT&?Q=nEp~3-9C|VoYQFoTgowRNqZiDqAD>gf<>*>K}cb{I&j+3~z5LQ-MY5(0x?h zGHLiA8PmghJ)bE0%)a)5OI^+*}qy;^BLsse98$e^M z7^OYb5Z5J#NVA8U)EMPqxjX|?sui)94yM6!2*#NcAz=TeP%Tip8qsTC2AInGpByA( z6pf2zQH7RC)&JK#3H@!}nlK>g|9YhhacB*=RfSmr%qI?o0)HSpuZaPT^x|F)7pbZC zKnK{fiT345Gu&lLDiUmp3^ql&o3b>}6|KGU3_^&S=Hz0571heE)pv2)Q<1;FG%$}MrVK*?liC61qcvauok>Yd83bLL`2wYJb_K~ ztEw(uYBo$uK5sIB!5gQuo)@!xZZXXUnBa9=PRm^A%J2xDkk;gBYEhNWk#^cVLWGN6|*k_qjH+=u2#7q^pe#@o`OvEH2wogH!VHaG821MWkNp4Y?Ke^MmEgCk0k4ECsk zqSz9JC-~=R+Z7`}!+63+89tLfKiTc^YJ1WkQY%8ybBfw+CW;8G3ygkJJ1}P%K6TT2 z?K#nX^W&N{Kkqu;E8cGP)kce=pm(ptKY6YJjRE6)PbIrZ;|5~;=aae~9!{Q46jCO< zt!6K!Oi?Dv`Dqfp^vsv7HJ;w&*9#r!>)w;S2(){j`rf0xaEo03TK}k5t2fzrV%G}1 z&RNO7Jr{$!@9$F_Eyf^*B!^5|Hik?X`l%zl@ubu{=?Nv%zl|FmhI99LJjZ~U<6>*m z4A3@K=C-DsSZLOCy|WR%Yd*V|S(~Ka;~yd;4c7>%C6ADjdpO@V*Y>2XHudE6#1LE; z`)S~zV?kb1w2Ko(Y@?o_yQjA&m6K_`X}!Dzf~8tf-XGy=Ksb9yg)o;Rbz+ig3_o@w z^&+JVT##Lm{Y`DncHNL|QnS1I*ojTVUV@r3mEtu0RdtnhOjBwt64*a+`L!V^{$~&4 zRD@qE>An9+qO|Cy-V>>^5`T*+DZ)vqGDS^HezX0lpdVhi~L2D845{huzgg89uKTAPK@#+iFn>SwdX{-CK2;^_|J$&SV?4AR5-!T*!ZUDf!gy|IuIyc!N*S-@_wNZFTJNX* zp$rf_e|6}y?`q}h!gtuVg!>sxa#R0=gol{N8s7DAYIdn^iGMqo_=fAm?GW3&)J2eE z6HDQkr+D-8`{{eDpV<}j7ZHzBf{LW3_vBi4zaBH#ICszfSRMO*s&LvrojI3T+X(Go zJ<(tN^Wn7V^bQ3Mg{to?=wLY+I~^P3IRzO_!7-#_?di5ub@;;nM?gn(< z{6{H;lBN|yNXMUOowA?C)DDc-c%FI=`rwl)eUUeU#v*efpMv{uo}I*6wR}H)=zsrY z^mKI4b{Fo}x3L4)3dY<>o&Zh()8?<6i5qTzEC`Qx#@?wL2{+Vxyx0G!-~`lTq|1s7($^Y@ZOkJ=X8g%>WqD+bw3h!j}9fyEN>Vv~I zNajghr@!F8Y+sxPY%A_4mQu|Tl`=LmmIVC?dSPV2`$fHsp7wXzJar(Rqpt5gesMRr zt^1-eQGPsb{mi{E%38Yrf6~)uhmB68$M6nL%uJ+Qz8-i@ z7Q?Il87ns+H>>8R_HoQ*iS2zD;NF%sN z!E$LW>TPlsnkf`hZi>s_sjvT2ig(uD>fW2eHgG28AL;YtHi>lLYd)yRN#|bYAa()4 zgik7a)avZ9s1*2LIxrV+b2d8d%%nr)vAEtDds(y4^%1l8_I?Y_W$`JgqW-p$L}@nH4Ykj zbGvo;OYx736xN3g{Vlne?TvOWY>8~bC-qF2a$ko@&NgO%;~<&MApI$hFN ze%m5H76+vt{QXkD-}Yyjok?Di?EQZvl%sN>n+&}){$Kd_t4#Fi4?;;FGg>vbFGuIXH<9o+H6ewprMni({wy=o<3Y-I~a1z`7F}?J#pTDdYNj zNY%VKe760=UDCQs%2}(<-`JO(bI&1NnSG0W_IyfN%Q$`4)GpNV)o733&3etrb zs%vxvD8QQPs$SjUiJe+h?yyTlyVlk3aQ9=OIpnLchYGIo5S*A6h6(rlZ1{`YuU~I) z$==cURntQrG7em-H+aacfeuhSSnF2VVjh>a(x>Yi->#^ZbT;hY=OHEI@dLsrt^+3x zd=DqhX0;upwrC1?Fa3I5>83aIkm=&5kJ4C*d*5HT&Me;b;qcYjqg7_8(ny->>WkX< zJV~(LkI;|R&$ZlAOjs$0X51PLxfxU9qgnaaZ&`3o-36`X9S4D(Z<)v^1=abABJJf= zIOJ8P-sRYK%8)+hpw0MVrEYKYUqx~lzXmn$%Qe`rL0ENw-n=X}D5XD=^D8-wee`i*VWqzQRPY03 zR*i~5ws?-hLT&TR)r6~^wz!QjV!qf!c@OR3o}+H41$ouCh)Ab@nYxKN57$c)DYWFE zF{|v!E0qF$15cUQ`NfwChJR`v9}#OF=)KUj*B|NFx;dP_=HxWW!ka^Hg} zaLRfD(z)Z7QN8#kY%rP3?yIe9v3)PSl^v06UYW^4WA{qMa=)ar?*SuBJ6@Cz57CCToM zds9fh&ingB-~L~9t03z0$K5sezdl}g+Cto@V2%-vABdLNZd5=JnBCOJz9G2>U(OAl(NjX#&ksVg)`n2mKL`@JfIiZGcU%M6;SvlGu_eaNj3T<_W87W+VEt zt_9t?aOrz^YEa2lMrvSW5an%T-Wa5uY-nCz%@)6NhhF4gXt0;|*oxGNir+nmnrw8n~p7hH;(@ zlh3k6Uh-iFlooNoF4d0a#nzmbV7qH3`@rc-#)b#dU!*=v=%^HV#y-)ufJVJ^dZy2+ zQ*YNNN6X}(Ef}4pdt2aKuMllN`?&iuSr@1Semq#Ip=Fn*epq1CaNyzji4&fmI?m1a z)ZQw3ERpt}?LMuNi2dnX`_t4DfUBmK)&#wv@%w1;52X&_+aX~YFP$Dv4C@+G0u1aN zzKiSArzq?3OzrsSRSn)9w#slzeH&fJz5O9kD_MU2LjYScdbpE&+b=`*ObeOoIF`># z@uQB=9$LqVCAoMry5ydG%IzRElwPA&B*_NWaIct@%M zA=)00?5b!&Mrmd|vAs>x^QY3EZPQOZtJqWjttaEjypii2cr3TkvAUd$ntesfFL`t2 z`b94l5IZBhRUm$^QXa_eWs6Q%;rb!3G{xaZsCKgpI8hIIOy=P&a?Z zc5(*P3uqvz5&-+9wv<$KAYV8cQC|Ok*T7k&vO8-7ao zQl=m^E3#jBw)sgWRhzJg9dQsg%A%7zOCl8d#map>C{LabMR6(4v;cp}FDkgbEhkUO zPOh;*8_8PQ(9i6Asz<6~L7|jssy>w!mUVlAQ-h+4_LMU@6_i$JaFV{zFq7VBeyR>V zih^LRQh(~4FPTKeIyv4N&E%}(W*@j%M5o^>fE)ih{Lw!W+>m5v(8M88zei6grjnw~ z+DbT9OyR3Iiw3Nopg0~+k9V>pb!KeSycM@gMkOOFC5Y@A4oIA8TQu+-inAT|Z>o%r z*~|Gk!3;&U{y+1tK1`_Mn?@uW@NemxJ{2x9$3?@g&sx+a9~589#mOVvfL*rN-ZajO z%?!EJ8$VB;$9Dgn{VOPN+j~i#kr`(kKXr9QgjLR9SuC8e>$4jfu%lC1i&%YhcwhHM zIiryRtBs}VQ_3hnM7z%N8i_;_&c@C<{rQ5{aCaR8FG8PG7?1!}f(j;dG4xMUjIoGfj;bMXU7as&Nz7FgHFob#O8Pe}G?y+{}7~9)A zOIb_x2`aV88Tp;Da6H{T2X^*ZFp};$krX}DLedxNI&OW+Ds&$nmx{+W!7OB0pr4dV+j5D_wJu!xr0p|wXYqTr4dEQV0& z5X{ZHSZLm?&Gym#xvJ+H244w2KtLMZLdN&t|ox(ZK`1 z$8)r7-w@N-E6}c8KPZYZ`}-w}&+ZwmV9;h)?1Qx!mShDQf@c{W&!S0>7whh+zIyX( zbA=EqtntjQG)F{#Q*b@zi-&Dmt#@u%kX#A1NtZ^IpAA0#H zJO2kp<($Iu7oSCLVbDj$0>+s#nPc(Eiwvg6-1)fTWX;w|4F&IU^wi~iOd_@ceCZHt z^C0lykZB2ShSVzAw2*f)Zu>|O*kP~S+NFe>CaA1(Fm9yxh_GP^tnGXo+Nn@*Gfnb5 zu(;DIml(+$7^83tGTt0}`PKe5+ot1v!3nr2dT;I+`OHXmmKW(kEV~td8egBsQIxovD=ib-dPTrHC1Cj?Hr0*O^VPtt(kl3Qjt;{{&^D(h!LGz(q_jbiR=LSC zI;8anDq~iDzH)X_+(b)bvO~c$ua#4_*uW?c`LZseF2YK%?7_sqC&jXYWU=ih;WozM zvu_*>okrO0wYHPr;Jhgux*W6yT>PhyH9ubG>Ip?bW9T7d4H)I zWrkda^w9i3kai5erxWfaQ(;k7H0wCJ+>F#tZpC{c3U1A-rhKi1Qr3HdtvVo3ZOvVz zP7cd&z_!)^Ik%AKTQ7kD%WFFB4u%phZqu&tdM0rFEHF)caq731EkX%4@= zzMguMLhvG`-c^qe$# zTDt(Om|;So`5;yiVUkEoLBwB59)91ExoG`aD_y)egyIzh$)Vv-;QyT3SB7IUM=!O| zZ}qPld_};oXpXy@`KkNM5{J}@BKzkIr#%Tv$!^k#t_E(ld&Y`Spc+}yrG;Pe1^c)* zVDTi(ss;Y`(ngj?xk5Hgu`CtZ0dRFE*y^wEi6301DMg6?9J~=_4h{_sG~>8DQm31z z3~(6ttMj!X2I>gIr$VPa-8DzXTDU+RDH|&y2Xc>>?T6O$fCShH+s97xqb60MO}jSL zn$M7}nH`p6xw~!Y*rd>=eVb}%Xv2ZNroY!u8t1hP5vAB>Hz|=)y^8?^VY$?pqQ9c0BO!qe*2Ks&C zS{!cn`RV7mUnFK7+%Brr5qi)_td08|z>C)Al{w3g+7j`36wfAb9&GKPfm{%8_xcDm?B4BWdM%N$+?e0LgLx~b}ivg%J-Rru@*gjY~n0zHxu1ZNm8({#+pEtiP3kZ09F>}l+g`tf`~G4CcA?-1bGsbHSu{KL7) zInKG$Il(!~Io-L)Io3J52G%^(Jk$KQ8PyE;9{29`=9ZV)!X9KFneLmOnx3#;x5~iH zHyPI%mwAuk58}_#@bp17GCMVgngYt9zLC1QPA0jCzl_IgUck@cc;3sJ^O{F;-7f}7Up`W~&%&xU!^O0n^3KzsNxq4z z0PtPwd+m2ZBfsI+Ppakp#!HJ$nz_tNPtPAryl4Kz1t7P3qDCZ0YC&zEqz1A=E;|EX zTRW9Kuo~9>Zq)fX_e8(SisJwQ`EcRy4V36JldJlotMJRzzX_}er0>*lo@-l>K(|dbPc-*6qnlyP2=8w1?kV{!r(}|! zG3-`!3Q$0AtyIe6Rd2k;&*LeMEiOa;RT8DU&8p#;wa)so7j3=WNxZ?%63t*!JGL>6 zkpPE+wcFh{n7s`WBY;Odg%G9|Lx_1=1H+yvbPzgMHTOuwR*zzgF#3Nse5w3Uk&}C- zA6y!n|Dv|go9KUNjWbap9fwD@5<_38>lPIL&HY1%FYqo3AleWTvAN08q=`m*-=-g6 z{$jr32wPFRQoB;v-9Qw8E+X5sJiNMe@J!H$NU{oZU!^aM^epQ%^@UfN`QdY{8dfdw zs=-rO3sNgBTd-z?l|)i^*#yRVWoOR@=b;z7fVU~4B1R%nlI2(p3>R0d3Reoeq~reX zx9pOi6vILgCrCC#3UUpRg%m(mAUY5M$Pok#;evq7mK%MJI^;1ga7sA#D;XuyZx}VY zNsR@9-N8|-8V_CYk-~-oO5V{d@_N zX1Z4PUP^DR-zfCdz)Jk8PAhc^ga}};(lcpTuJ=a$;K08fl;#|81&e)n-{O~ExAO#$ zBt1j}t^lWmd%=0m9N}j0dj^E2q!PU19o52`BFk)&B~rFh9S~KBG~9E5&lX~EvhF8N z*GAta6%jRsJx&zKKJiE-*gYiKaO>4kF;RMO*iq22V#11<&~7cEO*H!2rHhlR83p-; zVp^K}jW?W*g`=ABVlB*XpP=4L>=F-NK;+l&!CxHx*JBNlk2`^+K!n0Z2Y=qi1xibV z%#DF*1RV9#bw>Q$%f--o7Gr|ObofniL~Xx7j~K?}{kesE8FazKx>^X4NxMU|iy9qW z7Zz}IZW76KAB92)A%yE1|4RAKeoc*Do5cB$kfo_zAC4BRyADW){QS!E%_F>Ph z^iASU;--*LRsg_UyxqnAiM==BKY=wnWi-Ih+tN%$Nsg%_Zula76DCY}Q*pFTT^Rn` zE7AF2#fkN0%R!-PX@qC9xP7_=!gPtpE8COQJFOLrEKYgZ=DeEUY@D0~2OTPpS7MU!lkEa{rdbW;Iw(0e-i+i}5^QjGURkH_@~g3=jHaH3;pZy{b; z%v%7Ctve!H82!&}(G^i#%Vx_*?;3UB(n}5SxuP_!pCUesu;H}+?7AyE>}q5a_w~y} zio~A)WWf$uz1@rfr!L;EHBNOcD%q*bQJciZs<=C3QtFK-i*$MEco zYFi(*1~iUpuHURdbTMheLexHQtKP1d(bz&av`=amh^~$1c&AP{*Q|cTI(_u~bmhIO z#iO?NrA#u!jT+4;i#YHA7-*tWk*PX@Mj&J7JNg_)lnu%rWr@<%+9};_*-hSk)^jA+ zrF6{I1oHaQJa@D!-z0GQ0|3{8X^=Yu2@ho#P^pE#W%pWSR3iG zFhX&=911Ueu@X^iwoVzweQawiJx<&f>|X8u-6`SFDd+&7=zDUeUAuhQ2RW?`UA3=>cge_mN4bk3Rre`*nPXjk$>?krTDrm%rMEYKP2vu}TJi zqy~K7Hhwf!XzExu2>L?J=dIq>p|-? zJ?}}gUTOR71-uQ!Xw%FBwYA_(;{K}_+KXOsOaGg-QiM1V?{6BWTVAkCJt*ZH_#K?F zGU_(<#g7%NcB1Ma0Ege_xKKYQk0j@I-aNMB$^`5o@FHYln$YFu*eex#bq zEMqLQW&O(I61{GQ{({lj7^4 zIj1#>P8*{u>l_461p81)=VmmMgaihco}fY(y4-VR^fu**7{1A;}6!fZR<< z8hESsTO@-tr<3-l>*ytk9SPuqXD>ACkDeM;PC$p7Mg?F~!<0uOE0{Cx;|4J`&9(}7 z(+6O8{hxZImziIqq-w0qKV(MfgFQlAO?+IHXa6)y-cZ4$*fV&>^&+uhrb%4*^> zK=U^kc?@gQ5yl#m@=|kMyxAAw1N437hp07BHSrT2%IjS6+1&j%xPo3qZ=;vdyXXxm zJLgo0W1I{9KEnaS5u{M~)W>@c?g#fJ6|bn~N83e@xU0@|I?F)7*G%WHNR_6dQ`1iVuh}&we%Ucfbi08>Rwka# zhX4(1Ry1eiyPcuVqPw)#sn^-qdD2PTIa7)yUhp2~LwfgnL-xU)Tw&%%L|uJ3INp3diL8Oju3ni*va@(*G5odVHTjd8|ImFa zNZgqsq2@V=(D_?n>Sc-8_Epeq4}#fg&Dks4OXCE7*eq^?-+-#$eoS*Q&%Lmak{4cf zK5E7r?9*+V@8Vw5Q;H(+5>cHKU99qpap~0&u60byovCV!r?^90qvk&2{vF48KGdzU zD>HBo@lWQ%xqbh&?QXVLT34FXya-wV9z3+T(e-ugSe>-g%iwj|*7y4;U>i(~-pBQ` zPwuoC?JN3M8*}u(Ui~Kf%KtU~amaU3c;cQ|(t1rI!N(bN1P=u6*AwQD z|I$2XUQ&JKZ7!TfkUEbtDY(yNZvyV7@i+c#`nkxPdD-+duKR5qP}1SPvG4Rlum2W_ z1I(9lu?>NiOOZ!vORp4d7JUXDl`x3fewTi4 z$x@-M{HNw@(skG5PuFDaiwAi|(`#Yq#D<>kF`;W zbW$Ij-#OyE7?{mH_kn$jqZJ{a^<0L#4OeDVe?t(2J!L`5+jo$vB?PvKY>}Udmfb^% zvUEbhp{nya^Ua|!v}#C22q+s7g7wWNU+CtFUb5-Grs#1B!>wY@a)|c`_q^ktF#H3C zD4G%|9cA~d#4Y#e^a#AXIC}&q;C)>4uqIq?@Wn7G1@tUjC4@?rMYiChr7ZbJ3MPX= z#^@g}@{pfo?SQ3Xf?U%y8B{2v%4XPSJ`{<|(#jftM9H>g0rEQX9#lt< zFMsmhl-u;!bSxF|;FzXrWzhc%T@G<^_3>#DloXfbk>qnE%3S^|%23TDI}=X(SACg! zd45@J`C?gqnRVHEIb~UB*>kyizj%LkKW=|-zjME5KViRif5=7i+~oY@x!bve=$7=0 z2^Qakk5K7kuG+!hgON%`R%%uOg_8gFt7CjvmX%UEc==hiaS+CIn)E%c_>q_fxpf6f zIZDM;g;Yg-Xxc@I{Oskm+X*|uKH;RvsdFuX_|!CEG{Gq$J3%VpIzcv}AYmmzCqW?L zC;^pKrYm_@Gke^809NaA3oZAeulb@zIQ7o8{YY;|0&!%*W8;fpI*pR1EKrIN- z0Sb1ys+$bTyrJoyF{mEsJ^|_?qHGMHHIlniaj}&sveI z(ZFic0s_hGiN8E)`1|rHF??gSg2>TYLB9~&96J%X^aS}jQ+!`@@~jMk*|roj73Voo zKY`gSvNJ#SQ;S{ee`?WZlUFj;Bp{r%J}aLTc}#VEVwK|7FY|@TJ?pl+N!%m@AilR z73(Rah@7U|6{kZf*1w;VuZW!MnM;_fof|UL+%ehtxZ}3tz)g)Xr8sE!`Lg5?U>G3R z&Mo~`8iQjq++#^JQu<3agt@-ozSLSr)H0BKE@>gIh znSMk+VnC!czCV6Ivk%@2NBu|G^{VSdmp%t4V0m)*YB+y5aX2BR zfO9}!qqMTrL+_HSpr>wF&f3XZcCBG}ec0$*6m%c*WXhz4gdi(xvVrhIi&jYh674hx2*cTdO znI?9;8Iq2Nk>&q}tdjgpkIl#{;ds4RZCCUKaZKGdRr= zRqkgm4VqYybW&uB`RHcJTIO2uiG+~ssMsh#)NYh%R7cc=vW_p!HI?ohT4CrZA zHtA(T61P8lN;VX=7PnTn*0z@UDOf9?>}-oQ7>8wTU(A5Z({y<&%(hfqI%YsEnC<@$ zra)Q0bzE~1$8s*^nb*61~PHH9_9YDUzQ z)r_ebUsG-`lBW~$#2|HELF=v>M~$~8Y*xv$2)XO8sj8V$Q(rT+W_ry`dFCLkCr=gR zIsNGx{rHl>VyzCGmcJy}nsg7=N({5wJ8{ zT16!1gE@_&Hs^OazZZ?URk_vTiM%)ReuXEfD^lNs78H+*;i5@=T9o7WZENwJXde{o z#h1mS;wzLM6JHbG5DoZc+b6^i#BuRq@s>Czo)PE8@5Hm>kBSg4D4KG=_zZq?cB>Ln z+Qc{UyRm;zy=p-GS$$M(5I5A1t8)}h{gk>y8KVBPx=y)W{i?cExl{eIdPI4*`j*rkN#ClUQC`!}>Az9B z_225hRgUQw^`!D2MvjrAoHO!`u<{$D(x_6)jB2As9c9!R+tksP&6cmJFXosz0rjPv zw{p&?FXx=i`A_w8Ie*MG)Gy}duL798Rf}(r8NK%!#JWG|eETIHej&b(9(@F|CQx3`(;p%`xYjizqFj zw2ab9lb_|as9|`_NA&4J)tmKZ@|&mhr-Y%;)@KWg-lDhQ+xUuyml(Ihcba%T?xKC3) z3ybw-*{U?lN^#hy5mrfCWC?7s#$0E1nVZb5ux~m|Or>}#&F)VtQ)!2}+uTRx4pKg1 z9y3pxJ?1&{f_d4zY9>9pC(l!8&h`xRjPR6s_N|5(Jt=0>sA{1x;tl2&ym~T8U9ygX7pBGOUuNbf3J&O*!8I&)|_?y|>M^gD% zDxVZC_aXOD_i^_r_Zjzj_eJ*=_cc?P7Bk;0GE2;n<|uQlIl-(jU8diRnhCSkY)Cx| z(3*M*pxsTOJ<*W-J^PPJq4a(&u~wv zXS9c(Z&CD>`f9=75}B7}t>-9}i=&ht7H26{P>eYzCW+rtvKcQLFABS{)L1GU#;eAw z!YP#et3wMg_QsMY3$uyx458d}C51Q9xSLIRj`q-h;~BEA5B{}&PWQ5ByrRdhS?XEtS>;*lS?}54+5Fd^gSz!uDETZA%5fRuzv-zo z`P3NmF^;FA%qGrg54FYHZYI4eJbB*Lq!;TjSZ1AApNyRG{F!`~Dy7RUnf1ub@>#Xh zY#%%qb;;YuPco(TVqN$NCp_6iI!e8*@w7)eOEnUel`|u zWV@!W>9(b>nNJn>>q%|kCye>ZeS3?p>1)ak{r2dRSHHvD;rDtj{`IGm<+I7KANg$h z8D$W+n@fQ#~1s4x^Lxk!IF0KwV&sv z=cd#4V!umY`C00$|4RZRaUGS-cT2fZ*;n*K>EL$fC$0I}=>GrH&q&k%frboz@_T+> zI&J5)&C)&;m=$OZ%nK|`|IgPzTc91+6&ZZ1WxM~{HEoxhZ5`-HJzxIcTrq~pzG*x6 zkGE7`208;916u;y(|(w?dtevMlQbSV{$^g;Zv%S+2Y9@3+~e`~x2`wax4)j7{628l zTo>pjUz0SMrmw+?GOnes>6p?# zwr>7EJ=RjOkN*$af+ns(`9J7aW&fr7G4mRX2W$GrV%6Ydm9N1%Z$q%rGZp?&FR$rw znI6NzCeK`MXZqUjN2wUc^JmtT`Xo3bI2&^x%Ozh5&ha0G4dw?IVb0|_Gj-)TD7YlJ zEVwebhJ7ZuF4z^^6x_-_fLKg%Ke!{fo9F%DzTiRDGk7F;EO;{56Fe8ZknZ2$<>1v| zGNgy{LWP;}EHo@MB2*R{6B-{Xhy7{p2suLDP&iZ-ni8rHO$|+FyM<U7o-teVxU-)`N?bjhKGv!Z_+(-e(i%4-~c%(Ek zIx;RYF=C6DC{LN~6A4D*k(x+dq%qPInGu;CnG=~GSrkDXk!6vUku{NZ+{clw$fn5F z$d1VF$UfwQkt2~~k&}_0$hpXc$mPh@NRro0Q9YUmf1{jU(?tuT!=fXiWzjLw@zL_A zBkGM}-H3UXa==+v_3jDI^DiJIy2gWJU6-^x;VNtx;(lny4DwDU8C!x8`!U+ zo1@!!9)Ug6YeTYGbZ2xA>kAuEU!ot#wve$udMJ7{dOUh6dM0{4dNFz>dMzem7S@m3 z9m|gu#Y$o$x&6$`=_ z*Tn01jKv${O{`CRMtpXBPJDiRQG7{Sc6?cUCHGT&O?(~OgvV&SE50edHNGRhJH9V| zFn)yBNL*k1So~zXCw`9o3VlTV!S;?{h+pPD;&IIV9lsh+vahinIL1`!m3ftgmBTnr zRgS1Es~l4~zOua1!M<7PtqfOIRZgj_ubf&ry>ez{OXXbfET~*uxwLY5<*LfHmFp`v zc=J7Yr%C^s{&gX89?y9~XgQa1F5x@+$NmqW=xh}?aB}mQ`j$3N`4G-y{-B@Jf2)q> zlNfa@?`KsfpTwvxoWwkflbGjl67xJxVou;B<|IyHdT}+5|p{(H`WJ7>%DM?7}zlrB4=ii>Q0|0~PW)j0d9bV-M8wvltIF z^V1j)%)|2-m)%KIe_%B~iD3>iN0?>inDp}%na}p~ll}Z`ME2ACc#?moxyRg3bWR)0 z4J470nTJIGnTt6y&Y4dM^!b9nQ9gU$JD+;$1@S4`@qV3>9eZGh=oUYtUG9HSax3$c z=Y*-gs4fv+J~_j8A=l&EkJIh#5oMWAnwa{{t-AB{u$8w@H64^QT6a6QZz`pk#5Lyj zsnC(%EPfZhwOEMJg1?z`48Cu9EG12hqoj-R;{C!94~mJj_kLK|#1MQ#^H6-dVS$KJ zx=q9>6^bfKw~K_RCQUyerifzl#dVOmQrnM-_b9h1 zw~2d%Vwq=In0acXO?0=rE8HszYf~pj8wqY1a%kwN)ag+NpC1hwpVQ&)=BMEET<+6D zuNT%9sD%x;ouN`0Cra)?iVRyG#>ONf9YmOc=h3aWH$GKOV6G>`! zVeLS=drTU`NggMbl1fxB5}!}G_nJYX#aR~NIH_`3_;B`MzalS561FS*D@ahfLvo+j%}2VY%sASYm%>9VnYS=(>@lZZvn3{(b4prz!3& zWZl$>%H1Q(bA|1^5=Q-$d1b}*4{aEzn-i~0+$Tu8)8=STA+U5N3Q99yJ7?14mOL1p zXsbQLvh>f&bdPjSpYfzM%*?!o9*jn7JV&PX{jEry5kY5e39U7$m&AR$?_23^_e^(J z6sVaeN8E4e)1!)0?!$b7l-4i%B#At?Q`(%@WzzP9r_PpgN0SF1GF9`4`*6k?Q&IYq z$-SL?9obvK-oU+*K5M$UeP$Dl2+Go1%p_-?SGm`C-I4Z9#@U0i-q>3)w#?Ha-+}A5 zN~>AQXHBv{z1#C#g}t2FKJ0P*Z}WANM;tas7uI@D6sWw8CD=->)J(C+@XgoCnH-WB8q={o3p z-tZsx>9pUq^2v|8(|3}4fopvCIbRQFJ_T}L_g!WQe2?FGrkHW5-wV^;mL4T(OQ*(S z+Dh;4Dbcw{{dz(1(7mi7N;4;oe|Zj6P$y4<*rWX8b6SV&9I|uhUVk}%vXFk?+Vu<$<7m$44o*ZrP;}zmFl$_|SBwOnsuJLbYAH1FN_|Id{b&$ak|g|mPWhRXLCYL9}l3$PsU4L}n- zJAvc78IdQfTv=qRha3<_kb_$FR;6zKm8a3sF#0pDV#)`9XJz=u!@-x{KR9q>L- z9s|A`umYSvhJ>vQZ+sPWd|R*bBftrrt`#}MZ3LX_aH$KlWiEobk z%Tu5$kRZP=_cTi38{|~jN_B!FE%^~}z6ty@z-OWq=;|LpISR@@p)PzoZ}OA4y94kp z@O%L>`v8vs_TuheaQ8n!k=FY&AS7t70KWn_8}QeF_|7zCAMlfaZcx4r`~$$Z1C9p; zy`ZcHECgi(;1Ez=1U?D)T0nfylloKOTcF8z8R`>(qg@(m)IJM3ekDnTeDXr3+zSX# z(*l5FKzRTVxOxh>9e3f4#@B!Y>Yo6d1q!|qT0<{u;{Xc)KMja)aM$pyddXj+FV5ZQ zAkBvYhdSPXT^A@Ot3y0(=kP7eHSG+ynd(;6;G%1zZhyFW_46M1ki3|15A&l7D1)V=E|k z0WJg2{{}uC_zXaB(gwue} zk2CeH^p`L$82=a0*8{!=_-W7`fEwU#(7y`231#zvF9+VpP@M*Uv%rV*&|kj?eg~k8 zd(Q!vvFkAKL%)8fvbp|+8+Ti z7pQ*%z6`J$TH$*#b?BhWI4Nf_SXD#BQ{}t>pV3gGiupyuyn~-|RJ2b4hpjZkF&!~S zm-Egepi2s74RI$Z4}*eM>zD;78Zf<^p#iVcKMsfpuYUs&?bYNgumn)bhYx6&mo<2x zhP8yY5jx0~1EQ#gRflpA6huPpn+$KXgMtyE!P;UK@OPo!*8nklYS#e6fO2-mH}tF9 z0A;Bh;Fv=-%u@cvce6; z`5n@;S!N2C-yJP~6AQKIRIhpuw@xk6`5V8#s88cn1VhEbzo(=;qFqOfn$4rY;w6in zH#lk?B~2AI!4$m;lmsYOK{)}+)f>MdxSJ`40A)9LW`SooD6>GRXNp?SxG|FHnu=1Z zCC+rE0z8YDqEs+ND+Rt55;lV01(_Q`X@a)LKxqR1UZ&(YAagG$$=qFK^1G(tDDy!1HkZ=xWJ>N>rs#J< z&NlEgfM**hb3w@iWiBYWMlp{j_C_@ql4n_3(J%Zx@vA@?4W1p~34$_$dGrm?Gl9E@ za5uqsl^#fl@?E7>wupK3rQmTS$MRTa9wlihU>rSC!W1!^?`qe%cI67})5&EmE4ZxI zDSI5!#xq494wt?l5$V0xv-=U7(bM(gkg2z#0zJm_+O9A%7vH)q`?B zQ`Gy>YbNwr0DVm8^9cAm!2gK!WVG=L)0G}jj^-?43s@GgCnx!v^k?Nje@hqZ!*`8t zzN@Lg_ki;x@b$oREw%7K{;v7ajH~xsbZGS(+|}VZEUgVZ4$yG*4f7SqJ{+Yn%f`6{G4CqHdZ-Nd@pufoV8WwQAh`v~g(eXUIaVhLp1G}w< z-D;Rev%!nv{2Ld_hm*%(CAP^4Zg0*@sj|O;H&WT0kD}~($Uh@>gMAucp9v^CQ{osA zOIa&52+OYoJqRC&GbhECF2+HrW{Oe`+{^rQcLC$6XdwG#E5{Jv`HXA%X!}W&9ml`E zp(OPh#FkdJOiCZFWgpv0*$4hbkTV9lEs|pp@Cgg^f0utbMSTLCbD`%aEe@jh>emF)aaf7>yaGocKF8a zC|jNyH9Guo0&K#g%r8eG>{btbhNJK7sea^9Y=?xgd{-L_Iaj%M8sk%lzsn$hGtQ-K zxQ(^twrhpZ|EESThi>rH{pS2DlF#&V22 z#Ojll<3w47$WYJm(Aa2TeV%L~ScI5g1iT(F0XPBi!2zGCK#Mk7_Q6(*VZ#>Kq=hX2 z{#gtuZggQJwjf@0LFQO^GTSYW`_%Zp(Zsln=lXX@XI=Xt>WxAx72}bg->rhqs}N@v z$(0Q1IsnQ6;HyAimAniMThWhNtTHVmy>#g^C3W3;Y9pAJKfb6E~~HS2a3UcD7D zL51Xv7#%J-u5q^t__kEry=ePo*qot*>G~)c`DMT46k!Z{LAi{cl8}30FU!x7b7&`g zYz6y_ww&8SbRMCbL2t#nZa#W>GvHW6xv|jXd060i&`r=y=rb4exr`HqS1CuhE`2H2 zLihsol#Y0~0P#>queD$VvE+5ownVlL7T$>nwi7Fv!)Wi!oDo<9Ttdt_i&)x))jn2k z;MoQFGnkWR0qNl^c^_aGtUVWF@MN+LciZ3(O#e3gXCAb@AJWDng58PsmP1;TWfZT7 zxLw93a6SUc1&rB6kdO!Z^B6(TBQE_3ZTS;?vK_6y0@#anR4;T}g4Rtzteaw)!MZV| zbrFxgUiJ!#1K;JYZ=FiqR*h6k@|H+*Pj{eCtruf zK5uy$(kdATr3gG*d9zpvth9{h*6)ma1>et3Pz&-9K0*RGSw>9 zUy*yaiI(N;6-J10jPYNw%$#R2H~k8ByAO6yK{US{?ZF5oY_YfPgL(wq< z=KO^<(XqSY0yZr!bs+VtkfM6IDH>?zf z1qu)c>WuA(qGPdB_&Gy(_%_JD3-;Lu&Zp)21ah{aMYo}K?~ypPx(99PWX-jE2Qxk;&+WNI?l2x%c^_rn za))t?a(>Ag4%y6OFz1&{vGg(}cPnPbUQk-mM|B+Ej8iO`R;n~d8-2XK(zl{Vj$!@z zuT0SzQP)#kYRD8Wm4p3hPCb{(y^nb;$C-zGk|>rpnPMzMyNWR0Yq9pIh0V+0hwFGO z>wP?5ywL}c+OGo$03_} z-p|2lgXIcSa+ePwD-A?JO$MykOG)xQ z&U+z0i70U|I2+&tr+5^o4WKLo^9`KjV3n&JL|HH790X-8Q9T-P8iR11LZngHb!Jjwn0A(L2?*nBYDDOqA3o}Jq&baX%>;;x%bab-J9Gzuq zo$$|2X!S|xxfXiPLMuMY*3jlNZu}InYd-kzM>MnGuH4=4K`jqpM%yFD4qEXRG@qWD zl~}8{5P@L_<*?4bl2-;?&LfDf+IzV!#fRQRq^0!(d;5E#VVHlrP<=0Er7+}o!2=h- zhwo)i5Z54WCn!@eigk>I=XgvhOW*^&@+<;(<8lXz8h;EQ*opoAKCaPt7&ei+<0k0v zeWvKE(95mz1O`2|16G}YQs0v}G`|ishFSQ7fHj3dI|&7;q62F?cG3(e;nj}iR}V$poLQ?tw!d@{+cZq@m0>MZ>5 zW4x!Z`~jB#7_8C3zZ6SRg=gn+j4Mfo>PHyr_hRIJM0z_Y-v?zC=C2?_8m*1kl{6xH zG-A!)2+f)2e!xdS=>eV#=m1QBeh_di;BV18zh#_8F7GAlLB9??uR_o3uF6?eS3c{;Ow4zmBcAv3PMOxdJfnRB>luL=>O(jSZRTHERX>EdaYX+z z-R)qg9D#jm5$#VxlU$ajtz~JnzT(wavvH6u25E~R?Q`gni#qkSQ7m!jR)S9`bcQ$j z@cBgzK7EMgyvj3O&H?zzI;JqxJ^)ynvxUbL;Al`rTlm*fzXW_Q_!lzNUjeKF<=cQe z0Pi)15%d856X5ffhuJF_*Zd5Xg@%f^R!1r86CYlcgF3Z%cnxbiE8mLx-C8{mujDvVQ&;7cr% zx2thl5Nho zem6%~%L5Fx>kRc#OxIR|emA7GXgP$x#W<~JSk4-a{6yQN=hNMGK%e$wqTB`gOZa7B zKR%z@jaoXmb$Wx&=dMN2;Z2rrd|1!r6)$+&^xLS^NbN8DIhT45AfAL)>)FRtlCQ2{ zsQJ}j6U+zY9>9r!CqOS`TnU0wul|DYcWeJi(1Ef&fcF9BGQavszDsx?;T?>tCg}B$ zaF!*guQRTfg7O+*tHQqw{50@;6(9Sja)H-%DxbH^SMO%8W6hPN>c^O(aIf93Kf_QR z%~1J0DDUGar2dKRsgfntrvO_a=XvHKX?LL15MCWIU1?EE!O6AUuktS}Pf&T5^Z6Hbx&U1uy1vD@_7-^D;Bfr-*9|!&8z~2r0 z-Qc+gJokY94Cv1QZv@_m`Q;79l{Y~D4CtQ${d=H)4{iS?+Wt%MG=ZlHIQmORe`&R- zs}}aZ1p8kC&lK=X0S+D=JeC^BtU=kWD7zIlc_p`;`vUL>fDbcNr$gp+$X9{O9VPrq zgI9e6wNCxJf+JPJGtd^K9M8u%R0=b+y2 zqTcU<{#p5X8Sp!S-wFK3z<(@99JIoiwa77xF{onDg1%LbFR3}; z)8L0!8}Mp9ADsEXp_R4A;GYM60oJ}CV-_}?m}}dU-lGQ2Z{w0V=dZ~B#PtLU5}jNBsBf+(jV%BkCdZwHQury}C%h|;=@((gst z_X7VZ@Sj2l%qAAhCI+IMA){O=%9g?c0kkdv`bRVAJc@g*?;Cs*(=%&iG2jY^BxTGWM>WI2}1Mmjmn5T5iQ+hpc>={+8TU4xD zRLs#T=4kcTz<&*WFgIzKn>4gtL)(om=#M?D5eFWJe9XT(=3gCiu8uj^z(_PO5-sow z3%o+ZT1dlMNQH-}(nF-4_euy(#C%Q0{EOhc2s&0W8dfsu4?({oA?k%a4cJq|2-Pq` zHP}akeKhE)NjNn84Rpj$UB*w;rJ*j(3EYX%fl;4>QJ;$umx~cM z@Un3I%W+G_R(M;3+!fr-8A%2jTh zvO3D@XMvvu|8wAf4megdhFnu2qUwmKman1Suc2PV1Xa$SSl{Yc-x@h6o5Q#Q8!E7& zML}5w{O~|suI>&(4o+|MS)k){4Gm*Wlj~vFP=gIsj3ZT!qr1R=7x3qSKMx$Ul`dy1 ztol^B>VutiX=nJS0sp+w!Ow$fYj6(mn(>_AQx`rxI1S2mgHP(}Q|AwS@_@5~oFd%4 zV9?C&U+_-aup|9@_G0*xGUdexsP#8 z2WJQ9rSjQSaDEr~X!)s={45nbPXXeYNku;MET2Bb)9;FW&js)1D0oVlcENqzM%37d z^WJ9A<+;!nd?u)U>IUzx@ivWC3Ld=qrQjK9fj4^8Zux`* zD0uo^AXaO5M%us=)ap8UH%WVc&19%7kP>jpcU3-_AT7htf~T*IDseAy-gbjO6U6&9 z#wn3U6i@O4R93!~c1iF_!dfwe+lA-8n($P>ame)JY=0YI0{p+n(-HUKX@Q;a`E$@# zJ`KJwi5UTH9Gg6V6VadW3<%xuo`NRduG$ItOXU;ekn=AXHT%&n`QFEhQgmU>t6VXU4>av0KVT)VQEt)z}l{)O-j3`z2X zgfC)9_TjcX3I1;-0|ZU3SA8A&-^EaW{Kg*%{}id`~(=@zGs6GRT zcL$W8W4t_t@%RED-j&njTR*+*En;tyVwZvUU&J2VeP7C}86S%$rs-9cJ z5_0e+rUmaa8g;Ty(aXCq3xmfZXHx8~47_)vpO+&p^|V_Xd|N(;L*AHMiBj@?x^rBY zA@HdIVvdG!p~<%+Ux1zE`#AraTu6ACd>bP9Ny1?n75imXzJZ9HwIbh#!g~|SHxYCG zIq9QX@J^p`2m7tom7K%9014L-8K$!x6uc**tVynb9avf<$)DfBhm{X;UyC2JCgQ&U zu?kh9?7cM7$um_%Q3db#sEBfkeBRW#%yle~zb1#@h+BnUeB)n+TkqI_Uw+%{*hXn5 zr9G7PO=K1;bbl`m25qkP>l&8bq(rCgB0izyFJ<Vr0EPsmP}nI-LzzB<>X^tqIAWqDl#e!_O@zjkKmvMF`lnzH}6jO+GPpYE0Y z*?&#zaai^*t~*j~9G7uTw=H#b?xwu&|FHKqa5h!#|M0cX``%})&6(qEnqkb#IcFHo z%e)vGlO!Zbk|s1U-ZfqtLr9X4BuSDaNs=UWyWMWNB}qb(BuSbi$&KWeB$=82wZ41L zm^ta?exBd+|9_s(^O($<+{TIU>VF>SBb&!~6#OW?Ov5H2 zcboc;`vW=Ol#5LJO{}Jm-+TXPJw(5M^m|9kQp5Hu$M))d)ykq}Wu1dehnbEsow~yK z{!h!_)B9hQ(Rz;7-CvYd@BJq-TE~@o`ZHPOU(wPW%d5{uy;r4vB<`NSf~@qx3x+*b zO8B4U3gv%QpN#8Qm;a8P|B;Ly2h+}fBdcS;l_bv{64!qtqkZJhd?s2};##GQ#+Kj1 znm?1(vFJ+j&wR8}@_Z=gswx@npFB@u4y%;a?5H}{Rbigjw5x8dtL8BHKfimfjY%`p zm9n-;^$Z)zjlX;i`eXaZO=1c#wJ>ZtHdI#kWCqVb~ApXI#HbF-Y6e}nmzHXLPJ=+6%ML1vTwF=FvYYs=Ics3seE>2nEH-N5Kyo2IRe zc#o+~$QaKy*_Z3I$z^J1+QIV6)TR?tSEe3J{QNe3jrVIa$nfz>k~RaoVP9>-IM=4w zu-P`OpEi@OKvPYcX^^ysHgnA9$v!SJeSxVB<4l_s#yeNWhVq@;$at0Uw9Q&$EG4zs zVA5t&4{Wb(*st5Lp4%KS`)Arjn^N=LkDA2#Y$My1y18VGLmuljkM)RjA#~B12 za9{JdojiX3ymX_lc@dLx462G*WxTS~#F#u|JoEBeUygxA>#EooWjTg^s^a24M!mfD zh92@d8)K5!&8VN()6h|k_AIS`6L(j(U8!&Av!`iam3Cy>OrGpxVe6{68Ty=K+UpUc z|5Dd^953f_e4NKVn8!Yt$3C9Nv2Y&8!g(CO<}EO6DUWSAkK@cdjwACphRowQFpuNB zJdX47wwrZ0F3a0z;7i^?syieF0 zI>C1o@-xnR+nwGV^^+ zIf$vqOjovFY|3%fXcE&@rkPB0nC4Tn;OXGGsK1LL3OPbCp_t&gkVlq;8t@;58u6b4 z`IJ!8P$-lg$_=$cJ|t`NU#Czf&UNKJT1Z%~w_HzT8)K8-)W|cn>^M_P!%(RT_tu)hbKq|p? zEH|>;!g4#)Zl--q2bm6Y`7!jtxaSnpS(7eQljT*UgludB8dGhidQ9;~e?v)pEnwUe zYH_)pQ08w)3AF}MNMbANE7XN$ccy$ZUBEQJyv9Bf8pSjgc?wPB^c1ts45rzfpT}|` zNC_zOt&ZDrcYw1;Uw(;=oKT>m)B(@f`>E;8ov#203#4#zNgm>Q50 zZe;Bg926`H7Bh`w8WfxqoEn@NoD-ZMT*S0AxFWbZxR&Jx$jvObvD_8h8$7^N8axU* z5j+z-&vYqd3Auu2LW0T5>9|lL$Y)Y|C=$vE<%QaZI)}Oi=ZAWR`h*HYLqa1$CBdno z38BfM>7iMn5|(pA3;6ot(6Z3V&>O*Vp>@IH(7MpZ&=%Rp(Du;o;2_TL3mps{4jl`f z3Y`sI2%SYAC2=1^ z;X_q@SQ z6WJR%V3b!%;~gX0BBjB#prgSJkrON>oiT01u$L9p^$Fh+%{uKxO>KkkR_uecqU^)@C?RT(w>aTAWnzkGA2th%co1KuG@@R;fWb@ znHFR$&RCYQvT|HA-U!dgSjTcB%Pl;5*-fHz_{^m6DozJN-6DH4TZC7^4<&78 zJ6oTbnb|tCZDxnimdq|p-I-)MpQ(UpK<2Q_QJG^iCx*9XP6^G;oDrIUYqK-jXU@x9 zm^nLh3CrbDr>w&qLx-8Gq+h^~U72e_B6Cf6VdnbGP2qE(t(iMB_k?Yk`;BpulzAxB zC-X>XNapd()0yWoFYTlf&$+veaLDKqwk zx@E<1JrCDwkku%3Hgg8!P}RHEw4bb$tfryztPp&heLE{VxHl`evd;z%Wwon0_R)D` zyt6uis*QbCR~{cZu1r}y!soJjv1HR&l6(*0{{tS(CW` zQ?q7?Nrt+W1_@y;9@0~OB`n%W^E4JvbHfc%I7ndSM`H&QQ~=(lo(k_9WGPW zuJG2Zy`i~T2eL{*M>&6j^Jh5CR2@fweT<_L^Cgx_+|N4CeYh0rlWoa%NnDk9YEafx ziKj9xajX(!EAc8@1m{bt!pc9vtx8P(4Sq@7l2`v2FB6ydsl*&PZgR{d=42N}CS?zaO!_nI zkz-nkH&XWo@jS^CjW-59uFT`sAmt)&L49qHP#UZhv0yxh;0@scY0 z)iNo#S5j3zzv|-p$I6mW$Tu0nL4!W!qmEDccy$ZU%+yJNyCC?K%-0=+j1gk zSj#D(QB^b%G=uBRs8)ZrN%KrvXws74(VEn9IcOE9B`wM523pf{J=3O^TUl;pxs&Bi zmU~$4VY#N|ex^fJ^^UYW-tsilIi`zDM{4V%!cQ-GixDPTvR!F&Y!bsT#?4xZWUct0<>9 zXI##toT)Mnmd_6D%b6LRnlqy$g!i{937u^-o=|$mK}ooGL2xEWwy_|52qfD|3`Ib)&BdYVt(Ju*NU9zK%4byKuzXhfRO63V zxv^@xnn9$tR9liu9j%TbRlQfemtxdO>H}0u)3sRAwR+lB%?w`g)VRNi>3= zn(BJr#p^lO*RFq4ZP!WH&(zTMi|ZHisTS2je$}Zqqkwv~+Ldln?@;fcerj)Z2oIfR87OTZHTAip)q!M+qdV$8M7d1hrwG^$HV%3^!%@wznr(L7O$WIUzq4m&uE4p@< zR;bk1inV_#SGi-{4U~Q&O>|U7h#q2?@|d_++@~xP_lr{H6>(VnXmN|5^n6QW{ce4i ziUUWz}Qfj@@OA^{QTvwTYMitj)a1-mo>@o8fI^z1rK~JHRUUWlXm$ zz5E$MBVMmII!#I=UavOd^=e}>(v2M^@w&A!uUi{8U}{84;}qnT#!XpUEOcy~ajf+{1V>yZCRHm6sbC~8cE#mT}=!0?33Z~U2t*s_ERFTqn zGs|sEyO{Pe9WeV_%GZvX_nfHK&Y9nk()c`x8ebwxw2+eMVkwxsW;%{3(Y)qkN@t27 zPl-94&NJ(@XX?!PZY+C(l*B$DN-Sg=!Zd=ZglPiPWTxp%vzX>GEnr&A^_Q_+$@B)( zI;M?GTbQ;p?Pl7?bqODkS ze{BFM-kZE#@oTk2%U*nrK7#Uz;@S4%+4kbu?&8_*;=7u}winN~6W^C0f7SHw;&-NC-h>7hjeuXL5nv!iQp6w}~?J1t^DZZ5HsQDauo$V(6yh)cX%LGd` zV*5$(GO=AGBpUrl@ELUzBA4$^$hiWs9VK*TVjD_e+eu*CNf=_5Nt$eyvE3xF-6SkF ziESoWl$VVwD*H2AwUShEy3MgLvUSuaT1)x-7P!`4#C}F zVbMTvPjJfuySO_nEWWtBymjyQJ2i80XAQT8Z} z5^ymxF|x?w=9J`2N=r^lpOLEeFcNOc!fcw}ajcXPlp_)R>+KM}EcT^YqiIgL2aZpLPlV6PuCs4tA00z# zx~ZSM&U~=68#Rr8arJ^S-hWAv4+`ZSspz+Nv$8Y+efH+eoE$Fng0&^;P(tDu(ogug zAVvSVDW6lFQWcUxoAX>CX}ha=$qdi(lx2|k-Kt#zpoVa;gMSlZKf(ighl z=~6sy+Q0d?mfQt)d7Ag7Z;qZfUOl6s&QTYrQ{vknuJbR=qwY!mnD%sfjg*HENlr;7 zsSdOZ{_GE`y)&zCV{T#oIUdw~7hK;?>mejIRi7hX1bcX@VmI4Nkf6=VJ@LA87?U< zRW3y?(Jgz~>)FWcUE@9D4dWx@ZR1Vj?AbB(?qru2dN=dL-09XA)Y7)~3OKlUx=YYbU7YrQA7()n%`Lp>;5 zF*Ug8f{=`m<(1k?wfNxfibvhc;(GIL`lpIV3>e05bPo(%^cW1Yr~96IwoYz>sy7{k z23PI=wQ!$?ykgWHDauIjU+RNkK5$;+OEHvW?%mvD`|;PNUVRsjRm9P_en{D!hW4^c z+p1MQOwwy;e3lBV_{I%jnUL`(ZFTOUA>gB+kM!;%^LI%vNxbryC7B2zlS>h(M$^GL zBt4KMf0SAKb)cEK38;oUk@22KP%4Dz&w=s4t!^Gv*VuqI}kT8CTMi+Jm~S3ashv#b4wu6 z6w({{uf!yb3fz!6HDU$v?z|1UWM2wVMU=zqAVitql7C9M$jg#{s-{B?3|@YS3b-KT z8Mwmhq@I=D#_t7iUxh!YMQA6K&;Z18J6QClTH!HL?h%3b=CRO1(+j^qyudhZj;{A$ zaF?dLxOo%z>})(lXUg9kXr9279MqX{dy9P&9oXOH)}^eblkK==GJa=syK}w6&w0j) zsy?Z{tVTI~SvXuw^I!TO?Oh;393j3gzA1j(zSYdrdjA)=b#=RWAEnk+qW5@_}0lbbicZ{r)HwtSoy^pG5um?g{hhdG>iUe9U`HvPuZy zB64RfyMGoe&P-z@W~f$fyaC>>elglz-CNyQJz7Ps?n>`TA4=~?Z)fjIA9Sxtv#)-H zc!4BC{CWmTus}EnMkGLzG}2Z@r6OH|>#Y(srQM$tayz6n@k`7FY%w0MSDshI(_`}c zr8YGx++p{hWX7qQ`9h7!zcgr{J2}J$OzktZ>oA(yI|6Zj+z9bJ?2EtyubzX9T4BCS z9h?HZLOi@Y@*p}MSp*|bHj0n?*GWRn19Z+-JNS$87g1P6Pgc)u54dNhM*}RWeDFY7 zXiA399s3m!j`h+% zdFfbXKJsZf+?Unn=7|xJmXR;=!CHOK-8>wn>jE+XSy%+R$LN}a{6P$Y%!1sFL7-i@ zv$~2-0QgdwQ;j-FjINQv>oa1j?*RhSu`T_luAyT3;T4j%P?9O7T0O2n+D2NNw2X^C zzgfE}T&SfQ;aU2~3{cKno=d&`aTuVjadwCZQtW2GGnrpyzaTyyLvBbJ+L|H;{)>Sa zv*mw0IC(55z2mH~&Cye(nuPo>*prtFTB->MC084M@1rc&%%j=z&z zc=6LBsnN(tS?aaD%O|-4r7(!9yASw&>)RIEaBqeJW5V_U(L9qa19ayAYiDR_B&cmU7kWH7x*Sv0 z6OWKgJuWZocJ8o$v(k_jfYS{LHQo1xwcXPc+wrc@CqyMtylo}<#bGUG6sM8Vw;6R{ z`!im7Axl8q-gfF&iKOyfW?P15`S5xPy|M(%^;T)BwIoIzpE;Q$-2m0T`Kx#YfgBLI zPj4j7Qabp8k`#R`WipL?Hx-rBkpy6~U=u1Gytd+us+P9TaqFzdFX70yT7pi&tgMsc zl&iB-7#h{5lEhB#yavss(gEp=fsHf@Yt#cy7E3Dwos0V`!w(Dnd&n354xf(6uF_*y z(D$k_Ivt)?TXYIVRQ}#=gv5*Chovx8u0tM{&#ru57k|GGxs6kTka4$qb=(K`o&DGv zAa{NJPq@LG%N&pEshQ((RRGCpjvf4S%tI;8l$1&&8yZdI-rD$nhc<0gN7wZz&zfUl z@Tt0K1Fp3B9(aD(D#kMG!$YDQo06kHBDuoOw60deSR>=UOxM~OwbkTalJIdEUjmQO zMd|1h^(cLk@os@ctQd;Xr{+`c(VCZLFuIq~M@d2|4dVt z9~Yu0G%UPEk7Sbjp%=aq)IcYNhvIT_%zW&;P9EJaf}lOvBpK%y z0jGq*@7pZAdEe5gf9Q3@oSBvLQ!yqDZI)l*a!~m$ranjXWA$(XL1e zsPwG{_ZCUk*c4VLNw#DDP_7{iP5O-u@Y=s)J1(DektQAybWt$=0^#0Te&4C?{iEY{ zoL&B^dZ7^S?xE#1Zu1(eP{;S}udW@n#NG}OPID`=!{SPtoE&?t#4{GF5oa1}={>wN z`mzzh9pVDV-|$V#E%Rf1293qr3rhG!s%F!|1PY8~ z@hE@QU`dB2-LzbxxiYI*^sFnAT!Y=QAG9>P@V6Hexju`VhxJZX8M_g8Hj-aj&UNE# zx6H<$3IZxS{)(m!?EiF+IFXhro03SafBx|`4NbrAOlD+s(;$U zEiXn-;@tsWJMOzHz_Ht?H8QNj@Ke!$by*y(jrba&Z3IHz6uZ)wgLZi}Ed-3YncY8< zlH=)8w&*z>@?87)o+dsPpIH<8jJlt|;xTvf3j=Fq^8#->Wfv}k6-}4K@t*Z&T36#| zC$nKxs%}Q|<2uC0N=J4IXP$==8X?FQ!s_Lhi<{mC*7c3tCn?FqQ>0z8wHg+}$I0%i z?#^h8#AglPNp_5vUU3DqkaHfoDlG@cT}iI*MFj+%aqdwYv^U^wR*iYK3a9W9GKw6> z&J=a@C;?N38nzm!_dQy~Fd0b`N!Eml{a z)C)&H)1FF;2}i7>rn#=B>hy<(*#8V4>+w?F+n>a*ZT^u?G0FTOSRldbhc)PJhf_VA zd$V73z&5-M`RZAxW`vT@UaFJsl#qSo=DedXpEm$g({GE9NLF%ooe3oECJjjf%(#+m z>uxl6b2{bH7N3}|RO=)ein&ur=e$RRoZLe);)qdhdKROin_P=-J1&cJ?VQcSGbx;x z>62MoE{ol=fF7-o7`1cby$R`sbeFzOMp&*>^%j@xw!7j1`g}-fdoFT(3JaKDKm7k= zP3Ad|Ge=uzw=6C(SEkmfWP%0v869j_aX^((TA4e}4DP1cuU(31nwhCVCar~ZIJbtF z4@#@~;g8%+v~udsgBwl5m$mHa;<1t&KX)ktx%2JZie0#6DQD-cx9-D{JY{8iLxeYf z!c48V%s?t)3pw;&cC3lj^W3@&bmO<4j%oG>ZsLOjX|Q@h4OPkjlRPhLKg=sBE&yJ^ zOFe{rCM&?#J%lA zDtz6msktDe)nzVQ62hS}?#!qp@pEKg&>i_Ou!> zyo^XOb1xGgRcgNgbK-jW?mPy9ICl@YB!Bz?8^PIXtcdo9a7&{lNo(Z2KKh(QW~SLbK7A!zr2~X^aH`+*2|9L$Ob&$(@nb@ zr@;u{+U7~3;oYG!cH@bE27Lq~#+vgs$pPdjjwcc+;-7PjFp_48(eO#_Gv0rf69#Vt zejBE>Z!H<&q?w1N4Stg5Ufj;{(n1X}x78#AbJ>5cylHQvJ!Yvc&CPvCnMoP-D1wEF zA`exy&R$Om|J}5Lnt#WN7oOY{S;1xY5Cs)7kkYUL1`P4oCEw7Rb3Ww4PUHrY-36Rh zKkZ5vOYxpW;$dk|CnJoduxG%~*ALTsj(<%nq+@RFKw_~^D1cZe^9jBo)2 z=Ath2KL9WkrOAVo<%(vvMC!+tOo_v1S)Z^-P#*(zE=Sm$WHW#8W-*QWSuwUraoK9q z8154qyB?47`CHXWe6NcPtFeOn%y2#7INJ_$>WsK4uvIy`w@P$Fstaugv2IL&z&%3? z6qT)yoz43N6O3HAyvuAa?RJfG^Iu%&)Vco7AksbC>j374C48ZCsT!#;LVL6r1Sg6f z%DA3sA*lHov{_`@HCughYyUi-?nbZ-hcWWMc6$#by%#?jU;F)49yWO%@s$&&2dIkM z5QLeBZJH|=1Sy4TqIH?o7k~27 zw+CWFf4i7@E8Uw|=Z9Sd=_;Ua?|uQ|7o<_em|oT`xxbvbLz|K*2@uUva#ocC(2*S^ zPrTc)-uIybDv7Jr{W)@uLZ$s+EgqPPKm{Ym>bH?mHzJpYwJ(Bp$u#{x@hB zjLp?(YBUJ|P0>9##9f$|n%#JIEVK5x@QqM>*i{$9tgWKI($Zy08}`_X-nt=83lz6( zL~&>^OZY3(4S)69U`~KY*xS{a9J|Uf?=JcAjX(AiN@0ca!`!AMFRS#KzWHF+kf?H$ zzVPf)YpPXCuN3XK8RL$OWa_1bY0~Z<)IIXAJGe{tnp)qSd4}^vmF|wH^5&~#*R6L< zqL)zW{z{)*agU0|)e3gPf?A|iy46Fco2XAF@6;n;`f8tvPNlYw?Y&4_C+(`&mXsoZ-?32WqQ}BAUeG4V4tFQjhxBdMc;V@j3A? zW!t1ByA|9+0l8fBOy}q~hM5w6au8-{D)^DBHCmJtz+5u>Qz}YtMY+{jBt1dis3uRN zW$W;ykZtvr*Q2X^b|OlW*mnJ~UsFHx=8)cBev!I)puz*DP{N)@zH zCFbfPaZYWA{LgUEE`-0P=9543HM(e*203eKd&&1^uk|evy_#P$V%y}BSV`v{R0`C7 zs2tTiWWByqw0o=myPBveT-U}=?xSkO&wA+PA=-Iu{ito4q)uH0-TtE_vU=In+m3Rn zenx%LL7|iaR9fXblz1x}+Htx5kY3bnv`MN`jhgH5-hp!Z{o|g%Om*4zznTU$f2v%} zrv|m7kA4+u1K1iRfHX^|NYwFu{cwwFyu8?DFb7NWUK@$H07=2lC7-Cz8&(J0{3P%C zCbf+O)Rb!y``+s@cq~sE!HMB%y1|`gg660~Qocrt%4(fsqJ7?}v9jqp0>A1aAIJP< zyd-~hwd?d8(Bq91;2P~70=mnxfC5V2F3s6q15fBI^8v1w(rSl(s&hIiKf(u#a!pM7 zS2A?bq$sw-wSr%Ch>viGhM=urxisS~`I21rlmxG7G=#ci`D;2W`jL+e7Gq{<{nDu{ z3bVY@{Tp9JT&rXjf2H>;hWo1vfX|yn@HRm*>{S3C@QaVNDsN3NMlf>=@pgG_LD#q2 z|89xrsvD?$QojPHR6}H`Emu_o(doNQH?kZi@V#gBV$JZdX0_rw(^HvymRoR<2Jch8 zxM(91-tC!WMkiUXK?{Non@!@ixO#=(577J@a4x;T7g6ZrL+>E>4Vrs(8Q4T7UfYGc z@{Vy%2mXyZJC*d0%crPGVM}Jv;g(}v@dN+bxmGYCl~|$6A6ofWm+(^hwV)nOmTqEu zOP_6tj!CVQ-p@m1L5CLV6AItIHb2R{x||ifv;td3dV@Yb(1?JNz9O%&Bi5*23w#;~ zZhDf-hH2v0emsnU@~W}5+F5+}A= zjCqw-{4_w*FSOSeoo5{Sd7$eEj)sc6tOL|i-!@Yq$pZ3vr#Qsjh##Nl4s>xF<62qj zO+&JvyG9o27_qqO%(wh1zFB@_ulO_BCX9Wfc?^=6#Wh!hKp?ZI{$J5NA8&Tz71 z*zUl}@_$zqz7q|+e#H4>#(21W8vhz_I^4lOANsC_NUme>URoX!X&C<$0-@W!FSZ`T zm*A#C|2tYnw$NihWMg}&=*QMfu$^BlWkZq`mt@ou?b1NJRo7?JEWa%O^|r9VRRTTeMq4-ZCKB=9yGW-LdfHRPz`8dh`&E z3~|R3pHZb0%aWHOHbed=qitK4Wyi8U2n$fdUiPX!uvD0zaU9`i>7-9cSH@_Nj!1nSGLej;*)Rg*IuF%Jr=R} z9DmT|s$b|+?h@+uT#bfp>5nZC|49Gp^7Pz-{IKkeB{2SsuR-U>d>IupcZzI;b)@S^ zVHlr*3wfSdJo)c86fClUk*^rmdl(--)7xeI!Vr~7-kwkseOo{!#v0z7hL%4{n4Hqv zHd3(ezGh4A*iQA^`#Wy}J$9wYcY)w1P3#7aa6Q+)vHN$LbyOtA*!lHJu}MB}?bG6n zxGNTGTg*SIb5Ze%6m4D7nwyk(Qt-Gs%8?8D8o0?B3bpvIEsym5u@re2_!;)Se`KIN z;tjVx{*t7{C%Jh&xQkVhdqcVT@XPJ7lcIG()rfU^#Wzi!v{J#ob){ddPOl@a9hJL_ zc+J?Nx3KlSRmfK?IedX=}G;ak4QO}VwgIF z*i=^dRDv8VcOIRL(BcFQh)kumX%o;CGwl$QPBY8wdkUJW3d5XIWR!P^Qz={}CUfo< z;~STg`B)7f-{AtcYk#xB#0J|~Q{-p06y=O=;OUB>m&B7SY=x)ON12+)JQ0;rM-Y_1 z_Pz#zA3uoW-oT%8RLJXT-Wb57uexfU+BBu7n_b*EI?JS|Dy_*WY4})Eqj*J0WC*A) z5$aD)K)8B(N-lpoyE5w}yTYF2p^)hpNTU&OVEmack<$BH$+j&fe>Qt_KDV@sFGCfs5ZCY@Pk-tLY1^x6Ce`P6cso?{C@tv`F_|*&U7qnB|=2}sW zWPw!I3@4B^{y)1H$I^i*UQ*ZZPK0}eLtU^|@yys-tA%`*LW>H+omkh@|H!V*ueGir zd&I+hu#VAIa64QlCI}xKWqTAu(?bC-^4~}WX}WbkHW{v+|49$6r4qBSi*n+;#(rMR zF826@9aD?>TO}f2NLS=nzrPo`Hav+*T69|Dm8Tzg(>#mef_a4Dq9srtk|;^}tfWfq zTegmY^QQ5ChvL5ea8i_5|J~x`)tXL^ZG2K7*Y)R<(lz#&JJQs-+0a^?=R{26K<4W_ zi=&z#Xr{g*CvI!We{6YNwlgrKXafnarzVT(KMuZrej>BsE;N#0*9J@RYv+@oH5|nR za=`^RvU{>?)|20iRYZeWC+@?!_$Oqp+`d%4bS(rD)Dq~=u3vV%>>vw7zqUHrU;F*6 zvoqQ{Gm^J#P_&v~^1kA#Y-vR4Fsb{=dMlMRwQeBJ>w23Vs3JdG166`&@^;}Cdjl2L zontST$-4u1Xs)bMMr{KR`(MH%>gq!$m74VOCvPe!Sij#sV&xgdje3QBhjoFh8y{1Q z$;mNNF3TVz(|fcYlt-s0vHHylBWE~_b$X04j+IvdQ}?F0C9RLbMYiukMz)`p1$kuVQ8~txv|(#CqHtriHcNb(=TBK(Kl7iV zRXX>mV?SwGT^DU>7hR_k7^z9*my+R?+U;@q^6Io|$uyl)Zf0bsQq-hYa8S6_ggJq} zxQS}NVbiWuQt<_~tH$Uy3E`@HD@U@I6~4oJ53C=lMdZ5_`3feZiHfasDGDmMjDTU_ z50=do@)5S}0{4FwzXj?Wer*}H8NKG9e@4vx=8WO271dT`7IPPZmC)??}&6JyM(P8R3uO*Fl1=3uq@0H2fX??W4eP_g)`hH!1@UnY?KF3xP!3b8k!`Sv<;b}2 z=f*BSE^@vZE#y33KG6e7ovfN@)6U%hS52nNuOb_%U_qk_kf@vGcwlm0mdkPpP&Zgr z_d!+gd|1kzO+}rPv6jEYrJ0o=NhdGc+z$}5JW#fk3VrEanYJrsTN5|pQfnxEt~-7( zuTy-cQ*@?ZicmP{IqU}wQkO`ZXD8P$C^3gMrfl)@*$bsGbE`lZ&LvY zBh7ImSCJzGQ6qrZ5opwiV%%=yLGf98(OE?Cnbzhs7pP-FJ`UKfsZQ%KE5){ob;F`- z|GaCvQ%!UzrN2D4=eH(v{P~uVVV;Ii{49ju4xh7tvEkcF0jeRh2}UFKDPmtFw-ERK zQ@XaXeE~xj(ot~xIiSM3Z76GI%Wv(ZBgALj#_FLy-=Bg7rusTE49>A0`3^R*AHf4J zIgem~CBCWDaF;_+2X}JY5pvtM^4qi1eTVUq z4ra$>dfl5vSvPsPMQ664opapcGky?Vz$4WbrK?=hAfY@k{s7nRZCpVem9$#fyg)t) z%-u-+z>dhNc)1~8WuGip$Ul2^Hbows^JOFxEU^14(8Kd=d~$fzdZZUDVLcM_qobE9 zSA48>4d27_Xo%OEStpBspSo8~bTY+5t#vHLCBr?L)n^9oU&~T`xe(fsPQTL)CM_mD zx9^ua1@#c&N1O+`U)j8AWJ=_Of}b3kDZKvOOn?t(<*?9<$DLShxJ{tt>L^#UC>Za0)39@y!7zHw%Yn?+UOa&!F_SVY- z?R6hD)!E7YdDue0J9qe$b$aTq(^3Oo=MGn%wpBV zr8St$rW;XCzP#&Ru2>o2Tn5*pA~6$toD5oppf*A`POr!h{3yFVenkvk9lCZNZ*&~c z&nhk@Cz#SEFQcLkh}>J^+v1a8sN4f__twYF+eF=2KutdDfY&67eZS^)YB~O;cdVW% zh|X`Cp^;n=$Un^ig6u&2;3`g)O{Fs+agZP~MLU?sC@Hx2bNgBCRG34|CzBDgh*<%^gTlj)Jne41?$R5C55ni7;noGU+VDvd zl2>92Kb}6eFT4%E#gMFgRD2-d)DF=NDcObR!_ONGIt$DS7!mR)puY?!%;cg7Z2!${ zR=eT7QRR&Q?Sm|?oqdBwj2#f>-^$G7G+8sfFsWZ1;f>=2i*B@7C{49vyeJgXr&Mik zbXyR)Rmv_HDvabjN&T`L z9~tGDKqDZZI+$ zcW{{L8$|>A*j3_v^*SmV-c|M+l{Q|NU6;96&wUVLLG~%sX|-xNzROOzwD>(&Wy0MQ z$*F=F%?35tgMa_7iO2l;&S6-%zdg#0*$l89RA!fJ&|Nm+dTcuMJKOPUX`8 zOc14<`ddnBWfm|Wu#U(r*W#oo`}22x=QAWYm><#YOkFX`gfvf{rx@Ng`rBGJ1t+iQ z85XP-`2a}}&HIw6^0&+WQS}BPG9l`Qh21qSx{rk}Q>!{FsJ2d;Z48$zVfCB7>?3vH zrC<0;!5KujHyd(z)pXIMi|=b3V9cH$@SOR?g0mf5HA31Wchh|@Aor5f_xnU9eK=u< zkb$i6egmC!vb$z%i}BH0mgr0Xp9-0w^{`S34^zy$)~g&prw=u875V{hRgNGPlGu&8 zy4kbbr&P>CE>!$(=5M`Z?Yc$tvbj!kwSqCr6bGfaTj$vg-^nOr-X;3G#;d>fpQeHm zY-E1CkT5+70{!r-J#@jnppT`&Q)HJ&DBtH$rXB~lS>$VxO1Hlhx9oa7{ ztk}K1!@c*4v)vzdAE5%z-`~UPnRjxVE1JpM3;Vjr?@-4Lc7gG$-%3xx^>H#b_87rW zBs=+9j{z=b^XxJ8xn0jdWTdMT>A0!5Ud%xdp=Yiw6?9Ex!*Z56cB7gM=@2y&yX6=(g3-M)fzJkDSrz=>o4AN`XYnF(c$Gf{P<00BtFDT(z{O|OK0sSM_44;{c)qg8vLmjDgzRZ>< z&I2o*8$@-0K(@;mD7la7w0VE?M#i-U73mWRbDy%CiiaK7X*fyotAW-0Mgb%RQV8jd z#8+4|C--9~bE|GM4baRUQL5Z`mQ=_t9iQCc-9Y#|b;ch}T9W%5@UNJaK8%~LE`I{J z4n~1Du-%edL^CWuh)B@4<9I4>geAhrk9D2dM86|>_4pDFPJQ`C_^;CZ)px5TmU z%K70*;NH#LIb_!ZN}9(lY2M#O+%D?vaCkYFTi4z(Y({J8C}zpN$yN+K3`I{kFZ-{ct8eFmm}ma(PO``#?>7x`wJl!Wg-5m}==*GV;tAvTNtH2Bv%q^HNZo#pN}1>GKSF3tJxM zUDjv&q&7>+Yx>cm?J;s6`vaIVGQ;_$MO$Iy{*Pyml)R>d7H#X1`wGu@qB5M{TeJnd zg%Q((DdRF~FnO2B`aCTOVR4%oM|5$!8UHkh1j=?wB1GyvV7k?5`Y~Yot^l&r)z5N7|E!$`=%4c*Alz%q_a^};>1`1Q2E^kI2?|kSAKtEkJ>GJ{5b!88pE?fCW zZ?;F+No};3iFO5~mo(G z54oF>Rz{<4|K&gaag*aWDifZ~hDnQNy@dHo%0i!&QaB`Igj}sAqaXVdk?shy^3XKTxvQSttY3stKHtDlZt``n0})+0Ab{L|^<7wsx-JD-vByU&oLPm2=S z64`q}&v<&0g`@eMc?EF^aY=FeGTUZb;h?qogL&0!%`F z+Q95Bdx(82a*3R4ws$!cuRES#t~>7UQoOV9={qU_SV~7egkFv=Z|?Ie3^*En=px~i zQ<9Sd551c&Ds3@pAe@bKkPn!gM8zFs9IV#pY;d6{CIJ_u;eDFCYMn-7@6P+X`|dUZ zc;z{D6(jHZta$a*NcsEJc#X#h0g7KP_0GEQn{nLe2lmeaU5{olQ zbM&ITi=^_^zB=k>Uhyu%3B~0v+!>K~d{ef|3AKUhL%pF~P#UNdG;A)e?s%Zv#=NrGyIvk37>PRt>G9TF5%Ef*=s|GB6rL z%Cyw`OJFpP6yuA03bag$${_O0cVPMgIF|+~=3e7TB z%`$RLX6kYnRXGg3oJe=o3jPYs>+h%BmzvBN<;kz$!{~?xOhm)8#YULm!H2OBCKzyg zTzD%=kIf4nn-4rTZ+UEZcx+zs*s$=}kn!v|e^Ddku@T|1!Q`=F;IT<*is#*-DNyB| zuojpo#oXh=-s2%3oj9S6dVE?R)Lx*3DzKV_kjy*1`0 zv@PDPQl8K6Z#SeD(jy45aC~cI!YtMj-_qqp?UU;nbS#Fv{o|$Z=B=#BZl4IssIhZF zt5XJ9bg6X*>Fvin4ZY2{ZF!DgmE5M>HneF5X_yv0<5Ym=TEgX&)9MHtuNZ?;XC05} zTtozd21RsAP-iAtK%+|lDMfrmMf&SXf@y$&@-jFKL5`~O*Pzl3(GSt$wyzMO{|9Pp zeAXur)KhIVTd;GA^{y2%YX`KO2YkvdQis`q66^tX0DIg9+s6I{+yy?QHIf*qhZID5 zImKN9Ce=JiOyzwhbuOl|_aOdRG;m`C@L+aN7$JPnjA#y6xp2JbK>E#|ckN<874rZR z`TdXV-l~T}E)~LSPCHKP&%vn9>W5#q2SJ3O<5d}4=h;ld9ItHQ{2f!$ zm3fTq5>G#<4!uIs^WP-Ht{KvSDg^Fv5%7qif9zoUElpZ|S|;XNTDq+bK{=-2o39de z?($-CHAfd^7mU}O&=6SCH{y)Bu9WWN=6J1FhGJTa;mpIp?g=p|g@J9B;CoMR!HWGrJA zzoV~h8bAC`N77Bkq~O+{vy(({f^t8u{NtvbPP8Q^QsFeVNKz?y#e5c(e87CP4Xw$) zaoVyyB{7p(9g+;z4N6&EDioblG0BRlmb3eo(;?KE8*op6q%9diiP}3ao95s7$FzLU z56W(d%MXfZ3C|xVy`JCq7n2q@hVIxl<n>I&Q~`eOrH&{I_Z_$zw1{7DQ83z7jIo zPR98ofcb9kGp*i*)~3`9vv6%hwsz1(9op^O+n`uk+S<>wo0Ef>7j=ZUb7VnkRfomX zHkYT)NAnLgxithWw(X|v!y96|VuL|by21%=L5*k$&RJOl9x)PypZi}CQ$TxXld^X= z4p@KeZg4Tc(HlcO^OAA>9us$gzOKRY9JOv`iRr-R1Wn1jGTJh1383_!^C=htCc(|A zm44E3QFKcORjn^*C0ERLzPrI%U%-_7>6G6w9fYq$vZL z5L6;xR3gg-r?a$}bAC@|&So{k;*4CXg_lc+`MNy&hbe_U7?HAtU@sij-WkR&nf8yzE-m+03&d|mF4}+FWAul~@v6NkRu*~K zM7t4vD>-yfynpewHqmB6*Gy)-$i726OBS}R5=FB^JPo^u^i_~hO^Dv@^AMoyx)KR= z!4Eusb-iL@#@VR|I0Nm=W(~4~6ZTlm*nJQ5e9)#)-O)=TP zY)JB&(&d}!AGXt*$m4T(I1w)qP>iNx|8O+7d-B#wU9%n zvv>$Rst{%KbC1Kth)wQ&2YZC87v^2RCBpKMaH`v=r~4Zff%Gu%tPVowka}vCj*61o ziq=mfC_YH;)|BL)E8B8=`;fl2y!KauQi20kf&*ScI|WTTu9Zu#*2P^4&angTvBR^i z4K6y`%s2@34=t_^N65rC;X@)s7TEMuMHiB~=D%+q(o;E6>m_IdulL7KV9r!N`31&2 z#Xf_v!R$5{G$*TzYu%FT-OV0ykGR{F>2Osl4_=8n!0=v`utYO~#Fd7xGg=q!VT=n} zgxlCkHa!zLd2A?@q}Nul*H(4yx8?J>{`<;Z_vuC4=1}nKINPUO1tOk^(yUT>-Q z8O>~$l(;e2&Cv8aURU|z8JxDYs4mHe5Ix9A8`0m!pk4UzD!nNRiToJ*@t{wHH-2Sn z8XnXjBk_R=robz&R;X@Kk)h&(p(li)w?fF@ueN~h=m#7l`EAcmKL)#?`MD+gVc7Y@ zu;QmA$&7w!lFB}ZhIF9WfnB}<_e#mbhWUoM=cf+Fl_F^W;)atL%L?J~1nGw9DHk>R zV<77a>9G!E?xXhva0BBMjT)OS2v1IoPKtyUCfrk6yisudtqV&mh*=t1xVaJFmZfoe zi&PZD^AyANyd~W8#NWFhn%I|^*tac!VHLo*pV!5c@^X~cVmPI`_$3uTl}dlolnt^* z)6@>KlaR--=tr4Gt6QXR{B(=j*bp>Rnq>IK%KPrm`#&#d^dX#tYNtcx@~0!^@{qFC znq7805e2g1zWpo26&rAW6LqT65u6{KpH#3~yILzSMLR*ONpV1cAYhBSmA#c!AqvWp zQdgd$ouSoFLMdJ-ro4a9deCCj3sDPEJKaw>NMH|sc=hm#u|OIk4JmPBxJ#MR4KWHa zvIk2SOBa_MKoL;3an$a`ZVJim`R%#NPr~Xw?tZj)*}7v76eld$9wD4-i9Ji^lpZ0} zV-GZA4`yF$#W$CZdFInOrUs-FjyFU`s%d*WnU?}dO|3xs_C@pRCo5W3MpD)Yiwbxg6A~q zILflp^tUPL-Jvypk=)=1Mc)5Y%xH(~GSd4$Uus8M1@DS#21CATYR8)nM9b9idBqb~ z%WbV}!W65RV*2~+cbf+4`h(hoG4Zn>(?wT81BXwAhqmJdIn1}Yd+7dTmm=AOA}{*zl&=rfm3M}K3wsF2$cW6gumR!sc(&rz!5 zPhDGc=&ehqT(iN$b*Ubst(O5mxy71fxI8)tZjvm;x7-KuYdR%V=z+JT7svKi%qxMA zO$;6WcD3<9JCIE?Bs1Y!RFyhF?IF++VOg{T#1OI3%y6s*woO#wff;${IpM5sf*`g{ij+FF#J97+wAF)^hdRErC=1#PuJ z5<{{nM8ATz7zEs>;6to1i!Nb7j|KP`0odkWkHw=UVz&yCPpjUU!;d;kh9sVY6@rBX z-T%OcxWNispXs}^C|a#RC1Y@q*gc%3 zEc9jM^ATNhaL_i=h8Xq#b@T*T^<;u^Aa2|8pN{e$PgKXxtEIrVkcyg$yo#Q)p6H&D zo{ApCbMoXuPup_>CH6&6Y2mJ7wENOgHf07;2DL925BEuX&wbCgp1(asJ-9S_{C*l9pI*y#n(fnVrM}dljR(A*JbQ*RSit@?025|iQpm6?RaL#q6 ze?K&ZQd;NuI`eG97NO$_?)if6b?#%a_{^vO!1KP4%aL;DM=&D#Y!e6<4wiq|0K%n% z<*`oLDc*J$g*_MVyNlMJ3&QTA#OH#zo30DsNhwW?>;HYsF`;ZTrLCp zMN#wvvJU!>0-^w!M6e1f#OZCqVW5tz@;t3%I0vfA?=MlMACYeASZtH3UFiu7=v$njAZozt-#|MZD` z{aO1{toGnxE%K?3d-4Aj_8ovwzVYJ?r9@VUic`tTI_}Ql&Nw7HDd3}qj@~Voe z3aX0V_WBn1zT3+UxX2f&vuPNvZX_s_sAs5a(qN=+p01t+o`GeCm#OR+1x6V083-E2 z#6GStxNfMOnl)=^VyI|n0DH4EbH$~g?8abbW~Pu(cD^A`WLjoMaM?A8ZjK>?%ZJR| zU5ze1*Eb&wFHnDhfZPbns5c}=W|(FgW#-&{E0ZOfS=^w{(B+t!wk4nWzD$2GbtZGW zt6~OesB`e!#ny~vmm0)KtBW-=ra@Q4AZjL2CX?Tgzst}?A1-9EYPe(I+J#y*D9wBV z#`i#&GisV}hS$IOFNWfhAHNXA28UQ7;X z_<0Z36PgerbBn|4bNz-e-UavpUe-swqGn)cly+$5S(w-8VfEz8i=b595Vv4GL4ld) zTJLSucFh2hNuN^;P&W&2C+q-)Ah zgnC#Abmc7KN`J@LN{Q{Y<~K36I?WlSQwkz)0;kk+-bA{Eo9f%QKkC;#*B;Y7&;vp0y{k{0tx1J6!)_H4gc;Jy{_eS5bO-+fA^iu`&OeMeEQl z?%i9Db~aVlrp$VW@tCmO1~@20?&A>NqO{?Y^{#i&?8sj0PHe@tM9&AFGgu6LWzVmS z4`=HjEi^;8$*7MkH}vIN%|!BIi)Ax|W9U0X@}8iCk3>EVY!_=9^pB?X@& zD)@@fI<3i9*H#=FusV1R$G*-1ea|&g=jVC#xHqhx9vm|@@h#^(J#=Qi#1DmfiZQhQEA!L!cQW*?;u1Wnu|vOJzB#XY8#N&C6rx#lVfw4ZZFt*W+oF595OmGH%xA zg$?k}Jzuk56Wn&$F5G$O{n=-kXY~9##{QtW==o1;%-e5vLcE)Nx@z-U`+wAry(${c zZ|%bmOwPN`om%^_=Gl}h^Hlbdy3B-M=~EHR3v=&RJhDB`+sz3GZKYQ{+qb=b-Sk~} zIpz#j`EFmg34wl-OgWkG-Md^~S0_SW{!LX7%}q`4_^D0Q^`voKbpa-IhGVF9GFv`M z=nNe^$w@8fVp5@QMw?4gcoIv}ite;7=lRw!&bykfG49dB8#h&kysWZ%tH;T1CN#Q8 zn$n@p8l?pz5^S)U-?62%W5hHSc{SpLs%&XDt>}rv!<2gmg*oXblkpA~HBCjzQ=uII%J3<1>mL@3@nLW-L8QfJ`}aBY3&ki6GZvyA#3vx_-ua%MNiHxXfTx@`|=J z-}$HYF)6^61|FF}7MtbtNQ+NRP&t1=^g@`VnSA=>RH;Y&Ze09Zj;TNo=Fy0gH$&=8 zvZJSzDh$Lr8&~Nn^xk%4F;9MWDsp=T@yNNI-ZRVK@p>o)xZ-$~y|z^3mMphT)=*mU z>;;eXp;Xsdjuq~mi=*E-b2-A6!-ulgr+2pQBi}GiN3U9X(>QaVfIY2;XIiw^uVihN zAd_@vdR7E?WJcwDNSJP2<=e5To#tEsI0x>A?&|rbR(0>a7Mrb_ z!LJktcgoAjaZk$bR8%JKrTMn`hP|`DhOP~gzEm?7I;tFg@e8nqB`BQhq-u8Xg&WV9 zMm6bMAFnHn6&G}$<`pSWXE&LMo@l4}Am${XZMD;_^=?P~ZJItuJdc4On^n$wY7ro2Oc@lYt&B%|zlFyh{xcXrpi-XM5a1o#B znLPB!Od4-{(_P#f ze9!kO=9;yPXrr6i)o8ZpaWmF66UABaR;e4Mquce4 zuOy^m9Vg}<(0HCMPH6hU)SP|P;> zHoI<&xFlP4@bk-yH1aOjN~54voKgi`n(Dn-?8UBC%-Dw~B#TvU*WAXq%RWJpBnPfq zR^UH9?t%ID#CDBGb_IIN2i#(vIR7)Z%@|eUahc^&$ev$SJt1H4@Lpe6U20cUn0Z8_ z-e5&p{kl+4Mds3NVPzNl$Rd+(7{~9IDAjH2%=b#g@gF zL)<`jU$`C?t@Jz~K_dxi#BR*fEi^Tv$$>r13la%+ET~VUpV8-I-ky&;3R?BG$%MT?8gtfJZ%Sd+4fLx%~zw{L&tEl z-WNq5y{&UavtKO|tQj(UDs+QwZNbzaXoj@#@+KuQB(zNY*}>O{Z5Dr-i4a zus`I}-Io4WZ&9W(MyHGl*h>mcO>>ORoI})vLp5~lilFQD4HIAk!u5Xk^_&Yv&Obi( zSC8r)+vP0{_*PeTif{aO=yG0BYkzCmu*^q~k1`YwvWB+44z^HxuXN9d2LalI`^K)&~dEyU|0Ij-5KvN?LwQ&&Z|3k#9K$^o@Az2NZA zyCRp;93<@TaD?SXDIur*Cq;+FT0~A(%@%FMAirzBet`N}{lHJ@m=%5C8}M+mgU}zc z#Sc%nd#*frOv%izbP%I$G`R)liR5Vz2G-YdvAATxKkPJoei%FKJY4@v+@jy2bGUZ6 zS-xL>xN6Y1Vb3mHKI4|&dB_Vo0aR*5h#PMjFCTw|4UpWtwG=IQ zuR%+2Jr$k0q7f6GFZ5lZAuyuxfm5RTAJqy2A3uJ4416CQ`B?YSHKYCO-3$hO*|gJI zadBmWtHv|eGURDAj@i?kqy0d0?fB%e;^R8UoDMmwWEp zqOzY_is}af*SK-ty^{Pg!!xr?Grb_!b9A@Ay01ctjfH|{0`uENPd^e!N2Wh-|HwO4 zebLJ6rGDG5%1x%i7wG#yaZ@9bCqT`J%d9}@M48?%JY+Y*E23!XSGYnp0_7-}x~s7R zB`T=!IIxURKPq1lD2NmWwR2=BcL#flh?*Ir9c{tSS6zI*eZq17(qX8&sj-;jShMl-!_|3I|exLpj=O4UB z6_5MTuaFf%{tCz4DR;=#Ab$k<1ciyr%MCt*7NF=davlfMqhAEk({i2$e?zI>e|(5@ zg!hu7s^8-k@(s{y1yy&7Ex8@^8ZjbdLm}$^)kU%rwJ@5{<)1-k z1YJF9ay-8Y73F`G)?|TKSi$Ii_D^yoNLbOxgCayW1ZBygA(Xr1F7Eu}Xa))wqsgg! zc63fq_EBJ&+ZI%}e>Sbj58iVM(EAQQ$xlG%6rmoJD`YKDtlYRec~UWco!ktHRfKv{ z*vTRwGdZ*{#fY54ozH+iM}ac-ozB02{tz^GsPAz8C)B+Mb4U8V^Li?-`OU48y+PXw zYwi>u@(ySlF@A`0n0%C*z%&k`C^Eun2q(tLLFM#IU`iu5;q16L#gY+zgg`SM9CZE| zoR07nb^EaUv2iv=_;CXL_=})&x+Nh>7B}JixHQF?5q_9(WIQ0~6%G6(p#ydMs5`?r zgb{v>KsO!{RDOC%hBC`d;2M{r*fF{v9cLiJiJ(b^7I(@32=8A$&pWBu;{R%$?5Z$y*u5SldjHm;(m!~A_?4ep$_?^5v~-w4 z`>3|?qW*#umo$yY6*~}6xLJ-p@>52n(5Rgxvv7x>2Fe02pQ5^7#0pstl&YZqK+Uog zA)dykVf*D_37@Qy^wg75h6;)GM8-*^N!ms|exL$~ZFi)~i|thgg^ zccq7{Mbjsq|8nKtn?EDpkM+vZQyK1@`Rpic`Q2IgN}bRj_Z~SijIRacKXj7)nD=m* zwU`|nFDzMR-i-i~86=+(}@}|BYUT(bjVv?=M>9O&vh-GJK6PO1M{b(cA&tQ zFDzoR_ifR#xf!2HB&2?xRV@D@y6oo{&7p=X{nOwb&@ZfJ0<0?NR$`c2)mDC9y~hjf zC1<7lvh449_{8~|)@vWGYJ4GZgF`1mFC$;}`IO9@Kl&vbzxSlR`%y`%#_ZIku%eR~ zI-cf<`IP$Gp)*VFLDmBcyqFA@S!tmaZb%Mo46NB4a4bntbnC^Z(FcjjrqK`}7z=e61nlXYy2lFRh5 zk@r{~vFrq*OFF_xQs3zY-s_nNa2NNvcQc83Tw=2}Ia^)cU-d4VLmr|%&S{mJ9Nu}% zHhA0N(NLdTAI zpIJ*drbDB{d5h+fEcT2b6xYVMmP1m1!A87}y==_UAextVq3p6Se{cPlD-M%VQ7}H^ zWwiO@dA0s)!+gDFFOARkZCw#;%$^_he@u zsAD5GW95P-_>JY$KAmlrDCHNc_6dj9{t6GlWWk%nz(8Owf&ff8{@N>CH zV2b`UDyPCaw~1E&X5x3NHO!Ml6S< zUK{(+NpgMjUXPHLmc!>u*->7;-e*O$9>6Tuu$_Brp`R7t3C4)*`12p4r}YcAjJ>5l zi`$>AKWq79eCrN#Pr%_U@@z?B(JOn%KtH7@lrTFn%4|ktQ2YwooFmq7-C_8nfKg&c z{nhprr#ZG)Kf<$JZbkErnQ}ZDeU@m9Q{+J;e4012F+bWID9V;+!lgB1Q&O6|_m&$D z6>NLF9QiK4Ns?|Yx_3ATvC}Jg(({US>zTQX0Fxd5_YE~#FM8VX9kNlUnx7|E+1I)S zaB8U&_f$W6FY#`YnRat`abA_8Q89dAsHt;IWV)xT`?E!OkSoXC5B279KkOg6+6 zom1~yPt+njuQ!d{o6skBAdHq{iyamrd>^`fn~4rhL7pW@&7YP$+rtW#mqL3R!$&Fv ze-0VgGi)1>8@E_~?po}1E4H7b$!2D7Nwn-8P>e-MCdR0plJBv@Lf*(+e4p#uWF$50 z*i=mWV&j4QIfgDjD;lVQ*^6OeBdrSa;IFcJKbRhTt<2a_5%MXrwKg(kBl+3YoJ^x_ z47PoD>!-&J8Dm~Ie}QvemwPpD@ywl{6BVK*`gzylQLq5uIzs9*7ef1=g+BXHd(Enl(-8CK=aR>UZN@s`P8) zzQ0Er9nWb-8YCq2*%ME`_>|=3BlG5hnO4l+rFz;HE(meSNn`SDMp$s~o47o|pBf;G z)c5u2jL$A2n0D#%aEcrBbMt#o1iuGsuB|>jE3!~+_x#D3S>7uI4-C=c*^3`(&&FDg zdGVxEykBWUq*F}^ZxHEv48RISGxS^2Ur!?44Lxc*r{u4w95J3RLfTt9Apj7`e&^%dU&*gEewt3&bjXnP+t9f-^tN zV5M7mF};03{hktiU9k@vw@2}8dQZc;%K8QPU_LW4QWt!WRIxW4eb-K)&q@#`&O1-X zip){6$N0zIw)+`k9MTn*9&9AxA&aw0^a+)k<9HZKWB_e zxi+i%Rfvs=4#e-njGZ^%uCuj-i!fuSvcZNfvpX zlWfx7-9BdV!|+qD;4N}Cl?81k<5$`DK5Xu(hbBIs9hXML-PXqQw@#0Z z%X(kv6x!xn-n`z@_dRa6<n*di>^(H zWOK~OV-gnrI!>a+*yh!8q2y4^ADUH92!eaT?*X)Z|CNx@*llO^Jlhz>xUuH?q$5%(|v4>GP=qgU-&^ubVDMVihC%!AvVow&-;RIjN-t(=V^Z+ zKAtJ3ec`u$NdM=8MaV`fp2!ib+kTgK?tnVo z#mkdzN~Wszz}=SV2)CnKm*bL_NzagJty3CXpI1cu`7wgDtX&0;_Md-w z(($n4NykVh4l`6il4GJH>jI9}Hab9dkfHxV|IvQdmq+K1H3zOeoKW0WSWfaz+DY6= zI@Wf$?LnJjTXh?6TT+{4+ejO8+q1SCZS8I8iPnkMNn=T@iL6Pj3jB)vsC0#NrF6w~ zl#POol8s_QAd)ujXxyndTJuBZC(LQg>CKOb1c(NT`ilnT-p>ul^~-&j`ye+k*FQH1 zcOMsk^FuNY(hnXPq#HawczW>g;ISv)d%fFs+K#sQw;5~uaC)5epz%1v)i_e0_*N+l zrK6yuWZ}OnnflRW%1k%nME5}3a+_-+N8%49d2y~s3Z02JY){(C6kaZjX!mVb!~YW5 zD*Rr}UJX~nR%4sL8e0lYDuBCTIL)?X4jt%kEAzemR^$I?xho9!H z^K{pD{fxiGSEy#YRjJ9^tL-(n&~w#6i>pIXOBpB}*bk6^|o<#8B6jsRzQU5_Dq97@{?RZHXgM zK}3)l=>Luj(CNDqNf^iLI4pi2PltfU5bSU^ASr;69-WvT#>Ng1!5suSXzRN;IXPe) zF#uO_IwX>g%Gv;b?Ygp-r4vZ(IvO}(M{=hVqw=OoLa=ip;R*X)D^lemfh5FXaDdFx zNeyFXV@m?T#Kr#D^qp7O;YuF-c0JA^4p%Mbj4e*9II{*;_4E(_Gns>TJoL<@0SH&l>?&)l8lD$YpDYIXCUnq6=bcRm4l4^baqB{;JfO#Xu%6a>sI^C zOV^t3zId9na7W*gk#RN6^x6Nx$tC}(3&7<2?xQLJ+V_4v>hS+o+&^(q050HSRG*ii z>Qj$uCKLhhM0FuEkhmyd0pJCd00Vm%oVo`Pv@mEp%l{{at|fu$x%*vGLxPBRAy{LG zAPFjSYLMVbfT5_acHk|#mNuAwh`4X~KW+Qlj8bsPf0&UPMb~k5KqTuD@Yebm5(sOD zLlb^80$Bk;h@%b(ZD&pT-P(s)J5r*8+wpeW3l%I0ga! zjK*Mrj({LOh^Boqkw3#(1fcmFV}Fc*EC7YXfiP4DB|2GJV+fWw8w^NJ9N3T`IaOdo zf&d5q&v{@V`_fxst!*uV+yG!p0_fu6U@8^Rfb73Pzy~e(K?}P7CMC8129-Ey9RQ&R zgD@0NnNSV|s1%rcNU}}X(Nq}HbY6VM6futp<6)FxK0eKP(xH|xlq*f?c z93%~)R!KMvB)wlHrQtvj0J2d9pr+XaK}4t=so8j+H8p4djYZ9*``A$EpM?L+UMRc^ zHObzprTy>j|T~8*;y0tL_C%x1JVViPT*;nc#y8L zD$tFA9SN9${zd@Z#1qgU5s)(8-i11aN(laASZ)LimQEZb0b!t{#?Qe9xBx^F0>b`= z!ND*|K-JU@g!>Byg#jx5H%tNs13oGI3r1}Kj`m*|(EGn(a4=K?@PmKh0Wb)l^?$*D z1_YRe{{@4CsZRMHm;_w%zqD|1IAE6l;z|AQ{v=@F|1Ap)aPPlpNd!ya0|8;*8TLQL pNKoBlKPlq@FFZKbxAOqz-`^9bC4scBYd9DVhtcuzspzQE{SN?6D2D(5 literal 0 HcmV?d00001 diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin new file mode 100644 index 0000000000..82090ee2cb --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml deleted file mode 100644 index a04b808966..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/postFileTest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml deleted file mode 100644 index 39efdef351..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/scriptValidationTest.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - assert json.id == 12 - assert json.name == 'Snoopy' - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml deleted file mode 100644 index 3daad673c3..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralTest.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - {"id": 13} - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml deleted file mode 100644 index 11aacdf5a0..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyLiteralWithVariableTest.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - {"id": ${id}} - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml deleted file mode 100644 index 8cb689bf3f..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithBodyTest.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml deleted file mode 100644 index b2b002aa24..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/sendWithExtraHeaderTest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withActorTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withActorTest.xml new file mode 100644 index 0000000000..ed2765f31b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withActorTest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiCookieTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiCookieTest.xml new file mode 100644 index 0000000000..a051f6d1fc --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiCookieTest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysFromPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysFromPropertiesTest.xml new file mode 100644 index 0000000000..e9ddb58090 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysFromPropertiesTest.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysOverridingPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysOverridingPropertiesTest.xml new file mode 100644 index 0000000000..43b0053054 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withApiKeysOverridingPropertiesTest.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withArrayQueryDataTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withArrayQueryDataTest.xml new file mode 100644 index 0000000000..d2f4a05551 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withArrayQueryDataTest.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + tag1 + ${tag2} + ${nick1} + ${nick2} + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationFromPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationFromPropertiesTest.xml new file mode 100644 index 0000000000..770080fb5e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationFromPropertiesTest.xml @@ -0,0 +1,76 @@ + + + + + + + + + name + previous-owner + MrX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationOverridingPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationOverridingPropertiesTest.xml new file mode 100644 index 0000000000..21a4f9ee0f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicAuthenticationOverridingPropertiesTest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationFromPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationFromPropertiesTest.xml new file mode 100644 index 0000000000..1645d3348f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationFromPropertiesTest.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationOverridingPropertiesTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationOverridingPropertiesTest.xml new file mode 100644 index 0000000000..1b84deaa98 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBasicBearerAuthenticationOverridingPropertiesTest.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyAsPlainTextTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyAsPlainTextTest.xml new file mode 100644 index 0000000000..d5555d4947 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyAsPlainTextTest.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyFromResourceTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyFromResourceTest.xml new file mode 100644 index 0000000000..cf2290bf08 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withBodyFromResourceTest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyDataValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyDataValidationTest.xml new file mode 100644 index 0000000000..10f6bd7964 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyDataValidationTest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + {"description": "no pet"} + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyResourceValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyResourceValidationTest.xml new file mode 100644 index 0000000000..93ccf20f5e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnBodyResourceValidationTest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnInvalidResponseTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnInvalidResponseTest.xml new file mode 100644 index 0000000000..437a5f5af1 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnInvalidResponseTest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnJsonPathInvalidTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnJsonPathInvalidTest.xml new file mode 100644 index 0000000000..685ba5e94c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnJsonPathInvalidTest.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnReasonPhraseTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnReasonPhraseTest.xml new file mode 100644 index 0000000000..2e735d0b00 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnReasonPhraseTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnStatusTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnStatusTest.xml new file mode 100644 index 0000000000..9a198cf628 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnStatusTest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnVersionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnVersionTest.xml new file mode 100644 index 0000000000..fc6ee9ae54 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFailOnVersionTest.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFileUploadTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFileUploadTest.xml new file mode 100644 index 0000000000..c754a1f07b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFileUploadTest.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + ${file} + + + + + + + + + [102, 105, 108, 101, 100, 97, 116, 97] + + + + + + + + + + + + {"code": 12, "type":"post-image-ok", "message":"image successfully uploaded"} + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormDataTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormDataTest.xml new file mode 100644 index 0000000000..86b439bd74 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormDataTest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml new file mode 100644 index 0000000000..c1bef35959 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + tag1 + ${tag2} + ${nick1} + ${nick2} + ^`{|}~ }rd]]> + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathExtractionTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathExtractionTest.xml new file mode 100644 index 0000000000..69b88deed9 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathExtractionTest.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + String contentType = context.getVariable("varContentType") + assert contentType == "application/json" : "Expected variable 'varContentType' value 'application/json' but was '${varContentType}'" + + String name = context.getVariable("varName") + List allowedNames = ["cutie", "fluffy", "hasso"] + if (!allowedNames.contains(name)) { + throw new AssertionError("Expected variable 'varName' to be one of " + + allowedNames.join(", ") + " but was '" + name + "'") + } + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathValidationTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathValidationTest.xml new file mode 100644 index 0000000000..2ae560b2f8 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withJsonPathValidationTest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml new file mode 100644 index 0000000000..b68fc8646d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + import static org.assertj.core.api.Assertions.assertThat + import static java.util.Map.of + import static org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMa + + def multiMap = org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMap((org.citrusframework.http.message.HttpMessage) receivedMessage) + + org.assertj.core.api.Assertions.assertThat(multiMap) + .containsExactlyInAnyOrderEntriesOf(java.util.Map.of( + "additionalData", """${additionalData}""", + "reqIntVal", "1", + "template", new byte[]{36, 123, 116, 101, 109, 112, 108, 97, 116, 101, 68, 97, 116, 97, 125}, + "optIntVal", "100", + "optBoolVal","true", + "optDateVal","2024-12-1", + "optNumberVal","1", + "optStringVal","a")); + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveInXmlTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveInXmlTest.xml new file mode 100644 index 0000000000..de467ef686 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveInXmlTest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNonApiQueryParamTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNonApiQueryParamTest.xml new file mode 100644 index 0000000000..a83d2e6859 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNonApiQueryParamTest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromPlainTextTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromPlainTextTest.xml new file mode 100644 index 0000000000..4be7dccdc7 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromPlainTextTest.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromResourceTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromResourceTest.xml new file mode 100644 index 0000000000..2b878dff5f --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveBodyFromResourceTest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveNonApiCookieTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveNonApiCookieTest.xml new file mode 100644 index 0000000000..eaef099f0a --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withReceiveNonApiCookieTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withResponseValidationDisabledTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withResponseValidationDisabledTest.xml new file mode 100644 index 0000000000..8bc1df7b68 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withResponseValidationDisabledTest.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSoapTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSoapTest.xml new file mode 100644 index 0000000000..f253752b0b --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSoapTest.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificEndpointTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificEndpointTest.xml new file mode 100644 index 0000000000..cc1c66036d --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificEndpointTest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificUriTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificUriTest.xml new file mode 100644 index 0000000000..38e9e03d54 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withSpecificUriTest.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java deleted file mode 100644 index d66cc3aa30..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestAbstractTestRequest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.citrus; - -import static org.springframework.util.CollectionUtils.isEmpty; - -import jakarta.annotation.Nullable; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.actions.ReceiveMessageAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.spi.Resources; -import org.citrusframework.message.Message; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.json.JsonMessageValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public abstract class MultipartTestAbstractTestRequest extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("MULTIPARTTEST-API-COVERAGE"); - - @Autowired - @Qualifier("multipartTestEndpoint") - protected HttpClient httpClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected boolean schemaValidation; - protected String schema; - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - protected String responseAcceptType = "*/*"; - protected String responseType = "json"; - protected int responseStatus = 200; - protected String responseReasonPhrase = "OK"; - protected String responseVersion = "HTTP/1.1"; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value - protected Map cookies; - protected Map headers; - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - recieveResponse(context); - } - - /** - * This method receives the HTTP-Response. - * - * @deprecated use {@link MultipartTestAbstractTestRequest#receiveResponse(TestContext)} instead. - */ - public ReceiveMessageAction recieveResponse(TestContext context) { - - HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); - HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport - .statusCode(responseStatus) - .reasonPhrase(responseReasonPhrase) - .version(responseVersion) - .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - messageBuilderSupport.type(responseType); - httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); - var responseAction = httpClientResponseActionBuilder.build(); - - responseAction.execute(context); - - return responseAction; - } - - public @Nullable Message receiveResponse(TestContext context) { - var responseAction = recieveResponse(context); - - var messageStore = context.getMessageStore(); - return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); - } - - public abstract void sendRequest(TestContext context); - - public void setSchemaValidation(boolean schemaValidation) { - this.schemaValidation = schemaValidation; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setResponseAcceptType(String responseAcceptType) { - this.responseAcceptType = responseAcceptType; - } - - public void setCookie(Map cookies) { - this.cookies = cookies; - } - - public void setHeader(Map headers) { - this.headers = headers; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResponseType(String responseType) { - this.responseType = responseType; - } - - public void setResponseStatus(int responseStatus) { - this.responseStatus = responseStatus; - } - - public void setResponseReasonPhrase(String responseReasonPhrase) { - this.responseReasonPhrase = responseReasonPhrase; - } - - public void setResponseVersion(String responseVersion) { - this.responseVersion = responseVersion; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, - TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - - httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, - httpClientRequestActionBuilder); - - httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); - - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); - } - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeByBeans( - GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, httpClientRequestActionBuilder); - } - } - return httpClientRequestActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java deleted file mode 100644 index 1102147b82..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/MultipartTestBeanDefinitionParser.java +++ /dev/null @@ -1,219 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.citrus; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.core.Conventions; -import org.springframework.util.Assert; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class MultipartTestBeanDefinitionParser implements BeanDefinitionParser { - - private static final String COOKIE = "cookie"; - private static final String HEADER = "header"; - private static final String SOAP_HEADER = "soapHeader"; - private static final String MIME_HEADER = "mimeHeader"; - private static final String NAME = "name"; - private static final String REQUEST_BODY = "body"; - private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; - private static final String MULTIPART_BODY = "multipartBody"; - private static final String RESPONSE = "response"; - private static final String RESPONSE_JSONPATH = "json-path"; - private static final String RESPONSE_XPATH = "xpath"; - private static final String EXPRESSION = "expression"; - private static final String VALUE = "value"; - private static final String RESPONSE_RESOURCE = "resource"; - private static final String FILE = "file"; - private static final String RESPONSE_VARIABLE = "responseVariable"; - private static final String RESPONSE_VALUE = "responseValue"; - private static final String SCRIPT = "script"; - private static final String TYPE = "type"; - private static final String SQL = "sql"; - private static final String COLUMN = "column"; - private static final String VARIABLE = "variable"; - // new - private static final String SCHEMA = "schema"; - // new - private static final String SCHEMA_VALIDATION = "schemaValidation"; - - private final Class beanClass; - - public MultipartTestBeanDefinitionParser(Class beanClass) { - this.beanClass = beanClass; - } - - public BeanDefinition parse(Element element) { - return parse(element, null); - } - - /** - * Note: The {@link MultipartTestBeanDefinitionParser#parse(Element element)} allows access direct - * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. - */ - @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); - retrieveRootNodeAttributes(element, builder); - retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); - retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); - retrieveOptionalNodeAttributes(element, RESPONSE, builder); - retrieveParamNodeData(element, builder, COOKIE); - retrieveParamNodeData(element, builder, HEADER); - retrieveParamNodeData(element, builder, SOAP_HEADER); - retrieveParamNodeData(element, builder, MIME_HEADER); - retrieveOptionalNodeAttributes(element, SCHEMA, builder); - retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); - retrieveOptionalMultipartElements(element, builder); - retrieveResponseNodeData(element, builder); - builder.addPropertyValue("name", element.getTagName()); - return builder.getBeanDefinition(); - } - - private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { - var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); - if (multipartBodyElement != null) { - var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); - for(int i = 0; i < multipartBodyChildElements.size(); i++){ - var multipartBodyChildElement = multipartBodyChildElements.get(i); - String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); - builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); - } - } - } - - private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { - NamedNodeMap attributes = element.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - builder.addPropertyValue(propertyName, attribute.getValue()); - } - } - - private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - } - } - - private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el1.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); - String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - builder.addPropertyValue(elementName, el.getTextContent()); - } - } - - private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { - if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { - Map params = new HashMap<>(); - List elements = DomUtils.getChildElementsByTagName(element, paramType); - elements.forEach(e -> { - String name = e.getAttribute(NAME); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - params.put(name, value); - }); - builder.addPropertyValue(paramType, params); - } - } - - private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { - - if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { - Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); - List elements = DomUtils.getChildElements(response); - - Map responseVariable = new HashMap<>(); - Map responseValue = new HashMap<>(); - - for (int i = 0; i < elements.size(); i++) { - Element e = elements.get(i); - - if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { - String expression = e.getAttribute(EXPRESSION); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - // variable to save @variable('ebid')@ else value to validate - if (value.matches("\\@variable\\('.*'\\)\\@")) { - Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); - if (match.find()) { - responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); - } - } else { - responseValue.put(expression, value); - } - } else if (e.getTagName().contains(SCRIPT)) { - String script = e.getTextContent(); - Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); - builder.addPropertyValue(SCRIPT, script); - - if (!e.getAttribute(TYPE).isEmpty()) { - String type = e.getAttribute(TYPE); - Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); - builder.addPropertyValue(TYPE, type); - } - } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { - String filePath = e.getAttribute(FILE); - Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); - builder.addPropertyValue(RESPONSE_RESOURCE, filePath); - } - - } - - builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); - builder.addPropertyValue(RESPONSE_VALUE, responseValue); - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java deleted file mode 100644 index edd3e67e73..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/citrus/extension/MultipartTestNamespaceHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.citrus.extension; - -import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; -import org.citrusframework.openapi.generator.rest.multiparttest.citrus.MultipartTestBeanDefinitionParser; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class MultipartTestNamespaceHandler extends NamespaceHandlerSupport { - - @Override - public void init() { - registerBeanDefinitionParser("deleteObjectRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.DeleteObjectRequest.class)); - registerBeanDefinitionParser("fileExistsRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.FileExistsRequest.class)); - registerBeanDefinitionParser("generateReportRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.GenerateReportRequest.class)); - registerBeanDefinitionParser("multipleDatatypesRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.MultipleDatatypesRequest.class)); - registerBeanDefinitionParser("postFileRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.PostFileRequest.class)); - registerBeanDefinitionParser("postRandomRequest", new MultipartTestBeanDefinitionParser(MultiparttestControllerApi.PostRandomRequest.class)); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java deleted file mode 100644 index dbd2bcb664..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/Metadata.java +++ /dev/null @@ -1,294 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.model; - -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.time.OffsetDateTime; -import java.util.HashMap; -import java.util.Map; - -/** - * Metadata - */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class Metadata { - private Map userMetadata = new HashMap<>(); - - private Map rawMetadata = new HashMap<>(); - - private OffsetDateTime httpExpiresDate; - - private OffsetDateTime expirationTime; - - private String expirationTimeRuleId; - - private Boolean ongoingRestore; - - private OffsetDateTime restoreExpirationTime; - - private Boolean bucketKeyEnabled; - - public Metadata() { - } - - public Metadata userMetadata(Map userMetadata) { - - this.userMetadata = userMetadata; - return this; - } - - public Metadata putUserMetadataItem(String key, String userMetadataItem) { - if (this.userMetadata == null) { - this.userMetadata = new HashMap<>(); - } - this.userMetadata.put(key, userMetadataItem); - return this; - } - - /** - * Get userMetadata - * @return userMetadata - **/ - @jakarta.annotation.Nullable - - public Map getUserMetadata() { - return userMetadata; - } - - - public void setUserMetadata(Map userMetadata) { - this.userMetadata = userMetadata; - } - - - public Metadata rawMetadata(Map rawMetadata) { - - this.rawMetadata = rawMetadata; - return this; - } - - public Metadata putRawMetadataItem(String key, String rawMetadataItem) { - if (this.rawMetadata == null) { - this.rawMetadata = new HashMap<>(); - } - this.rawMetadata.put(key, rawMetadataItem); - return this; - } - - /** - * Get rawMetadata - * @return rawMetadata - **/ - @jakarta.annotation.Nullable - - public Map getRawMetadata() { - return rawMetadata; - } - - - public void setRawMetadata(Map rawMetadata) { - this.rawMetadata = rawMetadata; - } - - - public Metadata httpExpiresDate(OffsetDateTime httpExpiresDate) { - - this.httpExpiresDate = httpExpiresDate; - return this; - } - - /** - * Get httpExpiresDate - * @return httpExpiresDate - **/ - @jakarta.annotation.Nullable - - public OffsetDateTime getHttpExpiresDate() { - return httpExpiresDate; - } - - - public void setHttpExpiresDate(OffsetDateTime httpExpiresDate) { - this.httpExpiresDate = httpExpiresDate; - } - - - public Metadata expirationTime(OffsetDateTime expirationTime) { - - this.expirationTime = expirationTime; - return this; - } - - /** - * Get expirationTime - * @return expirationTime - **/ - @jakarta.annotation.Nullable - - public OffsetDateTime getExpirationTime() { - return expirationTime; - } - - - public void setExpirationTime(OffsetDateTime expirationTime) { - this.expirationTime = expirationTime; - } - - - public Metadata expirationTimeRuleId(String expirationTimeRuleId) { - - this.expirationTimeRuleId = expirationTimeRuleId; - return this; - } - - /** - * Get expirationTimeRuleId - * @return expirationTimeRuleId - **/ - @jakarta.annotation.Nullable - - public String getExpirationTimeRuleId() { - return expirationTimeRuleId; - } - - - public void setExpirationTimeRuleId(String expirationTimeRuleId) { - this.expirationTimeRuleId = expirationTimeRuleId; - } - - - public Metadata ongoingRestore(Boolean ongoingRestore) { - - this.ongoingRestore = ongoingRestore; - return this; - } - - /** - * Get ongoingRestore - * @return ongoingRestore - **/ - @jakarta.annotation.Nullable - - public Boolean getOngoingRestore() { - return ongoingRestore; - } - - - public void setOngoingRestore(Boolean ongoingRestore) { - this.ongoingRestore = ongoingRestore; - } - - - public Metadata restoreExpirationTime(OffsetDateTime restoreExpirationTime) { - - this.restoreExpirationTime = restoreExpirationTime; - return this; - } - - /** - * Get restoreExpirationTime - * @return restoreExpirationTime - **/ - @jakarta.annotation.Nullable - - public OffsetDateTime getRestoreExpirationTime() { - return restoreExpirationTime; - } - - - public void setRestoreExpirationTime(OffsetDateTime restoreExpirationTime) { - this.restoreExpirationTime = restoreExpirationTime; - } - - - public Metadata bucketKeyEnabled(Boolean bucketKeyEnabled) { - - this.bucketKeyEnabled = bucketKeyEnabled; - return this; - } - - /** - * Get bucketKeyEnabled - * @return bucketKeyEnabled - **/ - @jakarta.annotation.Nullable - - public Boolean getBucketKeyEnabled() { - return bucketKeyEnabled; - } - - - public void setBucketKeyEnabled(Boolean bucketKeyEnabled) { - this.bucketKeyEnabled = bucketKeyEnabled; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Metadata metadata = (Metadata) o; - return Objects.equals(this.userMetadata, metadata.userMetadata) && - Objects.equals(this.rawMetadata, metadata.rawMetadata) && - Objects.equals(this.httpExpiresDate, metadata.httpExpiresDate) && - Objects.equals(this.expirationTime, metadata.expirationTime) && - Objects.equals(this.expirationTimeRuleId, metadata.expirationTimeRuleId) && - Objects.equals(this.ongoingRestore, metadata.ongoingRestore) && - Objects.equals(this.restoreExpirationTime, metadata.restoreExpirationTime) && - Objects.equals(this.bucketKeyEnabled, metadata.bucketKeyEnabled); - } - - @Override - public int hashCode() { - return Objects.hash(userMetadata, rawMetadata, httpExpiresDate, expirationTime, expirationTimeRuleId, ongoingRestore, restoreExpirationTime, bucketKeyEnabled); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Metadata {\n"); - sb.append(" userMetadata: ").append(toIndentedString(userMetadata)).append("\n"); - sb.append(" rawMetadata: ").append(toIndentedString(rawMetadata)).append("\n"); - sb.append(" httpExpiresDate: ").append(toIndentedString(httpExpiresDate)).append("\n"); - sb.append(" expirationTime: ").append(toIndentedString(expirationTime)).append("\n"); - sb.append(" expirationTimeRuleId: ").append(toIndentedString(expirationTimeRuleId)).append("\n"); - sb.append(" ongoingRestore: ").append(toIndentedString(ongoingRestore)).append("\n"); - sb.append(" restoreExpirationTime: ").append(toIndentedString(restoreExpirationTime)).append("\n"); - sb.append(" bucketKeyEnabled: ").append(toIndentedString(bucketKeyEnabled)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } - -} - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java deleted file mode 100644 index 8e3abaa146..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/model/PutObjectResult.java +++ /dev/null @@ -1,251 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.model; - -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.time.OffsetDateTime; -import org.citrusframework.openapi.generator.rest.multiparttest.model.Metadata; - -/** - * PutObjectResult - */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PutObjectResult { - private String versionId; - - private String eTag; - - private OffsetDateTime expirationTime; - - private String expirationTimeRuleId; - - private String contentMd5; - - private Metadata metadata; - - private Boolean isRequesterCharged; - - public PutObjectResult() { - } - - public PutObjectResult versionId(String versionId) { - - this.versionId = versionId; - return this; - } - - /** - * Get versionId - * @return versionId - **/ - @jakarta.annotation.Nullable - - public String getVersionId() { - return versionId; - } - - - public void setVersionId(String versionId) { - this.versionId = versionId; - } - - - public PutObjectResult eTag(String eTag) { - - this.eTag = eTag; - return this; - } - - /** - * Get eTag - * @return eTag - **/ - @jakarta.annotation.Nullable - - public String geteTag() { - return eTag; - } - - - public void seteTag(String eTag) { - this.eTag = eTag; - } - - - public PutObjectResult expirationTime(OffsetDateTime expirationTime) { - - this.expirationTime = expirationTime; - return this; - } - - /** - * Get expirationTime - * @return expirationTime - **/ - @jakarta.annotation.Nullable - - public OffsetDateTime getExpirationTime() { - return expirationTime; - } - - - public void setExpirationTime(OffsetDateTime expirationTime) { - this.expirationTime = expirationTime; - } - - - public PutObjectResult expirationTimeRuleId(String expirationTimeRuleId) { - - this.expirationTimeRuleId = expirationTimeRuleId; - return this; - } - - /** - * Get expirationTimeRuleId - * @return expirationTimeRuleId - **/ - @jakarta.annotation.Nullable - - public String getExpirationTimeRuleId() { - return expirationTimeRuleId; - } - - - public void setExpirationTimeRuleId(String expirationTimeRuleId) { - this.expirationTimeRuleId = expirationTimeRuleId; - } - - - public PutObjectResult contentMd5(String contentMd5) { - - this.contentMd5 = contentMd5; - return this; - } - - /** - * Get contentMd5 - * @return contentMd5 - **/ - @jakarta.annotation.Nullable - - public String getContentMd5() { - return contentMd5; - } - - - public void setContentMd5(String contentMd5) { - this.contentMd5 = contentMd5; - } - - - public PutObjectResult metadata(Metadata metadata) { - - this.metadata = metadata; - return this; - } - - /** - * Get metadata - * @return metadata - **/ - @jakarta.annotation.Nullable - - public Metadata getMetadata() { - return metadata; - } - - - public void setMetadata(Metadata metadata) { - this.metadata = metadata; - } - - - public PutObjectResult isRequesterCharged(Boolean isRequesterCharged) { - - this.isRequesterCharged = isRequesterCharged; - return this; - } - - /** - * Get isRequesterCharged - * @return isRequesterCharged - **/ - @jakarta.annotation.Nullable - - public Boolean getIsRequesterCharged() { - return isRequesterCharged; - } - - - public void setIsRequesterCharged(Boolean isRequesterCharged) { - this.isRequesterCharged = isRequesterCharged; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - PutObjectResult putObjectResult = (PutObjectResult) o; - return Objects.equals(this.versionId, putObjectResult.versionId) && - Objects.equals(this.eTag, putObjectResult.eTag) && - Objects.equals(this.expirationTime, putObjectResult.expirationTime) && - Objects.equals(this.expirationTimeRuleId, putObjectResult.expirationTimeRuleId) && - Objects.equals(this.contentMd5, putObjectResult.contentMd5) && - Objects.equals(this.metadata, putObjectResult.metadata) && - Objects.equals(this.isRequesterCharged, putObjectResult.isRequesterCharged); - } - - @Override - public int hashCode() { - return Objects.hash(versionId, eTag, expirationTime, expirationTimeRuleId, contentMd5, metadata, isRequesterCharged); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class PutObjectResult {\n"); - sb.append(" versionId: ").append(toIndentedString(versionId)).append("\n"); - sb.append(" eTag: ").append(toIndentedString(eTag)).append("\n"); - sb.append(" expirationTime: ").append(toIndentedString(expirationTime)).append("\n"); - sb.append(" expirationTimeRuleId: ").append(toIndentedString(expirationTimeRuleId)).append("\n"); - sb.append(" contentMd5: ").append(toIndentedString(contentMd5)).append("\n"); - sb.append(" metadata: ").append(toIndentedString(metadata)).append("\n"); - sb.append(" isRequesterCharged: ").append(toIndentedString(isRequesterCharged)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } - -} - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java deleted file mode 100644 index 85f1b174b2..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/request/MultiparttestControllerApi.java +++ /dev/null @@ -1,758 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.request; - -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import org.citrusframework.openapi.generator.rest.multiparttest.citrus.MultipartTestAbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class MultiparttestControllerApi implements GeneratedApi -{ - - public static final MultiparttestControllerApi INSTANCE = new MultiparttestControllerApi(); - - public String getApiTitle() { - return "multiparttest API"; - } - - public String getApiVersion() { - return "2.0.0"; - } - - public String getApiPrefix() { - return "MultipartTest"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - infoExtensionMap.put("x-citrus-api-name", "multiparttest-rest-resource"); - infoExtensionMap.put("x-citrus-app", "MPT"); - return infoExtensionMap; - } - - /** deleteObject (DELETE /api/v2/multitest-file/{bucket}/{filename}) - Delete file. - - **/ - public static class DeleteObjectRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}"; - private final Logger coverageLogger = LoggerFactory.getLogger(DeleteObjectRequest.class); - - private String bucket; - - private String filename; - - - public DeleteObjectRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":deleteObjectRequestType"); - } - - public String getOperationName() { - return "deleteObject"; - } - - public String getMethod() { - return "DELETE"; - } - - public String getPath() { - return "/api/v2/multitest-file/{bucket}/{filename}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .delete(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "deleteObject;DELETE;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setBucket(String bucket) { - this.bucket = bucket; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); - return endpoint; - } - } - /** fileExists (GET /api/v2/multitest-file/{bucket}/{filename}/exists) - Checks if file exist. - - **/ - public static class FileExistsRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}/exists"; - private final Logger coverageLogger = LoggerFactory.getLogger(FileExistsRequest.class); - - private String bucket; - - private String filename; - - - public FileExistsRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":fileExistsRequestType"); - } - - public String getOperationName() { - return "fileExists"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/api/v2/multitest-file/{bucket}/{filename}/exists"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "fileExists;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setBucket(String bucket) { - this.bucket = bucket; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); - return endpoint; - } - } - /** generateReport (POST /api/v2/multitest-reportgeneration) - summary - - **/ - public static class GenerateReportRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-reportgeneration"; - private final Logger coverageLogger = LoggerFactory.getLogger(GenerateReportRequest.class); - - private String template; - - private String additionalData; - - private String _schema; - - - public GenerateReportRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":generateReportRequestType"); - } - - public String getOperationName() { - return "generateReport"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/api/v2/multitest-reportgeneration"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - if(StringUtils.isBlank(template)) { - throw new CitrusRuntimeException(String.format("Required attribute '%s' is not specified", "template")); - } - if (StringUtils.isNotBlank(template)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(template); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("template", resource); - } else { - multiValues.add("template", template); - } - bodyLog += template.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - if (StringUtils.isNotBlank(additionalData)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(additionalData); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("additionalData", resource); - } else { - multiValues.add("additionalData", additionalData); - } - bodyLog += additionalData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - if (StringUtils.isNotBlank(_schema)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(_schema); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("_schema", resource); - } else { - multiValues.add("_schema", _schema); - } - bodyLog += _schema.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "generateReport;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setTemplate(String template) { - this.template = template; - } - - public void setAdditionalData(String additionalData) { - this.additionalData = additionalData; - } - - public void set_schema(String _schema) { - this._schema = _schema; - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** multipleDatatypes (POST /api/v2/multitest-multipledatatypes) - summary - - **/ - public static class MultipleDatatypesRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-multipledatatypes"; - private final Logger coverageLogger = LoggerFactory.getLogger(MultipleDatatypesRequest.class); - - private String stringData; - - private String booleanData; - - private String integerData; - - - public MultipleDatatypesRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":multipleDatatypesRequestType"); - } - - public String getOperationName() { - return "multipleDatatypes"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/api/v2/multitest-multipledatatypes"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - if (StringUtils.isNotBlank(stringData)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(stringData); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("stringData", resource); - } else { - multiValues.add("stringData", stringData); - } - bodyLog += stringData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - if (StringUtils.isNotBlank(booleanData)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(booleanData); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("booleanData", resource); - } else { - multiValues.add("booleanData", booleanData); - } - bodyLog += booleanData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - if (StringUtils.isNotBlank(integerData)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(integerData); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("integerData", resource); - } else { - multiValues.add("integerData", integerData); - } - bodyLog += integerData.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "multipleDatatypes;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setStringData(String stringData) { - this.stringData = stringData; - } - - public void setBooleanData(String booleanData) { - this.booleanData = booleanData; - } - - public void setIntegerData(String integerData) { - this.integerData = integerData; - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** postFile (POST /api/v2/multitest-file/{bucket}/{filename}) - Uploads file. - - **/ - public static class PostFileRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}"; - private final Logger coverageLogger = LoggerFactory.getLogger(PostFileRequest.class); - - private String bucket; - - private String filename; - - private String multipartFile; - - - public PostFileRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":postFileRequestType"); - } - - public String getOperationName() { - return "postFile"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/api/v2/multitest-file/{bucket}/{filename}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - if (StringUtils.isNotBlank(multipartFile)) { - multiValues.add("multipartFile", new ClassPathResource(multipartFile)); - bodyLog += multipartFile.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "postFile;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setBucket(String bucket) { - this.bucket = bucket; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - public void setMultipartFile(String multipartFile) { - this.multipartFile = multipartFile; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); - return endpoint; - } - } - /** postRandom (POST /api/v2/multitest-file/{bucket}/{filename}/random) - Uploads random file. - - **/ - public static class PostRandomRequest extends MultipartTestAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/api/v2/multitest-file/{bucket}/{filename}/random"; - private final Logger coverageLogger = LoggerFactory.getLogger(PostRandomRequest.class); - - private String bucket; - - private String filename; - - - public PostRandomRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("MultipartTest".toLowerCase() + ":postRandomRequestType"); - } - - public String getOperationName() { - return "postRandom"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/api/v2/multitest-file/{bucket}/{filename}/random"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "postRandom;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setBucket(String bucket) { - this.bucket = bucket; - } - - public void setFilename(String filename) { - this.filename = filename; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "bucket" + "}", bucket);endpoint = endpoint.replace("{" + "filename" + "}", filename); - return endpoint; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java deleted file mode 100644 index d5fd2b4a60..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/multiparttest/spring/MultipartTestBeanConfiguration.java +++ /dev/null @@ -1,65 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.multiparttest.spring; - -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; - -import org.citrusframework.openapi.generator.rest.multiparttest.request.MultiparttestControllerApi; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -@Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.388350800+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class MultipartTestBeanConfiguration { - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.DeleteObjectRequest deleteObjectRequest() { - return new MultiparttestControllerApi.DeleteObjectRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.FileExistsRequest fileExistsRequest() { - return new MultiparttestControllerApi.FileExistsRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.GenerateReportRequest generateReportRequest() { - return new MultiparttestControllerApi.GenerateReportRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.MultipleDatatypesRequest multipleDatatypesRequest() { - return new MultiparttestControllerApi.MultipleDatatypesRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.PostFileRequest postFileRequest() { - return new MultiparttestControllerApi.PostFileRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public MultiparttestControllerApi.PostRandomRequest postRandomRequest() { - return new MultiparttestControllerApi.PostRandomRequest(); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java deleted file mode 100644 index 222b2f239f..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreAbstractTestRequest.java +++ /dev/null @@ -1,253 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.citrus; - -import static org.springframework.util.CollectionUtils.isEmpty; - -import jakarta.annotation.Nullable; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import javax.sql.DataSource; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.actions.ReceiveMessageAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder; -import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.http.client.HttpClient; -import org.citrusframework.spi.Resources; -import org.citrusframework.message.Message; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.json.JsonMessageValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public abstract class PetStoreAbstractTestRequest extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("PETSTORE-API-COVERAGE"); - - @Autowired - @Qualifier("petStoreEndpoint") - protected HttpClient httpClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected boolean schemaValidation; - protected String schema; - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - protected String responseAcceptType = "*/*"; - protected String responseType = "json"; - protected int responseStatus = 200; - protected String responseReasonPhrase = "OK"; - protected String responseVersion = "HTTP/1.1"; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'JSON-PATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'JSON-PATH' as key and the 'VALUE TO BE VALIDATED' as value - protected Map cookies; - protected Map headers; - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - recieveResponse(context); - } - - /** - * This method receives the HTTP-Response. - * - * @deprecated use {@link PetStoreAbstractTestRequest#receiveResponse(TestContext)} instead. - */ - public ReceiveMessageAction recieveResponse(TestContext context) { - - HttpClientResponseActionBuilder httpClientResponseActionBuilder = new HttpActionBuilder().client(httpClient).receive().response(); - HttpMessageBuilderSupport messageBuilderSupport = httpClientResponseActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport - .statusCode(responseStatus) - .reasonPhrase(responseReasonPhrase) - .version(responseVersion) - .validate(new JsonMessageValidationContext.Builder().schemaValidation(schemaValidation).schema(schema)); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - messageBuilderSupport.type(responseType); - httpClientResponseActionBuilder.withReferenceResolver(context.getReferenceResolver()); - var responseAction = httpClientResponseActionBuilder.build(); - - responseAction.execute(context); - - return responseAction; - } - - public @Nullable Message receiveResponse(TestContext context) { - var responseAction = recieveResponse(context); - - var messageStore = context.getMessageStore(); - return messageStore.getMessage(messageStore.constructMessageName(responseAction, httpClient)); - } - - public abstract void sendRequest(TestContext context); - - public void setSchemaValidation(boolean schemaValidation) { - this.schemaValidation = schemaValidation; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setResponseAcceptType(String responseAcceptType) { - this.responseAcceptType = responseAcceptType; - } - - public void setCookie(Map cookies) { - this.cookies = cookies; - } - - public void setHeader(Map headers) { - this.headers = headers; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResponseType(String responseType) { - this.responseType = responseType; - } - - public void setResponseStatus(int responseStatus) { - this.responseStatus = responseStatus; - } - - public void setResponseReasonPhrase(String responseReasonPhrase) { - this.responseReasonPhrase = responseReasonPhrase; - } - - public void setResponseVersion(String responseVersion) { - this.responseVersion = responseVersion; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - protected HttpClientRequestActionBuilder customizeBuilder(GeneratedApi generatedApi, - TestContext context, HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - - httpClientRequestActionBuilder = customizeByBeans(generatedApi, context, - httpClientRequestActionBuilder); - - httpClientRequestActionBuilder = customizeBySpi(generatedApi, context, httpClientRequestActionBuilder); - - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeBySpi(GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - httpClientRequestActionBuilder = service.build(generatedApi, this, context, httpClientRequestActionBuilder); - } - return httpClientRequestActionBuilder; - } - - private HttpClientRequestActionBuilder customizeByBeans( - GeneratedApi generatedApi, TestContext context, - HttpClientRequestActionBuilder httpClientRequestActionBuilder) { - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - httpClientRequestActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, httpClientRequestActionBuilder); - } - } - return httpClientRequestActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java deleted file mode 100644 index d1018d8efb..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/PetStoreBeanDefinitionParser.java +++ /dev/null @@ -1,219 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.citrus; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.core.Conventions; -import org.springframework.util.Assert; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetStoreBeanDefinitionParser implements BeanDefinitionParser { - - private static final String COOKIE = "cookie"; - private static final String HEADER = "header"; - private static final String SOAP_HEADER = "soapHeader"; - private static final String MIME_HEADER = "mimeHeader"; - private static final String NAME = "name"; - private static final String REQUEST_BODY = "body"; - private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; - private static final String MULTIPART_BODY = "multipartBody"; - private static final String RESPONSE = "response"; - private static final String RESPONSE_JSONPATH = "json-path"; - private static final String RESPONSE_XPATH = "xpath"; - private static final String EXPRESSION = "expression"; - private static final String VALUE = "value"; - private static final String RESPONSE_RESOURCE = "resource"; - private static final String FILE = "file"; - private static final String RESPONSE_VARIABLE = "responseVariable"; - private static final String RESPONSE_VALUE = "responseValue"; - private static final String SCRIPT = "script"; - private static final String TYPE = "type"; - private static final String SQL = "sql"; - private static final String COLUMN = "column"; - private static final String VARIABLE = "variable"; - // new - private static final String SCHEMA = "schema"; - // new - private static final String SCHEMA_VALIDATION = "schemaValidation"; - - private final Class beanClass; - - public PetStoreBeanDefinitionParser(Class beanClass) { - this.beanClass = beanClass; - } - - public BeanDefinition parse(Element element) { - return parse(element, null); - } - - /** - * Note: The {@link PetStoreBeanDefinitionParser#parse(Element element)} allows access direct - * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. - */ - @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); - retrieveRootNodeAttributes(element, builder); - retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); - retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); - retrieveOptionalNodeAttributes(element, RESPONSE, builder); - retrieveParamNodeData(element, builder, COOKIE); - retrieveParamNodeData(element, builder, HEADER); - retrieveParamNodeData(element, builder, SOAP_HEADER); - retrieveParamNodeData(element, builder, MIME_HEADER); - retrieveOptionalNodeAttributes(element, SCHEMA, builder); - retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); - retrieveOptionalMultipartElements(element, builder); - retrieveResponseNodeData(element, builder); - builder.addPropertyValue("name", element.getTagName()); - return builder.getBeanDefinition(); - } - - private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { - var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); - if (multipartBodyElement != null) { - var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); - for(int i = 0; i < multipartBodyChildElements.size(); i++){ - var multipartBodyChildElement = multipartBodyChildElements.get(i); - String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); - builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); - } - } - } - - private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { - NamedNodeMap attributes = element.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - builder.addPropertyValue(propertyName, attribute.getValue()); - } - } - - private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - } - } - - private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el1.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); - String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - builder.addPropertyValue(elementName, el.getTextContent()); - } - } - - private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { - if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { - Map params = new HashMap<>(); - List elements = DomUtils.getChildElementsByTagName(element, paramType); - elements.forEach(e -> { - String name = e.getAttribute(NAME); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - params.put(name, value); - }); - builder.addPropertyValue(paramType, params); - } - } - - private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { - - if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { - Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); - List elements = DomUtils.getChildElements(response); - - Map responseVariable = new HashMap<>(); - Map responseValue = new HashMap<>(); - - for (int i = 0; i < elements.size(); i++) { - Element e = elements.get(i); - - if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { - String expression = e.getAttribute(EXPRESSION); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - // variable to save @variable('ebid')@ else value to validate - if (value.matches("\\@variable\\('.*'\\)\\@")) { - Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); - if (match.find()) { - responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); - } - } else { - responseValue.put(expression, value); - } - } else if (e.getTagName().contains(SCRIPT)) { - String script = e.getTextContent(); - Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); - builder.addPropertyValue(SCRIPT, script); - - if (!e.getAttribute(TYPE).isEmpty()) { - String type = e.getAttribute(TYPE); - Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); - builder.addPropertyValue(TYPE, type); - } - } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { - String filePath = e.getAttribute(FILE); - Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); - builder.addPropertyValue(RESPONSE_RESOURCE, filePath); - } - - } - - builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); - builder.addPropertyValue(RESPONSE_VALUE, responseValue); - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java deleted file mode 100644 index ac9e93f527..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/citrus/extension/PetStoreNamespaceHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.citrus.extension; - -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; -import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; -import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; -import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreBeanDefinitionParser; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { - - @Override - public void init() { - registerBeanDefinitionParser("addPetRequest", new PetStoreBeanDefinitionParser(PetApi.AddPetRequest.class)); - registerBeanDefinitionParser("deletePetRequest", new PetStoreBeanDefinitionParser(PetApi.DeletePetRequest.class)); - registerBeanDefinitionParser("findPetsByStatusRequest", new PetStoreBeanDefinitionParser(PetApi.FindPetsByStatusRequest.class)); - registerBeanDefinitionParser("findPetsByTagsRequest", new PetStoreBeanDefinitionParser(PetApi.FindPetsByTagsRequest.class)); - registerBeanDefinitionParser("getPetByIdRequest", new PetStoreBeanDefinitionParser(PetApi.GetPetByIdRequest.class)); - registerBeanDefinitionParser("updatePetRequest", new PetStoreBeanDefinitionParser(PetApi.UpdatePetRequest.class)); - registerBeanDefinitionParser("updatePetWithFormRequest", new PetStoreBeanDefinitionParser(PetApi.UpdatePetWithFormRequest.class)); - registerBeanDefinitionParser("uploadFileRequest", new PetStoreBeanDefinitionParser(PetApi.UploadFileRequest.class)); - registerBeanDefinitionParser("deleteOrderRequest", new PetStoreBeanDefinitionParser(StoreApi.DeleteOrderRequest.class)); - registerBeanDefinitionParser("getInventoryRequest", new PetStoreBeanDefinitionParser(StoreApi.GetInventoryRequest.class)); - registerBeanDefinitionParser("getOrderByIdRequest", new PetStoreBeanDefinitionParser(StoreApi.GetOrderByIdRequest.class)); - registerBeanDefinitionParser("placeOrderRequest", new PetStoreBeanDefinitionParser(StoreApi.PlaceOrderRequest.class)); - registerBeanDefinitionParser("createUserRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUserRequest.class)); - registerBeanDefinitionParser("createUsersWithArrayInputRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUsersWithArrayInputRequest.class)); - registerBeanDefinitionParser("createUsersWithListInputRequest", new PetStoreBeanDefinitionParser(UserApi.CreateUsersWithListInputRequest.class)); - registerBeanDefinitionParser("deleteUserRequest", new PetStoreBeanDefinitionParser(UserApi.DeleteUserRequest.class)); - registerBeanDefinitionParser("getUserByNameRequest", new PetStoreBeanDefinitionParser(UserApi.GetUserByNameRequest.class)); - registerBeanDefinitionParser("loginUserRequest", new PetStoreBeanDefinitionParser(UserApi.LoginUserRequest.class)); - registerBeanDefinitionParser("logoutUserRequest", new PetStoreBeanDefinitionParser(UserApi.LogoutUserRequest.class)); - registerBeanDefinitionParser("updateUserRequest", new PetStoreBeanDefinitionParser(UserApi.UpdateUserRequest.class)); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java deleted file mode 100644 index 41a154158e..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/PetApi.java +++ /dev/null @@ -1,870 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.request; - -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetApi implements GeneratedApi -{ - - public static final PetApi INSTANCE = new PetApi(); - - public String getApiTitle() { - return "OpenAPI Petstore"; - } - - public String getApiVersion() { - return "1.0.0"; - } - - public String getApiPrefix() { - return "PetStore"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - infoExtensionMap.put("x-citrus-api-name", "petstore"); - infoExtensionMap.put("x-citrus-app", "PETS"); - return infoExtensionMap; - } - - /** addPet (POST /pet) - Add a new pet to the store - - **/ - public static class AddPetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet"; - private final Logger coverageLogger = LoggerFactory.getLogger(AddPetRequest.class); - - - public AddPetRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":addPetRequestType"); - } - - public String getOperationName() { - return "addPet"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/pet"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "addPet;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** deletePet (DELETE /pet/{petId}) - Deletes a pet - - **/ - public static class DeletePetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/{petId}"; - private final Logger coverageLogger = LoggerFactory.getLogger(DeletePetRequest.class); - - private String petId; - - - public DeletePetRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":deletePetRequestType"); - } - - public String getOperationName() { - return "deletePet"; - } - - public String getMethod() { - return "DELETE"; - } - - public String getPath() { - return "/pet/{petId}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .delete(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "deletePet;DELETE;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setPetId(String petId) { - this.petId = petId; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "petId" + "}", petId); - return endpoint; - } - } - /** findPetsByStatus (GET /pet/findByStatus) - Finds Pets by status - - **/ - public static class FindPetsByStatusRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/findByStatus"; - private final Logger coverageLogger = LoggerFactory.getLogger(FindPetsByStatusRequest.class); - - private String status; - - - public FindPetsByStatusRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":findPetsByStatusRequestType"); - } - - public String getOperationName() { - return "findPetsByStatus"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/pet/findByStatus"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - - if (StringUtils.isNotBlank(this.status)) { - queryParams.put("status", context.replaceDynamicContentInString(this.status)); - httpClientRequestActionBuilder.queryParam("status", this.status); - } - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "findPetsByStatus;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setStatus(String status) { - this.status = status; - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** findPetsByTags (GET /pet/findByTags) - Finds Pets by tags - - **/ - public static class FindPetsByTagsRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/findByTags"; - private final Logger coverageLogger = LoggerFactory.getLogger(FindPetsByTagsRequest.class); - - private String tags; - - - public FindPetsByTagsRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":findPetsByTagsRequestType"); - } - - public String getOperationName() { - return "findPetsByTags"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/pet/findByTags"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - - if (StringUtils.isNotBlank(this.tags)) { - queryParams.put("tags", context.replaceDynamicContentInString(this.tags)); - httpClientRequestActionBuilder.queryParam("tags", this.tags); - } - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "findPetsByTags;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setTags(String tags) { - this.tags = tags; - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** getPetById (GET /pet/{petId}) - Find pet by ID - - **/ - public static class GetPetByIdRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/{petId}"; - private final Logger coverageLogger = LoggerFactory.getLogger(GetPetByIdRequest.class); - - private String petId; - - - @Value("${" + "petStoreEndpoint.basic.username:#{null}}") - private String basicUsername; - @Value("${" + "petStoreEndpoint.basic.password:#{null}}") - private String basicPassword; - - - public GetPetByIdRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":getPetByIdRequestType"); - } - - public String getOperationName() { - return "getPetById"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/pet/{petId}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - - if(basicUsername != null && basicPassword != null){ - messageBuilderSupport.header("Authorization", "Basic " + Base64.getEncoder().encodeToString((context.replaceDynamicContentInString(basicUsername)+":"+context.replaceDynamicContentInString(basicPassword)).getBytes())); - } - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getPetById;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setPetId(String petId) { - this.petId = petId; - } - - - public void setBasicUsername(String basicUsername) { - this.basicUsername = basicUsername; - } - - public void setBasicPassword(String basicPassword) { - this.basicPassword = basicPassword; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "petId" + "}", petId); - return endpoint; - } - } - /** updatePet (PUT /pet) - Update an existing pet - - **/ - public static class UpdatePetRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet"; - private final Logger coverageLogger = LoggerFactory.getLogger(UpdatePetRequest.class); - - - public UpdatePetRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":updatePetRequestType"); - } - - public String getOperationName() { - return "updatePet"; - } - - public String getMethod() { - return "PUT"; - } - - public String getPath() { - return "/pet"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .put(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "updatePet;PUT;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** updatePetWithForm (POST /pet/{petId}) - Updates a pet in the store with form data - - **/ - public static class UpdatePetWithFormRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/{petId}"; - private final Logger coverageLogger = LoggerFactory.getLogger(UpdatePetWithFormRequest.class); - - private String petId; - - - public UpdatePetWithFormRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":updatePetWithFormRequestType"); - } - - public String getOperationName() { - return "updatePetWithForm"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/pet/{petId}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "updatePetWithForm;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setPetId(String petId) { - this.petId = petId; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "petId" + "}", petId); - return endpoint; - } - } - /** uploadFile (POST /pet/{petId}/uploadImage) - uploads an image - - **/ - public static class UploadFileRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/pet/{petId}/uploadImage"; - private final Logger coverageLogger = LoggerFactory.getLogger(UploadFileRequest.class); - - private String petId; - - private String additionalMetadata; - - private String _file; - - - public UploadFileRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":uploadFileRequestType"); - } - - public String getOperationName() { - return "uploadFile"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/pet/{petId}/uploadImage"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - MultiValueMap multiValues = new LinkedMultiValueMap<>(); - if (StringUtils.isNotBlank(additionalMetadata)) { - // first try to load from resource - ClassPathResource resource = null; - try { - resource = new ClassPathResource(additionalMetadata); - } - catch(Exception ignore) { - // Use plain text instead of resource - } - - if(resource != null && resource.exists()){ - multiValues.add("additionalMetadata", resource); - } else { - multiValues.add("additionalMetadata", additionalMetadata); - } - bodyLog += additionalMetadata.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - if (StringUtils.isNotBlank(_file)) { - multiValues.add("_file", new ClassPathResource(_file)); - bodyLog += _file.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") +","; - } - - bodyLog += "\";\"" + MediaType.MULTIPART_FORM_DATA_VALUE + "\""; - messageBuilderSupport.contentType(MediaType.MULTIPART_FORM_DATA_VALUE) - .body(multiValues); - - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "uploadFile;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setPetId(String petId) { - this.petId = petId; - } - - public void setAdditionalMetadata(String additionalMetadata) { - this.additionalMetadata = additionalMetadata; - } - - public void set_file(String _file) { - this._file = _file; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "petId" + "}", petId); - return endpoint; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java deleted file mode 100644 index db50a61387..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/StoreApi.java +++ /dev/null @@ -1,441 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.request; - -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class StoreApi implements GeneratedApi -{ - - public static final StoreApi INSTANCE = new StoreApi(); - - public String getApiTitle() { - return "OpenAPI Petstore"; - } - - public String getApiVersion() { - return "1.0.0"; - } - - public String getApiPrefix() { - return "PetStore"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - infoExtensionMap.put("x-citrus-api-name", "petstore"); - infoExtensionMap.put("x-citrus-app", "PETS"); - return infoExtensionMap; - } - - /** deleteOrder (DELETE /store/order/{order_id}) - Delete purchase order by ID - - **/ - public static class DeleteOrderRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/store/order/{order_id}"; - private final Logger coverageLogger = LoggerFactory.getLogger(DeleteOrderRequest.class); - - private String orderId; - - - public DeleteOrderRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":deleteOrderRequestType"); - } - - public String getOperationName() { - return "deleteOrder"; - } - - public String getMethod() { - return "DELETE"; - } - - public String getPath() { - return "/store/order/{order_id}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .delete(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "deleteOrder;DELETE;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setOrderId(String orderId) { - this.orderId = orderId; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "order_id" + "}", orderId); - return endpoint; - } - } - /** getInventory (GET /store/inventory) - Returns pet inventories by status - - **/ - public static class GetInventoryRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/store/inventory"; - private final Logger coverageLogger = LoggerFactory.getLogger(GetInventoryRequest.class); - - - public GetInventoryRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":getInventoryRequestType"); - } - - public String getOperationName() { - return "getInventory"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/store/inventory"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getInventory;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** getOrderById (GET /store/order/{order_id}) - Find purchase order by ID - - **/ - public static class GetOrderByIdRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/store/order/{order_id}"; - private final Logger coverageLogger = LoggerFactory.getLogger(GetOrderByIdRequest.class); - - private String orderId; - - - public GetOrderByIdRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":getOrderByIdRequestType"); - } - - public String getOperationName() { - return "getOrderById"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/store/order/{order_id}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getOrderById;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setOrderId(String orderId) { - this.orderId = orderId; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "order_id" + "}", orderId); - return endpoint; - } - } - /** placeOrder (POST /store/order) - Place an order for a pet - - **/ - public static class PlaceOrderRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/store/order"; - private final Logger coverageLogger = LoggerFactory.getLogger(PlaceOrderRequest.class); - - - public PlaceOrderRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":placeOrderRequestType"); - } - - public String getOperationName() { - return "placeOrder"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/store/order"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "placeOrder;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java deleted file mode 100644 index 6b07c599a5..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/request/UserApi.java +++ /dev/null @@ -1,827 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.request; - -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import jakarta.servlet.http.Cookie; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resources; -import org.citrusframework.http.actions.HttpActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -import org.citrusframework.openapi.generator.rest.petstore.citrus.PetStoreAbstractTestRequest; - -import java.io.IOException; -import java.util.Base64; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class UserApi implements GeneratedApi -{ - - public static final UserApi INSTANCE = new UserApi(); - - public String getApiTitle() { - return "OpenAPI Petstore"; - } - - public String getApiVersion() { - return "1.0.0"; - } - - public String getApiPrefix() { - return "PetStore"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - infoExtensionMap.put("x-citrus-api-name", "petstore"); - infoExtensionMap.put("x-citrus-app", "PETS"); - return infoExtensionMap; - } - - /** createUser (POST /user) - Create user - - **/ - public static class CreateUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user"; - private final Logger coverageLogger = LoggerFactory.getLogger(CreateUserRequest.class); - - - public CreateUserRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":createUserRequestType"); - } - - public String getOperationName() { - return "createUser"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/user"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "createUser;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** createUsersWithArrayInput (POST /user/createWithArray) - Creates list of users with given input array - - **/ - public static class CreateUsersWithArrayInputRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/createWithArray"; - private final Logger coverageLogger = LoggerFactory.getLogger(CreateUsersWithArrayInputRequest.class); - - - public CreateUsersWithArrayInputRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":createUsersWithArrayInputRequestType"); - } - - public String getOperationName() { - return "createUsersWithArrayInput"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/user/createWithArray"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "createUsersWithArrayInput;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** createUsersWithListInput (POST /user/createWithList) - Creates list of users with given input array - - **/ - public static class CreateUsersWithListInputRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/createWithList"; - private final Logger coverageLogger = LoggerFactory.getLogger(CreateUsersWithListInputRequest.class); - - - public CreateUsersWithListInputRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":createUsersWithListInputRequestType"); - } - - public String getOperationName() { - return "createUsersWithListInput"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/user/createWithList"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .post(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "createUsersWithListInput;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** deleteUser (DELETE /user/{username}) - Delete user - - **/ - public static class DeleteUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/{username}"; - private final Logger coverageLogger = LoggerFactory.getLogger(DeleteUserRequest.class); - - private String username; - - - public DeleteUserRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":deleteUserRequestType"); - } - - public String getOperationName() { - return "deleteUser"; - } - - public String getMethod() { - return "DELETE"; - } - - public String getPath() { - return "/user/{username}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .delete(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "deleteUser;DELETE;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setUsername(String username) { - this.username = username; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "username" + "}", username); - return endpoint; - } - } - /** getUserByName (GET /user/{username}) - Get user by user name - - **/ - public static class GetUserByNameRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/{username}"; - private final Logger coverageLogger = LoggerFactory.getLogger(GetUserByNameRequest.class); - - private String username; - - - public GetUserByNameRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":getUserByNameRequestType"); - } - - public String getOperationName() { - return "getUserByName"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/user/{username}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getUserByName;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setUsername(String username) { - this.username = username; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "username" + "}", username); - return endpoint; - } - } - /** loginUser (GET /user/login) - Logs user into the system - - **/ - public static class LoginUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/login"; - private final Logger coverageLogger = LoggerFactory.getLogger(LoginUserRequest.class); - - private String username; - - private String password; - - - public LoginUserRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":loginUserRequestType"); - } - - public String getOperationName() { - return "loginUser"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/user/login"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - - if (StringUtils.isNotBlank(this.username)) { - queryParams.put("username", context.replaceDynamicContentInString(this.username)); - httpClientRequestActionBuilder.queryParam("username", this.username); - } - - - if (StringUtils.isNotBlank(this.password)) { - queryParams.put("password", context.replaceDynamicContentInString(this.password)); - httpClientRequestActionBuilder.queryParam("password", this.password); - } - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "loginUser;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setUsername(String username) { - this.username = username; - } - - public void setPassword(String password) { - this.password = password; - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** logoutUser (GET /user/logout) - Logs out current logged in user session - - **/ - public static class LogoutUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/logout"; - private final Logger coverageLogger = LoggerFactory.getLogger(LogoutUserRequest.class); - - - public LogoutUserRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":logoutUserRequestType"); - } - - public String getOperationName() { - return "logoutUser"; - } - - public String getMethod() { - return "GET"; - } - - public String getPath() { - return "/user/logout"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .get(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "logoutUser;GET;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - private String replacePathParams(String endpoint) { - - return endpoint; - } - } - /** updateUser (PUT /user/{username}) - Updated user - - **/ - public static class UpdateUserRequest extends PetStoreAbstractTestRequest implements GeneratedApiRequest { - - private static final String ENDPOINT = "/user/{username}"; - private final Logger coverageLogger = LoggerFactory.getLogger(UpdateUserRequest.class); - - private String username; - - - public UpdateUserRequest() { - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("PetStore".toLowerCase() + ":updateUserRequestType"); - } - - public String getOperationName() { - return "updateUser"; - } - - public String getMethod() { - return "PUT"; - } - - public String getPath() { - return "/user/{username}"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - HttpClientRequestActionBuilder httpClientRequestActionBuilder = new HttpActionBuilder().client(httpClient).send() - .put(replacePathParams(ENDPOINT)); - - HttpMessageBuilderSupport messageBuilderSupport = httpClientRequestActionBuilder.getMessageBuilderSupport(); - messageBuilderSupport.accept(responseAcceptType); - - if (cookies != null) { - cookies.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - } - - if (headers != null) { - headers.forEach((k, v) -> messageBuilderSupport.cookie(new Cookie(k, v))); - headers.forEach(messageBuilderSupport::header); - } - - String bodyLog = ""; - String payload = null; - String payloadType = null; - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - bodyLog = body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""; - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - httpClientRequestActionBuilder.withReferenceResolver(context.getReferenceResolver()); - httpClientRequestActionBuilder = customizeBuilder(INSTANCE, context, httpClientRequestActionBuilder); - - httpClientRequestActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "updateUser;PUT;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - bodyLog); - } - - public void setUsername(String username) { - this.username = username; - } - - private String replacePathParams(String endpoint) { - endpoint = endpoint.replace("{" + "username" + "}", username); - return endpoint; - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java deleted file mode 100644 index 9b31309e7a..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.rest.petstore.spring; - -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; - -import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; -import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; -import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -@Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:45.610010900+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetStoreBeanConfiguration { - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.AddPetRequest addPetRequest() { - return new PetApi.AddPetRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.DeletePetRequest deletePetRequest() { - return new PetApi.DeletePetRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.FindPetsByStatusRequest findPetsByStatusRequest() { - return new PetApi.FindPetsByStatusRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.FindPetsByTagsRequest findPetsByTagsRequest() { - return new PetApi.FindPetsByTagsRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.GetPetByIdRequest getPetByIdRequest() { - return new PetApi.GetPetByIdRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.UpdatePetRequest updatePetRequest() { - return new PetApi.UpdatePetRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.UpdatePetWithFormRequest updatePetWithFormRequest() { - return new PetApi.UpdatePetWithFormRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public PetApi.UploadFileRequest uploadFileRequest() { - return new PetApi.UploadFileRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public StoreApi.DeleteOrderRequest deleteOrderRequest() { - return new StoreApi.DeleteOrderRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public StoreApi.GetInventoryRequest getInventoryRequest() { - return new StoreApi.GetInventoryRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public StoreApi.GetOrderByIdRequest getOrderByIdRequest() { - return new StoreApi.GetOrderByIdRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public StoreApi.PlaceOrderRequest placeOrderRequest() { - return new StoreApi.PlaceOrderRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.CreateUserRequest createUserRequest() { - return new UserApi.CreateUserRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.CreateUsersWithArrayInputRequest createUsersWithArrayInputRequest() { - return new UserApi.CreateUsersWithArrayInputRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.CreateUsersWithListInputRequest createUsersWithListInputRequest() { - return new UserApi.CreateUsersWithListInputRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.DeleteUserRequest deleteUserRequest() { - return new UserApi.DeleteUserRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.GetUserByNameRequest getUserByNameRequest() { - return new UserApi.GetUserByNameRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.LoginUserRequest loginUserRequest() { - return new UserApi.LoginUserRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.LogoutUserRequest logoutUserRequest() { - return new UserApi.LogoutUserRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public UserApi.UpdateUserRequest updateUserRequest() { - return new UserApi.UpdateUserRequest(); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java deleted file mode 100644 index 78cc8b5bcf..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlAbstractTestRequest.java +++ /dev/null @@ -1,196 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.soap.bookservice.citrus; - -import java.util.List; -import java.util.ServiceLoader; -import org.citrusframework.actions.AbstractTestAction; -import org.citrusframework.context.TestContext; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder; -import org.citrusframework.testapi.ApiActionBuilderCustomizerService; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.spi.Resources; -import org.citrusframework.validation.DelegatingPayloadVariableExtractor; -import org.citrusframework.validation.PathExpressionValidationContext; -import org.citrusframework.validation.script.ScriptValidationContext; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction.SoapMessageBuilderSupport; -import org.citrusframework.ws.actions.SendSoapMessageAction; -import org.citrusframework.ws.actions.SoapActionBuilder; -import org.citrusframework.ws.client.WebServiceClient; -import org.slf4j.Marker; -import org.slf4j.MarkerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.util.CollectionUtils; - -import javax.sql.DataSource; -import java.util.Map; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public abstract class OpenApiFromWsdlAbstractTestRequest extends AbstractTestAction { - - protected final Marker coverageMarker = MarkerFactory.getMarker("OPENAPIFROMWSDL-API-COVERAGE"); - - @Autowired - @Qualifier("soapSampleEndpoint") - protected WebServiceClient wsClient; - - @Autowired(required = false) - protected DataSource dataSource; - - @Autowired(required = false) - private List actionBuilderCustomizerServices; - - // attributes of differentNodes - protected String bodyContentType; - protected String bodyLiteralContentType; - protected String bodyFile; - protected String bodyLiteral; - - // children of response element - protected String resource; - protected Map responseVariable; // Contains the 'XPATH' as key and the 'VARIABLE NAME' as value - protected Map responseValue; // Contains the 'XPATH' as key and the 'VALUE TO BE VALIDATED' as value - protected String script; - protected String type; // default script type is groovy - supported types see com.consol.citrus.script.ScriptTypes - protected Map soapHeaders; - protected Map mimeHeaders; - - @Override - public void doExecute(TestContext context) { - sendRequest(context); - receiveResponse(context); - } - - /** - * This method receives the HTTP-Response - */ - public void receiveResponse(TestContext context) { - - ReceiveSoapMessageAction.Builder soapReceiveMessageActionBuilder = new SoapActionBuilder().client(wsClient).receive(); - SoapMessageBuilderSupport messageBuilderSupport = soapReceiveMessageActionBuilder.getMessageBuilderSupport(); - - if (resource != null) { - messageBuilderSupport.body(Resources.create(resource)); - } - - if (!CollectionUtils.isEmpty(responseVariable)) { - DelegatingPayloadVariableExtractor.Builder extractorBuilder = new DelegatingPayloadVariableExtractor.Builder(); - responseVariable.forEach(extractorBuilder::expression); - messageBuilderSupport.extract(extractorBuilder); - } - - if (!CollectionUtils.isEmpty(responseValue)) { - PathExpressionValidationContext.Builder validationContextBuilder = new PathExpressionValidationContext.Builder(); - responseValue.forEach(validationContextBuilder::expression); - messageBuilderSupport.validate(validationContextBuilder); - } - - if (script != null) { - ScriptValidationContext.Builder scriptValidationContextBuilder = new ScriptValidationContext.Builder(); - if (type != null) { - scriptValidationContextBuilder.scriptType(type); - } - scriptValidationContextBuilder.script(script); - messageBuilderSupport.validate(scriptValidationContextBuilder); - } - - soapReceiveMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapReceiveMessageActionBuilder.build().execute(context); - } - - public abstract void sendRequest(TestContext context); - - public void setBodyLiteral(String bodyLiteral) { - this.bodyLiteral = bodyLiteral; - } - public void setBodyContentType(String bodyContentType) { - this.bodyContentType = bodyContentType; - } - - public void setBodyLiteralContentType(String bodyLiteralContentType) { - this.bodyLiteralContentType = bodyLiteralContentType; - } - - public void setBodyFile(String bodyFile) { - this.bodyFile = bodyFile; - } - - public void setResource(String resource) { - this.resource = resource; - } - - public void setResponseVariable(Map responseVariable) { - this.responseVariable = responseVariable; - } - - public void setResponseValue(Map responseValue) { - this.responseValue = responseValue; - } - - public void setScript(String script) { - this.script = script; - } - - public void setType(String type) { - this.type = type; - } - - public void setSoapHeader(Map soapHeaders) { - this.soapHeaders = soapHeaders; - } - - public void setMimeHeader(Map mimeHeaders) { - this.mimeHeaders = mimeHeaders; - } - - protected SendSoapMessageAction.Builder customizeBuilder(GeneratedApi generatedApi, - TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - sendSoapMessageActionBuilder = customizeByBeans(generatedApi, context, sendSoapMessageActionBuilder); - - sendSoapMessageActionBuilder = customizeBySpi(generatedApi, context, sendSoapMessageActionBuilder); - - return sendSoapMessageActionBuilder; - } - - private SendSoapMessageAction.Builder customizeBySpi(GeneratedApi generatedApi, TestContext context, - SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - ServiceLoader serviceLoader = ServiceLoader.load( - ApiActionBuilderCustomizerService.class, ApiActionBuilderCustomizerService.class.getClassLoader()); - for (ApiActionBuilderCustomizerService service :serviceLoader) { - sendSoapMessageActionBuilder = service.build(generatedApi, this, context, sendSoapMessageActionBuilder); - } - - return sendSoapMessageActionBuilder; - } - - private SendSoapMessageAction.Builder customizeByBeans( - GeneratedApi generatedApi, TestContext context, SendSoapMessageAction.Builder sendSoapMessageActionBuilder) { - - if (actionBuilderCustomizerServices != null) { - for (ApiActionBuilderCustomizerService apiActionBuilderCustomizer : actionBuilderCustomizerServices) { - sendSoapMessageActionBuilder = apiActionBuilderCustomizer.build(generatedApi, this, - context, sendSoapMessageActionBuilder); - } - } - - return sendSoapMessageActionBuilder; - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java deleted file mode 100644 index e777f4608c..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/OpenApiFromWsdlBeanDefinitionParser.java +++ /dev/null @@ -1,219 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.soap.bookservice.citrus; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.BeanDefinitionParser; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.core.Conventions; -import org.springframework.util.Assert; -import org.springframework.util.xml.DomUtils; -import org.w3c.dom.Attr; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class OpenApiFromWsdlBeanDefinitionParser implements BeanDefinitionParser { - - private static final String COOKIE = "cookie"; - private static final String HEADER = "header"; - private static final String SOAP_HEADER = "soapHeader"; - private static final String MIME_HEADER = "mimeHeader"; - private static final String NAME = "name"; - private static final String REQUEST_BODY = "body"; - private static final String REQUEST_BODY_LITERAL = "bodyLiteral"; - private static final String MULTIPART_BODY = "multipartBody"; - private static final String RESPONSE = "response"; - private static final String RESPONSE_JSONPATH = "json-path"; - private static final String RESPONSE_XPATH = "xpath"; - private static final String EXPRESSION = "expression"; - private static final String VALUE = "value"; - private static final String RESPONSE_RESOURCE = "resource"; - private static final String FILE = "file"; - private static final String RESPONSE_VARIABLE = "responseVariable"; - private static final String RESPONSE_VALUE = "responseValue"; - private static final String SCRIPT = "script"; - private static final String TYPE = "type"; - private static final String SQL = "sql"; - private static final String COLUMN = "column"; - private static final String VARIABLE = "variable"; - // new - private static final String SCHEMA = "schema"; - // new - private static final String SCHEMA_VALIDATION = "schemaValidation"; - - private final Class beanClass; - - public OpenApiFromWsdlBeanDefinitionParser(Class beanClass) { - this.beanClass = beanClass; - } - - public BeanDefinition parse(Element element) { - return parse(element, null); - } - - /** - * Note: The {@link OpenApiFromWsdlBeanDefinitionParser#parse(Element element)} allows access direct - * access without the {@link org.springframework.beans.factory.xml.ParserContext} for convenience. - */ - @Override - public BeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(beanClass); - retrieveRootNodeAttributes(element, builder); - retrieveOptionalNodeAttributes(element, REQUEST_BODY, builder); - retrieveTextContentAndNodeAttributes(element, REQUEST_BODY_LITERAL, builder); - retrieveOptionalNodeAttributes(element, RESPONSE, builder); - retrieveParamNodeData(element, builder, COOKIE); - retrieveParamNodeData(element, builder, HEADER); - retrieveParamNodeData(element, builder, SOAP_HEADER); - retrieveParamNodeData(element, builder, MIME_HEADER); - retrieveOptionalNodeAttributes(element, SCHEMA, builder); - retrieveOptionalNodeAttributes(element, SCHEMA_VALIDATION, builder); - retrieveOptionalMultipartElements(element, builder); - retrieveResponseNodeData(element, builder); - builder.addPropertyValue("name", element.getTagName()); - return builder.getBeanDefinition(); - } - - private void retrieveOptionalMultipartElements(Element element, BeanDefinitionBuilder builder) { - var multipartBodyElement = DomUtils.getChildElementByTagName(element, MULTIPART_BODY); - if (multipartBodyElement != null) { - var multipartBodyChildElements = DomUtils.getChildElements(multipartBodyElement); - for(int i = 0; i < multipartBodyChildElements.size(); i++){ - var multipartBodyChildElement = multipartBodyChildElements.get(i); - String propertyName = Conventions.attributeNameToPropertyName(multipartBodyChildElement.getLocalName()); - builder.addPropertyValue(propertyName, multipartBodyChildElement.getTextContent()); - } - } - } - - private void retrieveRootNodeAttributes(Element element, BeanDefinitionBuilder builder) { - NamedNodeMap attributes = element.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - builder.addPropertyValue(propertyName, attribute.getValue()); - } - } - - private void retrieveOptionalNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName), "Illegal property name returned, it must not be null or empty."); - String variableName = el.getLocalName() + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - } - } - - private void retrieveTextContentAndNodeAttributes(Element element, String elementName, BeanDefinitionBuilder builder) { - if (!DomUtils.getChildElementsByTagName(element, elementName).isEmpty()) { - Element el1 = DomUtils.getChildElementsByTagName(element, elementName).get(0); - NamedNodeMap attributes = el1.getAttributes(); - for (int x = 0; x < attributes.getLength(); x++) { - Attr attribute = (Attr) attributes.item(x); - String propertyName1 = Conventions.attributeNameToPropertyName(attribute.getLocalName()); - Assert.state(StringUtils.isNotBlank(propertyName1), "Illegal property name returned, it must not be null or empty."); - String variableName = el1.getLocalName() + propertyName1.substring(0, 1).toUpperCase() + propertyName1.substring(1); - builder.addPropertyValue(variableName, attribute.getValue()); - } - Element el = DomUtils.getChildElementsByTagName(element, elementName).get(0); - builder.addPropertyValue(elementName, el.getTextContent()); - } - } - - private void retrieveParamNodeData(Element element, BeanDefinitionBuilder builder, String paramType) { - if (!DomUtils.getChildElementsByTagName(element, paramType).isEmpty()) { - Map params = new HashMap<>(); - List elements = DomUtils.getChildElementsByTagName(element, paramType); - elements.forEach(e -> { - String name = e.getAttribute(NAME); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(name), "Illegal attribute value returned. The 'name' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - params.put(name, value); - }); - builder.addPropertyValue(paramType, params); - } - } - - private void retrieveResponseNodeData(Element element, BeanDefinitionBuilder builder) { - - if (!DomUtils.getChildElementsByTagName(element, RESPONSE).isEmpty()) { - Element response = DomUtils.getChildElementsByTagName(element, RESPONSE).get(0); - List elements = DomUtils.getChildElements(response); - - Map responseVariable = new HashMap<>(); - Map responseValue = new HashMap<>(); - - for (int i = 0; i < elements.size(); i++) { - Element e = elements.get(i); - - if (e.getTagName().contains(RESPONSE_JSONPATH) || e.getTagName().contains(RESPONSE_XPATH)) { - String expression = e.getAttribute(EXPRESSION); - String value = e.getAttribute(VALUE); - - Assert.state(StringUtils.isNotBlank(expression), "Illegal attribute value returned. The 'expression' attribute must not be null or empty."); - Assert.state(StringUtils.isNotBlank(value), "Illegal attribute value returned. The 'value' attribute must not be null or empty."); - - // variable to save @variable('ebid')@ else value to validate - if (value.matches("\\@variable\\('.*'\\)\\@")) { - Matcher match = Pattern.compile("\\'(.*?)\\'").matcher(value); - if (match.find()) { - responseVariable.put(expression, value.substring(match.start() + 1, match.end() - 1)); - } - } else { - responseValue.put(expression, value); - } - } else if (e.getTagName().contains(SCRIPT)) { - String script = e.getTextContent(); - Assert.state(StringUtils.isNotBlank(script), "Illegal attribute value returned. The 'script' attribute must not be null or empty."); - builder.addPropertyValue(SCRIPT, script); - - if (!e.getAttribute(TYPE).isEmpty()) { - String type = e.getAttribute(TYPE); - Assert.state(StringUtils.isNotBlank(type), "Illegal attribute value returned. The 'type' attribute must not be null or empty."); - builder.addPropertyValue(TYPE, type); - } - } else if (e.getTagName().contains(RESPONSE_RESOURCE)) { - String filePath = e.getAttribute(FILE); - Assert.state(StringUtils.isNotBlank(filePath), "Illegal attribute value returned. The 'file' attribute must not be null or empty."); - builder.addPropertyValue(RESPONSE_RESOURCE, filePath); - } - - } - - builder.addPropertyValue(RESPONSE_VARIABLE, responseVariable); - builder.addPropertyValue(RESPONSE_VALUE, responseValue); - } - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java deleted file mode 100644 index 6454ee52fa..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/citrus/extension/OpenApiFromWsdlNamespaceHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.soap.bookservice.citrus.extension; - -import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; -import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlBeanDefinitionParser; - -import org.springframework.beans.factory.xml.NamespaceHandlerSupport; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class OpenApiFromWsdlNamespaceHandler extends NamespaceHandlerSupport { - - @Override - public void init() { - registerBeanDefinitionParser("addBookRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.AddBookRequest.class)); - registerBeanDefinitionParser("getAllBooksRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.GetAllBooksRequest.class)); - registerBeanDefinitionParser("getBookRequest", new OpenApiFromWsdlBeanDefinitionParser(BookServiceSoapApi.GetBookRequest.class)); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java deleted file mode 100644 index ae5505df35..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ /dev/null @@ -1,339 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.soap.bookservice.request; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.testapi.GeneratedApi; -import org.citrusframework.testapi.GeneratedApiRequest; -import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; -import org.citrusframework.spi.Resources; -import org.citrusframework.util.FileUtils; -import org.citrusframework.ws.actions.SendSoapMessageAction; -import org.citrusframework.ws.actions.SendSoapMessageAction.Builder.SendSoapMessageBuilderSupport; -import org.citrusframework.ws.actions.SoapActionBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.util.CollectionUtils; - -import org.citrusframework.openapi.generator.soap.bookservice.citrus.OpenApiFromWsdlAbstractTestRequest; - -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class BookServiceSoapApi implements GeneratedApi -{ - public static final BookServiceSoapApi INSTANCE = new BookServiceSoapApi(); - - public String getApiTitle() { - return "Generated api from wsdl"; - } - - public String getApiVersion() { - return "1.0.0"; - } - - public String getApiPrefix() { - return "OpenApiFromWsdl"; - } - - public Map getApiInfoExtensions() { - Map infoExtensionMap = new HashMap<>(); - return infoExtensionMap; - } - - /** - addBook (POST /AddBook) - - - **/ - public static class AddBookRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { - - private final Logger coverageLogger = LoggerFactory.getLogger(AddBookRequest.class); - - // Query params - - - public AddBookRequest(){ - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("OpenApiFromWsdl".toLowerCase() + ":addBookRequestType"); - } - - public String getOperationName() { - return "addBook"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/AddBook"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - - SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); - SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport.soapAction("addBook"); - - String payload = null; - String payloadType = null; - - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - if (!CollectionUtils.isEmpty(soapHeaders)) { - for (Entry entry : soapHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), - entry.getValue()); - } - } - - if (!CollectionUtils.isEmpty(mimeHeaders)) { - for (Entry entry : mimeHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), - entry.getValue()); - } - } - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); - - soapSendMessageActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "addBook;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); - } - - - } - /** - getAllBooks (POST /GetAllBooks) - - - **/ - public static class GetAllBooksRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { - - private final Logger coverageLogger = LoggerFactory.getLogger(GetAllBooksRequest.class); - - // Query params - - - public GetAllBooksRequest(){ - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("OpenApiFromWsdl".toLowerCase() + ":getAllBooksRequestType"); - } - - public String getOperationName() { - return "getAllBooks"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/GetAllBooks"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - - SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); - SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport.soapAction("getAllBooks"); - - String payload = null; - String payloadType = null; - - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - if (!CollectionUtils.isEmpty(soapHeaders)) { - for (Entry entry : soapHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), - entry.getValue()); - } - } - - if (!CollectionUtils.isEmpty(mimeHeaders)) { - for (Entry entry : mimeHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), - entry.getValue()); - } - } - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); - - soapSendMessageActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getAllBooks;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); - } - - - } - /** - getBook (POST /GetBook) - - - **/ - public static class GetBookRequest extends OpenApiFromWsdlAbstractTestRequest implements GeneratedApiRequest { - - private final Logger coverageLogger = LoggerFactory.getLogger(GetBookRequest.class); - - // Query params - - - public GetBookRequest(){ - // The name will be overwritten with the tag name using the actual namespace as prefix, when the class is loaded from xml - setName("OpenApiFromWsdl".toLowerCase() + ":getBookRequestType"); - } - - public String getOperationName() { - return "getBook"; - } - - public String getMethod() { - return "POST"; - } - - public String getPath() { - return "/GetBook"; - } - - /** - * This method sends the HTTP-Request - */ - public void sendRequest(TestContext context) { - - SendSoapMessageAction.Builder soapSendMessageActionBuilder = new SoapActionBuilder().client(wsClient).send(); - SendSoapMessageBuilderSupport messageBuilderSupport = soapSendMessageActionBuilder.getMessageBuilderSupport(); - - messageBuilderSupport.soapAction("getBook"); - - String payload = null; - String payloadType = null; - - if (StringUtils.isNotBlank(this.bodyFile)) { - try { - payload = FileUtils.readToString(Resources.create(this.bodyFile), FileUtils.getDefaultCharset()); - } catch (IOException e) { - throw new CitrusRuntimeException("Failed to read payload resource", e); - } - payloadType = this.bodyContentType; - } else if (StringUtils.isNotBlank(this.bodyLiteral)) { - payload = this.bodyLiteral; - payloadType = this.bodyLiteralContentType; - } - - String body = ""; - String bodyType = ""; - if(payload != null && payloadType != null) { - messageBuilderSupport.body(payload).contentType(payloadType); - body = context.replaceDynamicContentInString(payload); - bodyType = context.replaceDynamicContentInString(payloadType); - } - - if (!CollectionUtils.isEmpty(soapHeaders)) { - for (Entry entry : soapHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header(entry.getKey(), - entry.getValue()); - } - } - - if (!CollectionUtils.isEmpty(mimeHeaders)) { - for (Entry entry : mimeHeaders.entrySet()) { - messageBuilderSupport = messageBuilderSupport.header("citrus_http_" + entry.getKey(), - entry.getValue()); - } - } - - Map queryParams = new HashMap<>(); - - String query = queryParams.entrySet().stream().map(e -> "\"" + e.getKey() + "\":\"" + e.getValue() + "\"").collect(Collectors.joining(",", "{", "}")); - - soapSendMessageActionBuilder.withReferenceResolver(context.getReferenceResolver()); - soapSendMessageActionBuilder = customizeBuilder(INSTANCE, context, soapSendMessageActionBuilder); - - soapSendMessageActionBuilder.build().execute(context); - - coverageLogger.trace(coverageMarker, "getBook;POST;\"" + - query.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + - body.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\"\"") + "\";\"" + bodyType + "\""); - } - - - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java deleted file mode 100644 index b1bfeaee9d..0000000000 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/JavaCitrusCodegenIT/expectedgen/soap/bookservice/spring/OpenApiFromWsdlBeanConfiguration.java +++ /dev/null @@ -1,47 +0,0 @@ -/* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.citrusframework.openapi.generator.soap.bookservice.spring; - -import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; - -import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; - -@Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.JavaCitrusCodegen", date = "2024-07-03T15:24:46.256348400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class OpenApiFromWsdlBeanConfiguration { - - @Bean - @Scope(SCOPE_PROTOTYPE) - public BookServiceSoapApi.AddBookRequest addBookRequest() { - return new BookServiceSoapApi.AddBookRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public BookServiceSoapApi.GetAllBooksRequest getAllBooksRequest() { - return new BookServiceSoapApi.GetAllBooksRequest(); - } - - @Bean - @Scope(SCOPE_PROTOTYPE) - public BookServiceSoapApi.GetBookRequest getBookRequest() { - return new BookServiceSoapApi.GetBookRequest(); - } -} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd index c093acef11..3a735e7dd8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookDatatypes.xsd @@ -1,8 +1,8 @@ + This binding defines the SOAP over HTTP transport for BookService operations. + This operation retrieves details for a specific book identified by its ID. + soapAction="http://www.citrusframework.com/BookService/GetBook"> + Detailed Soap Operation documentation. + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index 134d44aee9..ce25d9119e 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -8,7 +8,7 @@ citrus-test-api-generator org.citrusframework - 4.3.0-SNAPSHOT + 4.4.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index 5b1d088727..f672feb374 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -17,7 +17,7 @@ package org.citrusframework.maven.plugin; import static java.lang.String.format; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.CODEGEN_NAME; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; import java.io.File; import java.util.HashMap; @@ -25,7 +25,7 @@ import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; -import org.citrusframework.openapi.generator.JavaCitrusCodegen; +import org.citrusframework.openapi.generator.CitrusJavaCodegen; import org.openapitools.codegen.plugin.CodeGenMojo; /** @@ -71,17 +71,17 @@ public CodeGenMojoWrapper configOptions(Map configOptionsPropert } public CodeGenMojoWrapper schemaFolder(String schemaFolder) { - configOptionsProperties.put(JavaCitrusCodegen.GENERATED_SCHEMA_FOLDER, schemaFolder); + configOptionsProperties.put(CitrusJavaCodegen.GENERATED_SCHEMA_FOLDER, schemaFolder); return this; } public CodeGenMojoWrapper resourceFolder(String resourceFolder) { - configOptionsProperties.put(JavaCitrusCodegen.RESOURCE_FOLDER, resourceFolder); + configOptionsProperties.put(CitrusJavaCodegen.RESOURCE_FOLDER, resourceFolder); return this; } public CodeGenMojoWrapper sourceFolder(String sourceFolder) { - configOptionsProperties.put(JavaCitrusCodegen.SOURCE_FOLDER, sourceFolder); + configOptionsProperties.put(CitrusJavaCodegen.SOURCE_FOLDER, sourceFolder); return this; } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index 0c079c7402..491ac48363 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -18,10 +18,10 @@ import static java.lang.String.format; import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_ENDPOINT; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.API_TYPE; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.PREFIX; -import static org.citrusframework.openapi.generator.JavaCitrusCodegen.TARGET_XMLNS_NAMESPACE; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_ENDPOINT; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_TYPE; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.PREFIX; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.TARGET_XMLNS_NAMESPACE; import com.google.common.annotations.VisibleForTesting; import java.io.File; diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java index 4cccffe386..3408d5f74d 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -21,7 +21,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; @@ -31,7 +30,6 @@ import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.TestCaseFailedException; import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiType; import org.citrusframework.maven.plugin.stubs.CitrusOpenApiGeneratorMavenProjectStub; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; @@ -49,16 +47,14 @@ class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { * testing scenario. */ private static final String[] STANDARD_FILE_PATH_TEMPLATES = new String[]{ - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/extension/%CAMEL_PREFIX%NamespaceHandler.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/%CAMEL_PREFIX%AbstractTestRequest.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/citrus/%CAMEL_PREFIX%BeanDefinitionParser.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/%CAMEL_PREFIX%.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%NamespaceHandler.java", "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%BeanConfiguration.java", "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingReqType.java", "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingRespType.java", "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PingApi.java", "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PungApi.java", - "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%SCHEMA_FOLDER%/%LOWER_PREFIX%-api.xsd", - "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%LOWER_PREFIX%-api-model.csv" + "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%SCHEMA_FOLDER%/%LOWER_PREFIX%-api.xsd" }; /** @@ -170,7 +166,6 @@ private void assertSpecificFileContent(ApiConfig apiConfig) { try { assertEndpointName(apiConfig); assertTargetNamespace(apiConfig); - assertApiType(apiConfig); assertSchemasInSpringSchemas(apiConfig); assertHandlersInSpringHandlers(apiConfig); } catch (IOException e) { @@ -207,18 +202,6 @@ private void assertSchemasInSpringSchemas(ApiConfig apiConfig) throws IOExceptio assertThat(getContentOfFile(apiConfig, "spring.schemas")).doesNotContain(OTHER_CITRUS_META_FILE_CONTENT); } - private void assertApiType(ApiConfig apiConfig) throws IOException { - String text; - switch (apiConfig.getType()) { - case REST -> text = "HttpClient httpClient"; - case SOAP -> text = "WebServiceClient wsClient"; - default -> throw new IllegalArgumentException(String.format("No apiTye set in ApiConfig. Expected one of %s", - stream(ApiType.values()).map(ApiType::toString).collect( - Collectors.joining()))); - } - assertThat(getContentOfFile(apiConfig, "AbstractTestRequest.java")).contains(text); - } - private void assertTargetNamespace(ApiConfig apiConfig) throws IOException { assertThat(getContentOfFile(apiConfig, "-api.xsd")).contains( String.format("targetNamespace=\"%s\"", @@ -226,7 +209,7 @@ private void assertTargetNamespace(ApiConfig apiConfig) throws IOException { } private void assertEndpointName(ApiConfig apiConfig) throws IOException { - assertThat(getContentOfFile(apiConfig, "AbstractTestRequest")).contains( + assertThat(getContentOfFile(apiConfig, "BeanConfiguration")).contains( String.format("@Qualifier(\"%s\")", apiConfig.qualifiedEndpoint())); } diff --git a/test-api-generator/citrus-test-api-spring/pom.xml b/test-api-generator/citrus-test-api-spring/pom.xml new file mode 100644 index 0000000000..ec7d3a6f95 --- /dev/null +++ b/test-api-generator/citrus-test-api-spring/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + org.citrusframework + citrus + 4.4.0-SNAPSHOT + ../../pom.xml + + + citrus-test-api-spring + Citrus :: Test API Spring + Citrus Test API Spring Integration + jar + + + 17 + 17 + UTF-8 + + + + + org.citrusframework + citrus-spring + ${project.version} + + + org.citrusframework + citrus-test-api-core + ${project.version} + + + + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java new file mode 100644 index 0000000000..6c8bed9e16 --- /dev/null +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java @@ -0,0 +1,194 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi.spring; + +import java.util.List; +import org.citrusframework.actions.ReceiveMessageAction; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.config.xml.AbstractReceiveMessageActionFactoryBean; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder; +import org.citrusframework.http.actions.HttpClientResponseActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.config.xml.HttpReceiveResponseActionParser; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageBuilder; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder.OpenApiClientResponseMessageBuilder; +import org.citrusframework.openapi.actions.OpenApiSpecificationSource; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.validation.context.ValidationContext; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +/** + * Parses XML configuration for receiving API responses based on OpenAPI specifications. Extends + * {@link HttpReceiveResponseActionParser} to handle OpenAPI-specific response builders and + * validation. + */ +public class RestApiReceiveMessageActionParser extends HttpReceiveResponseActionParser { + + /** + * The generated api bean class. + */ + private final Class apiBeanClass; + + /** + * The builder class for the receive message action. + */ + private final Class beanClass; + + /** + * The OpenAPI specification related to this parser. + */ + private final OpenApiSpecification openApiSpecification; + + /** + * The OpenAPI operationId associated with this parser. + */ + private final String operationId; + + private final String defaultApiEndpointName; + + public RestApiReceiveMessageActionParser(OpenApiSpecification openApiSpecification, + String operationId, + Class apiBeanClass, + Class beanClass, + String defaultApiEndpointName) { + this.openApiSpecification = openApiSpecification; + this.operationId = operationId; + this.apiBeanClass = apiBeanClass; + this.beanClass = beanClass; + this.defaultApiEndpointName = defaultApiEndpointName; + } + + @Override + protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, + ParserContext parserContext) { + + BeanDefinitionBuilder beanDefinitionBuilder = super.createBeanDefinitionBuilder(element, + parserContext); + + // Remove the messageBuilder property and inject it directly into the action builder. + BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); + OpenApiClientResponseMessageBuilder messageBuilder = (OpenApiClientResponseMessageBuilder) beanDefinition.getPropertyValues() + .get("messageBuilder"); + messageBuilder.statusCode(element.getAttribute("statusCode")); + + beanDefinition.getPropertyValues().removePropertyValue("messageBuilder"); + + BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + beanClass); + actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); + actionBuilder.addConstructorArgValue(openApiSpecification); + actionBuilder.addConstructorArgValue(messageBuilder); + + beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); + setDefaultEndpoint(beanDefinitionBuilder); + + return beanDefinitionBuilder; + } + + /** + * Sets the default endpoint for the message if not already specified. + */ + private void setDefaultEndpoint(BeanDefinitionBuilder beanDefinitionBuilder) { + if (!beanDefinitionBuilder.getBeanDefinition().getPropertyValues().contains("endpoint")) { + beanDefinitionBuilder.addPropertyReference("endpoint", defaultApiEndpointName); + } + } + + @Override + protected Class> getMessageFactoryClass() { + return TestApiOpenApiClientReceiveActionBuilderFactoryBean.class; + } + + @Override + protected void validateEndpointConfiguration(Element element) { + // skip validation, as we support endpoint injection + } + + @Override + protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { + return new OpenApiClientResponseMessageBuilder(httpMessage, + new OpenApiSpecificationSource(openApiSpecification), operationId, null); + } + + @Override + protected List parseValidationContexts(Element messageElement, + BeanDefinitionBuilder builder) { + List validationContexts = super.parseValidationContexts(messageElement, + builder); + OpenApiMessageValidationContext openApiMessageValidationContext = getOpenApiMessageValidationContext( + messageElement); + validationContexts.add(openApiMessageValidationContext); + return validationContexts; + } + + /** + * Constructs the OpenAPI message validation context based on the XML element. + */ + private OpenApiMessageValidationContext getOpenApiMessageValidationContext( + Element messageElement) { + OpenApiMessageValidationContext.Builder context = OpenApiMessageValidationContext.Builder.openApi( + openApiSpecification); + + if (messageElement != null) { + addSchemaInformationToValidationContext(messageElement, context); + } + + return context.build(); + } + + /** + * Factory bean for creating {@link ReceiveMessageAction} instances using the provided + * {@link RestApiReceiveMessageActionBuilder}. + */ + public static class TestApiOpenApiClientReceiveActionBuilderFactoryBean extends + AbstractReceiveMessageActionFactoryBean { + + private RestApiReceiveMessageActionBuilder builder; + + public TestApiOpenApiClientReceiveActionBuilderFactoryBean( + RestApiReceiveMessageActionBuilder builder) { + this.builder = builder; + } + + public void setBuilder(RestApiReceiveMessageActionBuilder builder) { + this.builder = builder; + } + + @Override + public ReceiveMessageAction getObject() { + return builder.build(); + } + + @Override + public Class getObjectType() { + return SendMessageAction.class; + } + + @Override + public HttpClientResponseActionBuilder getBuilder() { + return builder; + } + } + +} diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java new file mode 100644 index 0000000000..b244ef47cf --- /dev/null +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java @@ -0,0 +1,350 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi.spring; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; + +import java.util.List; +import java.util.stream.Collectors; +import org.citrusframework.actions.SendMessageAction; +import org.citrusframework.config.xml.AbstractSendMessageActionFactoryBean; +import org.citrusframework.config.xml.AbstractTestContainerFactoryBean; +import org.citrusframework.config.xml.AsyncParser.AsyncFactoryBean; +import org.citrusframework.config.xml.SequenceParser.SequenceFactoryBean; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.citrusframework.http.config.xml.HttpSendRequestActionParser; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.http.message.HttpMessageBuilder; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder.OpenApiClientRequestMessageBuilder; +import org.citrusframework.openapi.actions.OpenApiSpecificationSource; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder.TestApiClientRequestMessageBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.util.StringUtils; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Parses the XML configuration for sending API requests based on OpenAPI specifications. Extends + * {@link HttpSendRequestActionParser} to handle OpenAPI specific request and response builders. + */ +public class RestApiSendMessageActionParser extends HttpSendRequestActionParser { + + /** + * The generated api bean class. + */ + private final Class apiBeanClass; + + /** + * The builder class for the send message action. + */ + private final Class requestBeanClass; + + /** + * The builder class for the receive message action, required when using nested send/receive xml + * elements. + */ + private final Class receiveBeanClass; + + /** + * The OpenAPI specification that relates to the TestAPI classes. + */ + private final OpenApiSpecification openApiSpecification; + + /** + * The OpenAPI operationId, related to this parser + */ + private final String operationId; + + /** + * The OpenAPI operation path. + */ + private final String path; + + /** + * Constructor parameters for the requestBeanClass. + */ + private List constructorParameters = emptyList(); + + /** + * Optional non constructor parameters for the requestBeanClass. + */ + private List nonConstructorParameters = emptyList(); + + private final String defaultEndpointName; + + public RestApiSendMessageActionParser( + OpenApiSpecification openApiSpecification, + String operationId, + String path, + Class apiBeanClass, + Class sendBeanClass, + Class receiveBeanClass, + String defaultEndpointName) { + this.openApiSpecification = openApiSpecification; + this.operationId = operationId; + this.path = path; + this.apiBeanClass = apiBeanClass; + this.requestBeanClass = sendBeanClass; + this.receiveBeanClass = receiveBeanClass; + this.defaultEndpointName = defaultEndpointName; + } + + @Override + protected BeanDefinitionBuilder createBeanDefinitionBuilder(final Element element, + ParserContext parserContext) { + + BeanDefinitionBuilder beanDefinitionBuilder = super.createBeanDefinitionBuilder(element, + parserContext); + + BeanDefinitionBuilder actionBuilder = createTestApiActionBuilder( + element, beanDefinitionBuilder); + beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); + + setDefaultEndpoint(beanDefinitionBuilder); + + Element receive = DomUtils.getChildElementByTagName(element, "receive"); + if (receive != null) { + boolean fork = Boolean.parseBoolean(element.getAttribute("fork")); + return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, + beanDefinitionBuilder); + } + + return beanDefinitionBuilder; + } + + private BeanDefinitionBuilder createTestApiActionBuilder(Element element, + BeanDefinitionBuilder beanDefinitionBuilder) { + BeanDefinitionBuilder actionBuilder = propagateMessageBuilderToActionBuilder( + beanDefinitionBuilder); + readConstructorParameters(element, actionBuilder); + readNonConstructorParameters(element, actionBuilder); + return actionBuilder; + } + + /** + * Handles the configuration for both sending and receiving actions when a nested + * element is present in the XML specification. It creates appropriate builders for both sending + * and receiving messages and adds them to a container that executes these actions in sequence + * or asynchronously, depending on the {@code fork} parameter. + */ + private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, Element receive, + ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + + Class> containerClass = + fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; + + BeanDefinitionBuilder sequenceBuilder = BeanDefinitionBuilder.genericBeanDefinition( + containerClass); + + RestApiReceiveMessageActionParser receiveApiResponseActionParser = new RestApiReceiveMessageActionParser( + openApiSpecification, operationId, apiBeanClass, receiveBeanClass, defaultEndpointName); + BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse( + receive, parserContext); + + ManagedList actions = new ManagedList<>(); + actions.add(beanDefinitionBuilder.getBeanDefinition()); + actions.add(receiveResponseBeanDefinition); + + sequenceBuilder.addPropertyValue("actions", actions); + + return sequenceBuilder; + } + + /** + * Propagates the message builder created by the superclass into the specific send message + * action builder. + */ + private BeanDefinitionBuilder propagateMessageBuilderToActionBuilder( + BeanDefinitionBuilder beanDefinitionBuilder) { + + BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); + OpenApiClientRequestMessageBuilder messageBuilder = (OpenApiClientRequestMessageBuilder) beanDefinition.getPropertyValues() + .get("messageBuilder"); + beanDefinition.getPropertyValues().removePropertyValue("messageBuilder"); + + BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + requestBeanClass); + + actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); + actionBuilder.addConstructorArgValue(openApiSpecification); + actionBuilder.addConstructorArgValue(messageBuilder); + + return actionBuilder; + } + + /** + * Reads constructor parameters from the XML element and adds them as constructor arguments to + * the provided {@link BeanDefinitionBuilder}. + */ + private void readConstructorParameters(Element element, BeanDefinitionBuilder actionBuilder) { + + for (String parameterName : constructorParameters) { + if (element.hasAttribute(parameterName)) { + actionBuilder.addConstructorArgValue(element.getAttribute(parameterName)); + } else { + List values = collectChildNodeContents(element, parameterName); + actionBuilder.addConstructorArgValue(values); + } + } + } + + /** + * Reads non-constructor parameters from the XML element and adds them as properties to the + * provided {@link BeanDefinitionBuilder}. + */ + private void readNonConstructorParameters(Element element, + BeanDefinitionBuilder actionBuilder) { + + for (String parameterName : nonConstructorParameters) { + + if (isHandledBySuper(parameterName)) { + continue; + } + + // For java parameter types other that string, we need to use the non-typed java property + // with type string. These properties in java dsl are identified by a trailing '$'. In xml + // however, the trailing '$' is omitted. Thus, the respective names are prepared accordingly. + String attributeName = parameterName; + if (parameterName.endsWith("$")) { + attributeName = parameterName.substring(0, parameterName.length() - 1); + } + + Attr attribute = element.getAttributeNode(attributeName); + if (attribute != null) { + actionBuilder.addPropertyValue( + TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), + attribute.getValue()); + } else { + List values = collectChildNodeContents(element, attributeName); + if (values != null && !values.isEmpty()) { + actionBuilder.addPropertyValue( + TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), + values); + } + } + } + } + + private static List collectChildNodeContents(Element element, String parameterName) { + return DomUtils.getChildElementsByTagName(element, parameterName) + .stream() + .map(Node::getTextContent) + .filter(StringUtils::isNotEmpty) + .collect(Collectors.toList()); // For further processing, list must not be immutable + } + + /** + * Sets the default endpoint for TestApi actions, if not already specified. + */ + private void setDefaultEndpoint(BeanDefinitionBuilder beanDefinitionBuilder) { + if (!beanDefinitionBuilder.getBeanDefinition().getPropertyValues().contains("endpoint")) { + beanDefinitionBuilder.addPropertyReference("endpoint", defaultEndpointName); + } + } + + /** + * Checks if the property is handled by the superclass implementation. + * + * @param property The property name to check. + * @return True if handled by the superclass, false otherwise. + */ + private boolean isHandledBySuper(String property) { + return "body".equals(property); + } + + @Override + protected Class> getMessageFactoryClass() { + return TestApiOpenApiClientSendActionBuilderFactoryBean.class; + } + + @Override + protected void validateEndpointConfiguration(Element element) { + // skip validation, as we support endpoint injection + } + + @Override + protected Element getRequestElement(Element element) { + return element; + } + + @Override + protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { + httpMessage.path(path); + return new TestApiClientRequestMessageBuilder(httpMessage, + new OpenApiSpecificationSource(openApiSpecification), operationId); + } + + public void setConstructorParameters(String... constructorParameters) { + this.constructorParameters = + constructorParameters != null ? asList(constructorParameters) + : emptyList(); + } + + public void setNonConstructorParameters(String... nonConstructorParameters) { + this.nonConstructorParameters = + nonConstructorParameters != null ? asList(nonConstructorParameters) + : emptyList(); + } + + /** + * Factory bean for creating {@link SendMessageAction} instances using the provided + * {@link RestApiSendMessageActionBuilder}. + */ + public static class TestApiOpenApiClientSendActionBuilderFactoryBean extends + AbstractSendMessageActionFactoryBean { + + private RestApiSendMessageActionBuilder builder; + + public TestApiOpenApiClientSendActionBuilderFactoryBean( + RestApiSendMessageActionBuilder builder) { + this.builder = builder; + } + + public void setBuilder(RestApiSendMessageActionBuilder builder) { + this.builder = builder; + } + + @Override + public SendMessageAction getObject() { + return builder.build(); + } + + @Override + public Class getObjectType() { + return SendMessageAction.class; + } + + @Override + public HttpClientRequestActionBuilder getBuilder() { + return builder; + } + } + +} diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java new file mode 100644 index 0000000000..89d6617060 --- /dev/null +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java @@ -0,0 +1,96 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi.spring; + +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.util.StringUtils; +import org.citrusframework.ws.config.xml.ReceiveSoapMessageActionParser; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.w3c.dom.Element; + +public class SoapApiReceiveMessageActionParser extends ReceiveSoapMessageActionParser { + + /** + * The generated api bean class. + */ + private final Class apiBeanClass; + + /** + * The builder class for the receive message action. + */ + private final Class receiveBeanClass; + + private final String defaultEndpointName; + + public SoapApiReceiveMessageActionParser( + Class apiBeanClass, + Class beanClass, + String defaultEndpointName) { + this.apiBeanClass = apiBeanClass; + this.receiveBeanClass = beanClass; + this.defaultEndpointName = defaultEndpointName; + } + + @Override + protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { + BeanDefinitionBuilder beanDefinitionBuilder = super.parseComponent(element, parserContext); + + BeanDefinitionBuilder actionBuilder = createTestApiActionBuilder(); + beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); + + return beanDefinitionBuilder; + } + + protected String parseEndpoint(Element element) { + String endpointUri = element.getAttribute("endpoint"); + + if (!StringUtils.hasText(endpointUri)) { + endpointUri = defaultEndpointName; + } + return endpointUri; + } + + private BeanDefinitionBuilder createTestApiActionBuilder() { + + BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + receiveBeanClass); + actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); + + return actionBuilder; + } + + @Override + protected Class getMessageFactoryClass() { + return TestApiSoapClientReceiveActionBuilderFactoryBean.class; + } + + /** + * Test action factory bean. + */ + public static class TestApiSoapClientReceiveActionBuilderFactoryBean extends + ReceiveSoapMessageActionFactoryBean { + + public TestApiSoapClientReceiveActionBuilderFactoryBean( + SoapApiReceiveMessageActionBuilder builder) { + super(builder); + } + } + +} diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java new file mode 100644 index 0000000000..c498623a00 --- /dev/null +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java @@ -0,0 +1,147 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.testapi.spring; + +import org.citrusframework.config.xml.AbstractTestContainerFactoryBean; +import org.citrusframework.config.xml.AsyncParser.AsyncFactoryBean; +import org.citrusframework.config.xml.SequenceParser.SequenceFactoryBean; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +import org.citrusframework.util.StringUtils; +import org.citrusframework.ws.config.xml.SendSoapMessageActionParser; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; + +public class SoapApiSendMessageActionParser extends SendSoapMessageActionParser { + + /** + * The generated api bean class. + */ + private final Class apiBeanClass; + + /** + * The builder class for the send message action. + */ + private final Class sendBeanClass; + + /** + * The builder class for the receive message action, required when using nested send/receive xml + * elements. + */ + private final Class receiveBeanClass; + + private final String defaultEndpointName; + + public SoapApiSendMessageActionParser( + Class apiBeanClass, + Class sendBeanClass, + Class receiveBeanClass, + String defaultEndpointName) { + this.apiBeanClass = apiBeanClass; + this.sendBeanClass = sendBeanClass; + this.receiveBeanClass = receiveBeanClass; + this.defaultEndpointName = defaultEndpointName; + } + + @Override + public BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { + BeanDefinitionBuilder beanDefinitionBuilder = super.parseComponent(element, parserContext); + + BeanDefinitionBuilder actionBuilder = createTestApiActionBuilder(); + beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); + + Element receive = DomUtils.getChildElementByTagName(element, "receive"); + if (receive != null) { + boolean fork = Boolean.parseBoolean(element.getAttribute("fork")); + return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, + beanDefinitionBuilder); + } + + return beanDefinitionBuilder; + } + + protected String parseEndpoint(Element element) { + String endpointUri = element.getAttribute("endpoint"); + + if (!StringUtils.hasText(endpointUri)) { + endpointUri = defaultEndpointName; + } + return endpointUri; + } + + private BeanDefinitionBuilder createTestApiActionBuilder() { + + BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( + sendBeanClass); + actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); + + return actionBuilder; + } + + + @Override + protected Class getMessageFactoryClass() { + return TestApiSoapClientSendActionBuilderFactoryBean.class; + } + + /** + * Handles the configuration for both sending and receiving actions when a nested + * element is present in the XML specification. It creates appropriate builders for both sending + * and receiving messages and adds them to a container that executes these actions in sequence + * or asynchronously, depending on the {@code fork} parameter. + */ + private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, Element receive, + ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + + Class> containerClass = + fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; + + BeanDefinitionBuilder sequenceBuilder = BeanDefinitionBuilder.genericBeanDefinition( + containerClass); + + SoapApiReceiveMessageActionParser receiveApiResponseActionParser = new SoapApiReceiveMessageActionParser( + apiBeanClass, receiveBeanClass, defaultEndpointName); + BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse( + receive, parserContext); + + ManagedList actions = new ManagedList<>(); + actions.add(beanDefinitionBuilder.getBeanDefinition()); + actions.add(receiveResponseBeanDefinition); + + sequenceBuilder.addPropertyValue("actions", actions); + + return sequenceBuilder; + } + + /** + * Test action factory bean. + */ + public static class TestApiSoapClientSendActionBuilderFactoryBean extends + SendSoapMessageActionFactoryBean { + + public TestApiSoapClientSendActionBuilderFactoryBean( + SoapApiSendMessageActionBuilder builder) { + super(builder); + } + } +} diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index c3776c4931..025be2115a 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -6,7 +6,7 @@ org.citrusframework citrus - 4.3.0-SNAPSHOT + 4.4.0-SNAPSHOT ../pom.xml @@ -20,8 +20,10 @@ + citrus-test-api-core citrus-test-api-generator-core citrus-test-api-generator-maven-plugin + citrus-test-api-spring From c7d90fe4f80c91d31c857c9bb93ac5b4f7b366fe Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Tue, 15 Oct 2024 22:44:07 +0200 Subject: [PATCH 18/47] fix: pom structure --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 86e72604de..fae7d57f2e 100644 --- a/pom.xml +++ b/pom.xml @@ -58,7 +58,6 @@ test-api-generator tools utils - utils validation @@ -536,11 +535,6 @@ provided - - org.springframework - spring-test - ${spring.version} - org.testng testng From 9347c9411e5ce7b529cc4d3f186b6b9384b2a337 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Mon, 21 Oct 2024 16:41:15 +0200 Subject: [PATCH 19/47] chore(citrus-openapi): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-openapi` module. --- connectors/citrus-openapi/pom.xml | 1 - .../openapi/OpenApiConstants.java | 2 +- .../openapi/OpenApiRepository.java | 110 +- .../openapi/OpenApiResourceLoader.java | 73 +- .../openapi/OpenApiSettings.java | 12 +- .../openapi/OpenApiSpecification.java | 209 +- .../openapi/OpenApiSpecificationAdapter.java | 27 - .../OpenApiSpecificationProcessor.java | 18 +- .../openapi/OpenApiTestDataGenerator.java | 19 +- .../OpenApiTestValidationDataGenerator.java | 74 +- .../openapi/actions/OpenApiActionBuilder.java | 254 +- .../actions/OpenApiClientActionBuilder.java | 16 +- .../OpenApiClientRequestActionBuilder.java | 166 +- .../OpenApiClientResponseActionBuilder.java | 138 +- .../actions/OpenApiPayloadBuilder.java | 32 +- .../actions/OpenApiServerActionBuilder.java | 12 +- .../OpenApiServerRequestActionBuilder.java | 206 +- .../OpenApiServerResponseActionBuilder.java | 140 +- .../actions/OpenApiSpecificationSource.java | 25 +- .../openapi/model/OasModelHelper.java | 127 +- .../openapi/model/OpenApiVersion.java | 6 +- .../openapi/model/OperationPathAdapter.java | 4 +- .../openapi/model/v2/Oas20ModelHelper.java | 90 +- .../openapi/model/v3/Oas30ModelHelper.java | 50 +- .../openapi/random/RandomArrayGenerator.java | 39 +- .../random/RandomCompositeGenerator.java | 46 +- .../openapi/random/RandomConfiguration.java | 44 +- .../openapi/random/RandomContext.java | 61 +- .../openapi/random/RandomEnumGenerator.java | 11 +- .../openapi/random/RandomGenerator.java | 19 +- .../random/RandomGeneratorBuilder.java | 6 +- .../openapi/random/RandomModelBuilder.java | 34 +- .../openapi/random/RandomModelWriter.java | 15 +- .../openapi/random/RandomNumberGenerator.java | 139 +- .../openapi/random/RandomObjectGenerator.java | 23 +- .../openapi/random/RandomStringGenerator.java | 5 +- .../openapi/util/OpenApiUtils.java | 31 +- .../OpenApiMessageValidationContext.java | 19 +- ...piOperationToMessageHeadersProcessor.java} | 28 +- .../validation/OpenApiRequestValidator.java | 56 +- .../validation/OpenApiResponseValidator.java | 24 +- .../validation/OpenApiSchemaValidation.java | 148 +- .../validation/OpenApiValidationContext.java | 11 +- .../OpenApiValidationContextLoader.java | 19 +- .../openapi/validation/OpenApiValidator.java | 5 +- .../openapi/xml/ObjectFactory.java | 3 - .../citrusframework/openapi/xml/OpenApi.java | 2 + .../citrusframework/openapi/yaml/OpenApi.java | 2 + .../openapi/OpenApiMessageTypeTest.java | 4 +- .../openapi/OpenApiRepositoryTest.java | 12 +- .../openapi/OpenApiSettingsTest.java | 14 +- .../OpenApiSpecificationAdapterTest.java | 49 - .../openapi/OpenApiSpecificationTest.java | 116 +- .../openapi/OpenApiTestDataGeneratorTest.java | 419 ++- ...penApiTestValidationDataGeneratorTest.java | 149 +- .../openapi/OpenApiUtilsTest.java | 44 +- .../OpenApiClientActionBuilderTest.java | 6 +- .../actions/OpenApiPayloadBuilderTest.java | 24 +- .../OpenApiServerActionBuilderTest.java | 6 +- .../groovy/AbstractGroovyActionDslTest.java | 2 +- .../openapi/groovy/OpenApiClientTest.java | 157 +- .../openapi/groovy/OpenApiServerTest.java | 65 +- .../openapi/integration/OpenApiClientIT.java | 126 +- .../openapi/integration/OpenApiServerIT.java | 316 +- .../model/OperationPathAdapterTest.java | 3 +- .../model/v2/Oas20ModelHelperTest.java | 8 +- .../model/v3/Oas30ModelHelperTest.java | 17 +- .../random/OasRandomConfigurationTest.java | 8 +- .../random/RandomArrayGeneratorTest.java | 12 +- .../random/RandomCompositeGeneratorTest.java | 15 +- .../openapi/random/RandomContextTest.java | 25 +- .../openapi/random/RandomElementTest.java | 4 +- .../random/RandomEnumGeneratorTest.java | 14 +- .../random/RandomGeneratorBuilderTest.java | 50 +- .../openapi/random/RandomGeneratorTest.java | 15 +- .../random/RandomModelBuilderTest.java | 28 +- .../random/RandomNumberGeneratorTest.java | 47 +- .../random/RandomObjectGeneratorTest.java | 29 +- .../random/RandomStringGeneratorTest.java | 8 +- ...erationToMessageHeadersProcessorTest.java} | 22 +- .../OpenApiRequestValidatorTest.java | 44 +- .../OpenApiResponseValidatorTest.java | 35 +- .../openapi/xml/AbstractXmlActionTest.java | 2 +- .../openapi/xml/OpenApiClientTest.java | 22 +- .../openapi/xml/OpenApiServerTest.java | 65 +- .../openapi/yaml/AbstractYamlActionTest.java | 2 +- .../openapi/yaml/OpenApiClientTest.java | 23 +- .../openapi/yaml/OpenApiServerTest.java | 65 +- .../testapi/ApiActionBuilderCustomizer.java | 4 +- .../openapi/testapi/GeneratedApi.java | 6 +- .../testapi/OpenApiParameterFormatter.java | 41 +- .../RestApiReceiveMessageActionBuilder.java | 17 +- .../RestApiSendMessageActionBuilder.java | 187 +- .../SoapApiReceiveMessageActionBuilder.java | 9 +- .../SoapApiSendMessageActionBuilder.java | 7 +- .../openapi/testapi/TestApiUtils.java | 2 +- .../OpenApiParameterFormatterTest.java | 75 +- .../openapi/testapi/TestApiUtilsTest.java | 6 +- .../openapi/generator/CitrusJavaCodegen.java | 265 +- .../generator/WsdlToOpenApiTransformer.java | 60 +- .../generator/CitrusJavaCodegenTest.java | 63 +- .../openapi/generator/ExpectedCodeGenIT.java | 137 +- .../openapi/generator/GeneratedRestApiIT.java | 2875 +++++++++-------- .../openapi/generator/GeneratedSoapApiIT.java | 94 +- .../GeneratedSpringBeanConfigurationIT.java | 22 +- .../WsdlToOpenApiTransformerTest.java | 13 +- .../generator/util/MultipartConverter.java | 11 +- .../rest/extpetstore/model/Category.java | 175 +- .../extpetstore/model/HistoricalData.java | 179 +- .../rest/extpetstore/model/Pet.java | 409 ++- .../rest/extpetstore/model/Tag.java | 175 +- .../model/VaccinationDocumentResult.java | 136 +- .../rest/extpetstore/request/ExtPetApi.java | 1168 ++++--- .../spring/ExtPetStoreBeanConfiguration.java | 11 +- .../spring/ExtPetStoreNamespaceHandler.java | 232 +- .../rest/petstore/model/Address.java | 291 +- .../rest/petstore/model/Category.java | 175 +- .../rest/petstore/model/Customer.java | 232 +- .../rest/petstore/model/ModelApiResponse.java | 214 +- .../rest/petstore/model/Order.java | 380 ++- .../expectedgen/rest/petstore/model/Pet.java | 409 ++- .../expectedgen/rest/petstore/model/Tag.java | 175 +- .../expectedgen/rest/petstore/model/User.java | 409 +-- .../rest/petstore/request/PetApi.java | 228 +- .../rest/petstore/request/StoreApi.java | 135 +- .../rest/petstore/request/UserApi.java | 167 +- .../spring/PetStoreBeanConfiguration.java | 15 +- .../spring/PetStoreNamespaceHandler.java | 148 +- .../request/BookServiceSoapApi.java | 35 +- .../maven/plugin/CodeGenMojoWrapper.java | 17 +- .../maven/plugin/SpringMetaFileGenerator.java | 96 +- .../maven/plugin/TestApiGeneratorMojo.java | 197 +- .../TestApiGeneratorMojoIntegrationTest.java | 147 +- .../plugin/TestApiGeneratorMojoUnitTest.java | 211 +- ...itrusOpenApiGeneratorMavenProjectStub.java | 7 +- .../RestApiReceiveMessageActionParser.java | 47 +- .../RestApiSendMessageActionParser.java | 106 +- .../SoapApiReceiveMessageActionParser.java | 12 +- .../SoapApiSendMessageActionParser.java | 26 +- 139 files changed, 7323 insertions(+), 7608 deletions(-) delete mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java rename connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/{OpenApiMessageProcessor.java => OpenApiOperationToMessageHeadersProcessor.java} (60%) delete mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java rename connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/{OpenApiMessageProcessorTest.java => OpenApiOperationToMessageHeadersProcessorTest.java} (76%) diff --git a/connectors/citrus-openapi/pom.xml b/connectors/citrus-openapi/pom.xml index b182d4d4ad..3dc018d1c3 100644 --- a/connectors/citrus-openapi/pom.xml +++ b/connectors/citrus-openapi/pom.xml @@ -48,7 +48,6 @@ com.atlassian.oai swagger-request-validator-core - ${swagger-request-validator.version} com.fasterxml.jackson.datatype diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java index d6802ed996..fd40e3e8f2 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiConstants.java @@ -16,7 +16,7 @@ package org.citrusframework.openapi; -public abstract class OpenApiConstants { +public final class OpenApiConstants { public static final String TYPE_ARRAY = "array"; public static final String TYPE_BOOLEAN = "boolean"; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 7479040c33..99c568fbcc 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -16,6 +16,7 @@ package org.citrusframework.openapi; +import jakarta.annotation.Nullable; import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; import org.slf4j.Logger; @@ -25,11 +26,12 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * OpenApi repository holding a set of {@link OpenApiSpecification} known in the test scope. * @@ -60,50 +62,6 @@ public OpenApiRepository() { super(DEFAULT_NAME); } - public String getRootContextPath() { - return rootContextPath; - } - - public void setRootContextPath(String rootContextPath) { - this.rootContextPath = rootContextPath; - } - - public boolean isRequestValidationEnabled() { - return requestValidationEnabled; - } - - public void setRequestValidationEnabled(boolean requestValidationEnabled) { - this.requestValidationEnabled = requestValidationEnabled; - } - - public boolean isResponseValidationEnabled() { - return responseValidationEnabled; - } - - public void setResponseValidationEnabled(boolean responseValidationEnabled) { - this.responseValidationEnabled = responseValidationEnabled; - } - - /** - * Adds an OpenAPI Specification specified by the given resource to the repository. - * If an alias is determined from the resource name, it is added to the specification. - * - * @param openApiResource the resource to add as an OpenAPI specification - */ - @Override - public void addRepository(Resource openApiResource) { - OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); - determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); - openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); - openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); - openApiSpecification.setRootContextPath(rootContextPath); - - this.openApiSpecifications.add(openApiSpecification); - - OpenApiSpecificationProcessor.lookup().values() - .forEach(processor -> processor.process(openApiSpecification)); - } - /** * @param openApiResource the OpenAPI resource from which to determine the alias * @return an {@code Optional} containing the resource alias if it can be resolved, otherwise an empty {@code Optional} @@ -117,7 +75,7 @@ static Optional determineResourceAlias(Resource openApiResource) { if (file != null) { resourceAlias = file.getName(); int index = resourceAlias.lastIndexOf("."); - if (index != -1 && index != resourceAlias.length()-1) { + if (index != -1 && index != resourceAlias.length() - 1) { resourceAlias = resourceAlias.substring(0, index); } return Optional.of(resourceAlias); @@ -129,14 +87,14 @@ static Optional determineResourceAlias(Resource openApiResource) { try { URL url = openApiResource.getURL(); if (url != null) { - String urlString = URLDecoder.decode(url.getPath(), StandardCharsets.UTF_8).replace("\\","/"); + String urlString = URLDecoder.decode(url.getPath(), UTF_8).replace("\\", "/"); int index = urlString.lastIndexOf("/"); resourceAlias = urlString; - if (index != -1 && index != urlString.length()-1) { - resourceAlias = resourceAlias.substring(index+1); + if (index != -1 && index != urlString.length() - 1) { + resourceAlias = resourceAlias.substring(index + 1); } index = resourceAlias.lastIndexOf("."); - if (index != -1 && index != resourceAlias.length()-1) { + if (index != -1 && index != resourceAlias.length() - 1) { resourceAlias = resourceAlias.substring(0, index); } @@ -152,12 +110,60 @@ public List getOpenApiSpecifications() { return openApiSpecifications; } + public String getRootContextPath() { + return rootContextPath; + } + + public void setRootContextPath(String rootContextPath) { + this.rootContextPath = rootContextPath; + } + + public boolean isRequestValidationEnabled() { + return requestValidationEnabled; + } + + public void setRequestValidationEnabled(boolean requestValidationEnabled) { + this.requestValidationEnabled = requestValidationEnabled; + } + + public boolean isResponseValidationEnabled() { + return responseValidationEnabled; + } + + public void setResponseValidationEnabled(boolean responseValidationEnabled) { + this.responseValidationEnabled = responseValidationEnabled; + } + + /** + * Adds an OpenAPI Specification specified by the given resource to the repository. + * If an alias is determined from the resource name, it is added to the specification. + * + * @param openApiResource the resource to add as an OpenAPI specification + */ + @Override + public void addRepository(Resource openApiResource) { + OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); + determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); + openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); + openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); + openApiSpecification.setRootContextPath(rootContextPath); + + this.openApiSpecifications.add(openApiSpecification); + + OpenApiSpecificationProcessor.lookup() + .values() + .forEach(processor -> processor.process(openApiSpecification)); + } + public OpenApiRepository locations(List locations) { setLocations(locations); return this; } - public OpenApiSpecification openApi(String alias) { - return getOpenApiSpecifications().stream().filter(spec -> spec.getAliases().contains(alias)).findFirst().orElse(null); + public @Nullable OpenApiSpecification openApi(String alias) { + return getOpenApiSpecifications().stream() + .filter(spec -> spec.getAliases().contains(alias)) + .findFirst() + .orElse(null); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java index 7f4e31efa3..fc2c3deccd 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiResourceLoader.java @@ -21,28 +21,32 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.apicurio.datamodels.Library; import io.apicurio.datamodels.openapi.models.OasDocument; -import java.io.InputStream; -import java.net.URLConnection; import org.apache.hc.client5.http.ssl.NoopHostnameVerifier; import org.apache.hc.client5.http.ssl.TrustAllStrategy; -import org.apache.hc.core5.http.HttpHeaders; import org.apache.hc.core5.ssl.SSLContexts; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.Resource; -import org.citrusframework.util.FileUtils; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import java.io.IOException; +import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLConnection; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.util.Objects; +import static javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier; +import static javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory; +import static org.apache.hc.core5.http.HttpHeaders.ACCEPT; +import static org.apache.hc.core5.http.Method.GET; +import static org.citrusframework.util.FileUtils.getFileResource; +import static org.citrusframework.util.FileUtils.readToString; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + /** * Loads Open API specifications from different locations like file resource or web resource. */ @@ -63,15 +67,15 @@ private OpenApiResourceLoader() { * Loads the specification from a file resource. Either classpath or file system resource path is supported. */ public static OasDocument fromFile(String resource) { - return fromFile(FileUtils.getFileResource(resource), OAS_RESOLVER); + return fromFile(getFileResource(resource), OAS_RESOLVER); } /** * Loads the raw specification from a file resource. Either classpath or file system resource path is supported. */ public static String rawFromFile(String resource) { - return fromFile(FileUtils.getFileResource(resource), - RAW_RESOLVER); + return fromFile(getFileResource(resource), + RAW_RESOLVER); } /** @@ -90,7 +94,7 @@ public static String rawFromFile(Resource resource) { private static T fromFile(Resource resource, Resolver resolver) { try { - return resolve(FileUtils.readToString(resource), resolver); + return resolve(readToString(resource), resolver); } catch (IOException e) { throw new IllegalStateException("Failed to parse Open API specification: " + resource, e); } @@ -111,30 +115,29 @@ public static String rawFromWebResource(URL url) { } private static T fromWebResource(URL url, Resolver resolver) { - URLConnection con = null; + URLConnection connection = null; try { - con = url.openConnection(); + connection = url.openConnection(); - if (con instanceof HttpURLConnection httpURLConnection) { - httpURLConnection.setRequestMethod(HttpMethod.GET.name()); - con.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + if (connection instanceof HttpURLConnection httpURLConnection) { + httpURLConnection.setRequestMethod(GET.name()); + connection.setRequestProperty(ACCEPT, APPLICATION_JSON_VALUE); int status = httpURLConnection.getResponseCode(); if (status > 299) { throw new IllegalStateException( - "Failed to retrieve Open API specification: " + url, - new IOException(FileUtils.readToString(httpURLConnection.getErrorStream()))); + "Failed to retrieve Open API specification: " + url, + new IOException(readToString(httpURLConnection.getErrorStream()))); } } - try (InputStream inputStream = con.getInputStream()) { - return resolve(FileUtils.readToString(inputStream), resolver); + try (InputStream inputStream = connection.getInputStream()) { + return resolve(readToString(inputStream), resolver); } - } catch (IOException e) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url, e); } finally { - if (con instanceof HttpURLConnection httpURLConnection) { + if (connection instanceof HttpURLConnection httpURLConnection) { httpURLConnection.disconnect(); } } @@ -157,34 +160,34 @@ public static String rawFromSecuredWebResource(URL url) { private static T fromSecuredWebResource(URL url, Resolver resolver) { Objects.requireNonNull(url); - HttpsURLConnection con = null; + HttpsURLConnection connection = null; try { SSLContext sslcontext = SSLContexts - .custom() - .loadTrustMaterial(TrustAllStrategy.INSTANCE) - .build(); + .custom() + .loadTrustMaterial(TrustAllStrategy.INSTANCE) + .build(); - HttpsURLConnection.setDefaultSSLSocketFactory(sslcontext.getSocketFactory()); - HttpsURLConnection.setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE); + setDefaultSSLSocketFactory(sslcontext.getSocketFactory()); + setDefaultHostnameVerifier(NoopHostnameVerifier.INSTANCE); - con = (HttpsURLConnection) url.openConnection(); - con.setRequestMethod(HttpMethod.GET.name()); - con.setRequestProperty(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE); + connection = (HttpsURLConnection) url.openConnection(); + connection.setRequestMethod(GET.name()); + connection.setRequestProperty(ACCEPT, APPLICATION_JSON_VALUE); - int status = con.getResponseCode(); + int status = connection.getResponseCode(); if (status > 299) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url, - new IOException(FileUtils.readToString(con.getErrorStream()))); + new IOException(readToString(connection.getErrorStream()))); } else { - return resolve(FileUtils.readToString(con.getInputStream()), resolver); + return resolve(readToString(connection.getInputStream()), resolver); } } catch (NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) { throw new IllegalStateException("Failed to create https client for ssl connection", e); } catch (IOException e) { throw new IllegalStateException("Failed to retrieve Open API specification: " + url, e); } finally { - if (con != null) { - con.disconnect(); + if (connection != null) { + connection.disconnect(); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java index 02441f1115..df0c4bc0ea 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java @@ -43,23 +43,23 @@ private OpenApiSettings() { public static boolean isGenerateOptionalFieldsGlobally() { return parseBoolean(System.getProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) != null ? - System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) : "true")); + System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) : "true")); } public static boolean isValidateOptionalFieldsGlobally() { return parseBoolean(System.getProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) != null ? - System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) : "true")); + System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) : "true")); } public static boolean isRequestValidationEnabledGlobally() { return parseBoolean(System.getProperty( - REQUEST_VALIDATION_ENABLED_PROPERTY, System.getenv(REQUEST_VALIDATION_ENABLED_ENV) != null ? - System.getenv(REQUEST_VALIDATION_ENABLED_ENV) : "true")); + REQUEST_VALIDATION_ENABLED_PROPERTY, System.getenv(REQUEST_VALIDATION_ENABLED_ENV) != null ? + System.getenv(REQUEST_VALIDATION_ENABLED_ENV) : "true")); } public static boolean isResponseValidationEnabledGlobally() { return parseBoolean(System.getProperty( - RESPONSE_VALIDATION_ENABLED_PROPERTY, System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) != null ? - System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) : "true")); + RESPONSE_VALIDATION_ENABLED_PROPERTY, System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) != null ? + System.getenv(RESPONSE_VALIDATION_ENABLED_ENV) : "true")); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index a31d84019f..25d6eb320d 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -16,25 +16,9 @@ package org.citrusframework.openapi; -import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; - import io.apicurio.datamodels.core.models.common.Info; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Supplier; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.client.HttpClient; @@ -45,24 +29,44 @@ import org.citrusframework.openapi.validation.OpenApiValidationContextLoader; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; -import org.citrusframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +import static java.lang.String.format; +import static java.util.Collections.emptySet; +import static java.util.Collections.singletonList; +import static java.util.Collections.synchronizedSet; +import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; +import static org.citrusframework.util.StringUtils.hasText; +import static org.citrusframework.util.StringUtils.isEmpty; + /** - * OpenApi specification resolves URL or local file resources to a specification document. - *

      * The OpenApiSpecification class is responsible for handling the loading and processing of OpenAPI * specification documents from various sources, such as URLs or local files. It supports the * extraction and usage of key information from these documents, facilitating the interaction with * OpenAPI-compliant APIs. - *

      *

      * The class maintains a set of aliases derived from the OpenAPI document's information. These * aliases typically include the title of the API and its version, providing easy reference and * identification. For example, if the OpenAPI document's title is "Sample API" and its version is * "1.0", the aliases set will include "Sample API" and "Sample API/1.0". - *

      + *

      * Users are responsible for ensuring that the sources provided to this class have unique aliases, * or at least use the correct alias. If the same API is registered with different versions, all * versions will likely share the same title alias but can be distinguished by the version alias @@ -75,14 +79,30 @@ public class OpenApiSpecification { private static final Logger logger = LoggerFactory.getLogger(OpenApiSpecification.class); - public static final String HTTPS = "https"; - public static final String HTTP = "http"; + private static final String HTTPS = "https"; + private static final String HTTP = "http"; + + private final Set aliases = synchronizedSet(new HashSet<>()); + + /** + * Maps the identifier (id) of an operation to OperationPathAdapters. Two different keys may be + * used for each operation. Refer to + * {@link org.citrusframework.openapi.OpenApiSpecification#storeOperationPathAdapter} for more + * details. + */ + private final Map operationIdToOperationPathAdapter = new ConcurrentHashMap<>(); + + /** + * Stores the unique identifier (uniqueId) of an operation, derived from its HTTP method and + * path. This identifier can always be determined and is therefore safe to use, even for + * operations without an optional operationId defined. + */ + private final Map operationToUniqueId = new ConcurrentHashMap<>(); /** * URL to load the OpenAPI specification */ private String specUrl; - private String httpClient; private String requestUrl; @@ -92,19 +112,16 @@ public class OpenApiSpecification { * the base path and additional segments are used. */ private String rootContextPath; - private OasDocument openApiDoc; - private OpenApiValidationContext openApiValidationContext; - private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); - private boolean validateOptionalFields = isValidateOptionalFieldsGlobally(); /** * Flag to indicate, whether request validation is enabled on api level. Api level overrules global * level and may be overruled by request level. */ + private boolean apiRequestValidationEnabled = isRequestValidationEnabledGlobally(); /** @@ -113,23 +130,6 @@ public class OpenApiSpecification { */ private boolean apiResponseValidationEnabled = isResponseValidationEnabledGlobally(); - private final Set aliases = Collections.synchronizedSet(new HashSet<>()); - - /** - * Maps the identifier (id) of an operation to OperationPathAdapters. Two different keys may be - * used for each operation. Refer to - * {@link org.citrusframework.openapi.OpenApiSpecification#storeOperationPathAdapter} for more - * details. - */ - private final Map operationIdToOperationPathAdapter = new ConcurrentHashMap<>(); - - /** - * Stores the unique identifier (uniqueId) of an operation, derived from its HTTP method and - * path. This identifier can always be determined and is therefore safe to use, even for - * operations without an optional operationId defined. - */ - private final Map operationToUniqueId = new ConcurrentHashMap<>(); - public static OpenApiSpecification from(String specUrl) { OpenApiSpecification specification = new OpenApiSpecification(); specification.setSpecUrl(specUrl); @@ -143,10 +143,10 @@ public static OpenApiSpecification from(URL specUrl) { OpenApiValidationContext openApiValidationContext; if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); - openApiValidationContext = OpenApiValidationContextLoader.fromSecuredWebResource(specUrl); + openApiValidationContext = OpenApiValidationContextLoader.fromSecuredWebResource(specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); - openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl); + openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl); } specification.setSpecUrl(specUrl.toString()); @@ -154,9 +154,8 @@ public static OpenApiSpecification from(URL specUrl) { specification.setOpenApiDoc(openApiDoc); specification.setOpenApiValidationContext(openApiValidationContext); specification.setRequestUrl( - String.format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), - specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", - OasModelHelper.getBasePath(openApiDoc))); + format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", + OasModelHelper.getBasePath(openApiDoc))); return specification; } @@ -169,15 +168,14 @@ public static OpenApiSpecification from(Resource resource) { specification.setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource)); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList(HTTP)) - .stream() - .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) - .findFirst() - .orElse(HTTP); + .orElse(singletonList(HTTP)) + .stream() + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) + .findFirst() + .orElse(HTTP); specification.setSpecUrl(resource.getLocation()); - specification.setRequestUrl( - String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), + specification.setRequestUrl(format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), OasModelHelper.getBasePath(openApiDoc))); return specification; @@ -195,29 +193,26 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { // relative path URL - try to resolve with given request URL if (requestUrl != null) { resolvedSpecUrl = - requestUrl.endsWith("/") ? requestUrl + resolvedSpecUrl.substring(1) - : requestUrl + resolvedSpecUrl; - } else if (httpClient != null && context.getReferenceResolver() - .isResolvable(httpClient, HttpClient.class)) { + requestUrl.endsWith("/") ? requestUrl + resolvedSpecUrl.substring(1) + : requestUrl + resolvedSpecUrl; + } else if (httpClient != null && context.getReferenceResolver().isResolvable(httpClient, HttpClient.class)) { String baseUrl = context.getReferenceResolver() - .resolve(httpClient, HttpClient.class).getEndpointConfiguration() - .getRequestUrl(); + .resolve(httpClient, HttpClient.class).getEndpointConfiguration() + .getRequestUrl(); resolvedSpecUrl = baseUrl.endsWith("/") ? baseUrl + resolvedSpecUrl.substring(1) - : baseUrl + resolvedSpecUrl; + : baseUrl + resolvedSpecUrl; } else { throw new CitrusRuntimeException( - ("Failed to resolve OpenAPI spec URL from relative path %s - " + - "make sure to provide a proper base URL when using relative paths").formatted( - resolvedSpecUrl)); + ("Failed to resolve OpenAPI spec URL from relative path %s - " + + "make sure to provide a proper base URL when using relative paths").formatted( + resolvedSpecUrl)); } } if (resolvedSpecUrl.startsWith(HTTP)) { URL specWebResource = toSpecUrl(resolvedSpecUrl); if (resolvedSpecUrl.startsWith(HTTPS)) { - initApiDoc( - () -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); - + initApiDoc(() -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); setOpenApiValidationContext(OpenApiValidationContextLoader.fromSecuredWebResource(specWebResource)); } else { initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); @@ -225,29 +220,28 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { } if (requestUrl == null) { - setRequestUrl(String.format("%s://%s%s%s", specWebResource.getProtocol(), - specWebResource.getHost(), - specWebResource.getPort() > 0 ? ":" + specWebResource.getPort() : "", - OasModelHelper.getBasePath(openApiDoc))); + setRequestUrl(format("%s://%s%s%s", specWebResource.getProtocol(), + specWebResource.getHost(), + specWebResource.getPort() > 0 ? ":" + specWebResource.getPort() : "", + OasModelHelper.getBasePath(openApiDoc))); } } else { Resource resource = Resources.create(resolvedSpecUrl); - initApiDoc( - () -> OpenApiResourceLoader.fromFile(resource)); + initApiDoc(() -> OpenApiResourceLoader.fromFile(resource)); setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource)); if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) - .orElse(Collections.singletonList(HTTP)) - .stream() - .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) - .findFirst() - .orElse(HTTP); + .orElse(singletonList(HTTP)) + .stream() + .filter(s -> s.equals(HTTP) || s.equals(HTTPS)) + .findFirst() + .orElse(HTTP); setRequestUrl( - String.format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), - OasModelHelper.getBasePath(openApiDoc))); + format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), + OasModelHelper.getBasePath(openApiDoc))); } } } @@ -259,14 +253,19 @@ public OpenApiValidationContext getOpenApiValidationContext() { return openApiValidationContext; } + private void setOpenApiValidationContext(OpenApiValidationContext openApiValidationContext) { + this.openApiValidationContext = openApiValidationContext; + this.openApiValidationContext.setResponseValidationEnabled(apiResponseValidationEnabled); + this.openApiValidationContext.setRequestValidationEnabled(apiRequestValidationEnabled); + } - // provided for testing + // exposed for testing URL toSpecUrl(String resolvedSpecUrl) { try { return URI.create(resolvedSpecUrl).toURL(); } catch (MalformedURLException e) { throw new IllegalStateException( - "Failed to retrieve Open API specification as web resource: " + resolvedSpecUrl, e); + "Failed to retrieve Open API specification as web resource: " + resolvedSpecUrl, e); } } @@ -274,13 +273,6 @@ void setOpenApiDoc(OasDocument openApiDoc) { initApiDoc(() -> openApiDoc); } - private void setOpenApiValidationContext( - OpenApiValidationContext openApiValidationContext) { - this.openApiValidationContext = openApiValidationContext; - this.openApiValidationContext.setResponseValidationEnabled(apiResponseValidationEnabled); - this.openApiValidationContext.setRequestValidationEnabled(apiRequestValidationEnabled); - } - private void initApiDoc(Supplier openApiDocSupplier) { this.openApiDoc = openApiDocSupplier.get(); this.aliases.addAll(collectAliases(openApiDoc)); @@ -288,7 +280,6 @@ private void initApiDoc(Supplier openApiDocSupplier) { } private void initPathLookups() { - if (this.openApiDoc == null) { return; } @@ -297,13 +288,12 @@ private void initPathLookups() { OasModelHelper.visitOasOperations(this.openApiDoc, (oasPathItem, oasOperation) -> { String path = oasPathItem.getPath(); - if (StringUtils.isEmpty(path)) { + if (isEmpty(path)) { logger.warn("Skipping path item without path."); return; } - for (Map.Entry operationEntry : OasModelHelper.getOperationMap( - oasPathItem).entrySet()) { + for (Map.Entry operationEntry : OasModelHelper.getOperationMap(oasPathItem).entrySet()) { storeOperationPathAdapter(operationEntry.getValue(), path); } }); @@ -320,18 +310,16 @@ private void initPathLookups() { * @param path The full path of the operation, including the method. */ private void storeOperationPathAdapter(OasOperation operation, String path) { - String basePath = OasModelHelper.getBasePath(openApiDoc); - String fullOperationPath = StringUtils.appendSegmentToUrlPath(basePath, path); + String fullOperationPath = appendSegmentToUrlPath(basePath, path); String uniqueOperationId = OpenApiUtils.createFullPathOperationIdentifier(operation, fullOperationPath); operationToUniqueId.put(operation, uniqueOperationId); - OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, - StringUtils.appendSegmentToUrlPath(rootContextPath, path), operation, uniqueOperationId); + OperationPathAdapter operationPathAdapter = new OperationPathAdapter(path, rootContextPath, appendSegmentToUrlPath(rootContextPath, path), operation, uniqueOperationId); operationIdToOperationPathAdapter.put(uniqueOperationId, operationPathAdapter); - if (StringUtils.hasText(operation.operationId)) { + if (hasText(operation.operationId)) { operationIdToOperationPathAdapter.put(operation.operationId, operationPathAdapter); } } @@ -344,14 +332,14 @@ public void setSpecUrl(String specUrl) { this.specUrl = specUrl; } - public void setHttpClient(String httpClient) { - this.httpClient = httpClient; - } - public String getHttpClient() { return httpClient; } + public void setHttpClient(String httpClient) { + this.httpClient = httpClient; + } + public String getRequestUrl() { if (requestUrl == null) { return specUrl; @@ -421,27 +409,27 @@ public Set getAliases() { private Collection collectAliases(OasDocument document) { if (document == null) { - return Collections.emptySet(); + return emptySet(); } Info info = document.info; if (info == null) { - return Collections.emptySet(); + return emptySet(); } Set set = new HashSet<>(); - if (StringUtils.hasText(info.title)) { + if (hasText(info.title)) { set.add(info.title); - if (StringUtils.hasText(info.version)) { + if (hasText(info.version)) { set.add(info.title + "/" + info.version); } } + return set; } public Optional getOperation(String operationId, TestContext context) { - if (operationId == null) { return Optional.empty(); } @@ -463,5 +451,4 @@ public OpenApiSpecification withRootContext(String rootContextPath) { public String getUniqueId(OasOperation oasOperation) { return operationToUniqueId.get(oasOperation); } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java deleted file mode 100644 index 011a2dc7fd..0000000000 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationAdapter.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.citrusframework.openapi; - -/** - * Adapter class that links an OAS entity to its associated OpenAPI specification context. - * This class provides methods to access both the OpenAPI specification and the specific OAS entity. - * - * @param the type to which the specification is adapted. - */ -public record OpenApiSpecificationAdapter(OpenApiSpecification openApiSpecification, T entity) { - -} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java index ceeb9286d5..540ad87d9e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecificationProcessor.java @@ -28,21 +28,24 @@ *

      * This interface is designed to be implemented by custom processors that handle OpenAPI specifications. * Implementations of this interface are discovered by the standard citrus SPI mechanism. - *

      */ public interface OpenApiSpecificationProcessor { - /** Logger */ + /** + * Logger + */ Logger logger = LoggerFactory.getLogger(OpenApiSpecificationProcessor.class); - /** OpenAPI processors resource lookup path */ + /** + * OpenAPI processors resource lookup path + */ String RESOURCE_PATH = "META-INF/citrus/openapi/processor"; - /** Type resolver to find OpenAPI processors on classpath via resource path lookup */ + /** + * Type resolver to find OpenAPI processors on classpath via resource path lookup + */ TypeResolver TYPE_RESOLVER = new ResourcePathTypeResolver(RESOURCE_PATH); - void process(OpenApiSpecification openApiSpecification); - /** * Resolves all available processors from resource path lookup. Scans classpath for processors meta information * and instantiates those processors. @@ -51,10 +54,11 @@ static Map lookup() { Map processors = TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name"); if (logger.isDebugEnabled()) { - processors.forEach((k, v) -> logger.debug(String.format("Found openapi specification processor '%s' as %s", k, v.getClass()))); + processors.forEach((k, v) -> logger.debug("Found openapi specification processor '{}' as {}", k, v.getClass())); } return processors; } + void process(OpenApiSpecification openApiSpecification); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java index 106d06fd36..2f6db9e17d 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestDataGenerator.java @@ -24,7 +24,7 @@ /** * Generates proper payloads and validation expressions based on Open API specification rules. */ -public abstract class OpenApiTestDataGenerator { +public final class OpenApiTestDataGenerator { private OpenApiTestDataGenerator() { // Static access only @@ -33,8 +33,7 @@ private OpenApiTestDataGenerator() { /** * Creates payload from schema for outbound message. */ - public static String createOutboundPayload(OasSchema schema, - OpenApiSpecification specification) { + public static String createOutboundPayload(OasSchema schema, OpenApiSpecification specification) { RandomContext randomContext = new RandomContext(specification, true); randomContext.generate(schema); return randomContext.getRandomModelBuilder().write(); @@ -43,9 +42,7 @@ public static String createOutboundPayload(OasSchema schema, /** * Use test variable with given name if present or create value from schema with random values */ - public static String createRandomValueExpression(String name, OasSchema schema, OpenApiSpecification specification, - TestContext context) { - + public static String createRandomValueExpression(String name, OasSchema schema, OpenApiSpecification specification, TestContext context) { if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } @@ -53,23 +50,18 @@ public static String createRandomValueExpression(String name, OasSchema schema, RandomContext randomContext = new RandomContext(specification, false); randomContext.generate(schema); return randomContext.getRandomModelBuilder().write(); - } /** * Use test variable with given name (if present) or create random value expression using * functions according to schema type and format. */ - public static String createRandomValueExpression(String name, OasSchema schema, - TestContext context) { - + public static String createRandomValueExpression(String name, OasSchema schema, TestContext context) { if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } - RandomContext randomContext = new RandomContext(); - randomContext.generate(schema); - return randomContext.getRandomModelBuilder().write(); + return createRandomValueExpression(schema); } public static String createRandomValueExpression(OasSchema schema) { @@ -77,5 +69,4 @@ public static String createRandomValueExpression(OasSchema schema) { randomContext.generate(schema); return randomContext.getRandomModelBuilder().write(); } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java index 95033bb26c..be0fede27b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiTestValidationDataGenerator.java @@ -16,25 +16,25 @@ package org.citrusframework.openapi; -import static org.citrusframework.util.StringUtils.hasText; -import static org.springframework.util.CollectionUtils.isEmpty; - import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; -import java.util.Map; import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.model.OasModelHelper; +import org.citrusframework.openapi.util.OpenApiUtils; + +import java.util.Map; + +import static org.citrusframework.util.StringUtils.hasText; +import static org.springframework.util.CollectionUtils.isEmpty; /** * Generates proper payloads and validation expressions based on Open API specification rules. * Creates outbound payloads with generated random test data according to specification and creates * inbound payloads with proper validation expressions to enforce the specification rules. - * - * @author Christoph Deppisch */ -public abstract class OpenApiTestValidationDataGenerator { +public final class OpenApiTestValidationDataGenerator { private OpenApiTestValidationDataGenerator() { // Static access only @@ -44,7 +44,7 @@ private OpenApiTestValidationDataGenerator() { * Creates control payload from schema for validation. */ public static String createInboundPayload(OasSchema schema, Map definitions, - OpenApiSpecification specification) { + OpenApiSpecification specification) { if (OasModelHelper.isReferenceType(schema)) { OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); return createInboundPayload(resolved, definitions, specification); @@ -57,13 +57,13 @@ public static String createInboundPayload(OasSchema schema, Map entry : schema.properties.entrySet()) { if (specification.isValidateOptionalFields() || isRequired(schema, - entry.getKey())) { + entry.getKey())) { payload.append("\"") - .append(entry.getKey()) - .append("\": ") - .append(createValidationExpression(entry.getValue(), definitions, true, - specification)) - .append(","); + .append(entry.getKey()) + .append("\": ") + .append(createValidationExpression(entry.getValue(), definitions, true, + specification)) + .append(","); } } } @@ -76,7 +76,7 @@ public static String createInboundPayload(OasSchema schema, Map definitions, - boolean quotes, OpenApiSpecification specification, - TestContext context) { + Map definitions, + boolean quotes, OpenApiSpecification specification, + TestContext context) { if (context.getVariables().containsKey(name)) { return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } @@ -115,8 +111,8 @@ public static String createValidationExpression(String name, OasSchema schema, * Create validation expression using functions according to schema type and format. */ public static String createValidationExpression(OasSchema schema, - Map definitions, boolean quotes, - OpenApiSpecification specification) { + Map definitions, boolean quotes, + OpenApiSpecification specification) { if (OasModelHelper.isReferenceType(schema)) { OasSchema resolved = definitions.get(OasModelHelper.getReferenceName(schema.$ref)); return createValidationExpression(resolved, definitions, quotes, specification); @@ -129,14 +125,14 @@ public static String createValidationExpression(OasSchema schema, if (schema.properties != null) { for (Map.Entry entry : schema.properties.entrySet()) { if (specification.isValidateOptionalFields() || isRequired(schema, - entry.getKey())) { + entry.getKey())) { payload.append("\"") - .append(entry.getKey()) - .append("\": ") - .append( - createValidationExpression(entry.getValue(), definitions, quotes, - specification)) - .append(","); + .append(entry.getKey()) + .append("\": ") + .append( + createValidationExpression(entry.getValue(), definitions, quotes, + specification)) + .append(","); } } } @@ -175,7 +171,7 @@ private static String createValidationExpression(OasSchema schema) { } switch (schema.type) { - case OpenApiConstants.TYPE_STRING : + case OpenApiConstants.TYPE_STRING: if (schema.format != null && schema.format.equals("date")) { return "@matchesDatePattern('yyyy-MM-dd')@"; } else if (schema.format != null && schema.format.equals("date-time")) { @@ -184,13 +180,13 @@ private static String createValidationExpression(OasSchema schema) { return String.format("@matches(%s)@", schema.pattern); } else if (!isEmpty(schema.enum_)) { return String.format("@matches(%s)@", - String.join("|", schema.enum_)); + String.join("|", schema.enum_)); } else { return "@notEmpty()@"; } case OpenApiConstants.TYPE_NUMBER, OpenApiConstants.TYPE_INTEGER: return "@isNumber()@"; - case OpenApiConstants.TYPE_BOOLEAN : + case OpenApiConstants.TYPE_BOOLEAN: return "@matches(true|false)@"; default: return "@ignore@"; @@ -201,12 +197,10 @@ private static String createValidationExpression(OasSchema schema) { * Create validation expression using regex according to schema type and format. */ public static String createValidationRegex(String name, @Nullable OasSchema oasSchema) { - - if (oasSchema != null && (OasModelHelper.isReferenceType(oasSchema) - || OasModelHelper.isObjectType(oasSchema))) { + if (OasModelHelper.isReferenceType(oasSchema) || OasModelHelper.isObjectType(oasSchema)) { throw new CitrusRuntimeException(String.format( - "Unable to create a validation regex for an reference of object schema '%s'!", - name)); + "Unable to create a validation regex for an reference of object schema '%s'!", + name)); } return createValidationRegex(oasSchema); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java index 73ece7f474..d53817e3dd 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java @@ -35,136 +35,126 @@ */ public class OpenApiActionBuilder extends AbstractReferenceResolverAwareTestActionBuilder { - private OpenApiSpecificationSource openApiSpecificationSource; - - public OpenApiActionBuilder() { - } - - public OpenApiActionBuilder(OpenApiSpecification specification) { - this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); - } - - public OpenApiActionBuilder(String openApiAlias) { - this.openApiSpecificationSource = new OpenApiSpecificationSource(openApiAlias); - } - - /** - * Static entrance method for the OpenApi fluent action builder. - */ - public static OpenApiActionBuilder openapi() { - return new OpenApiActionBuilder(); - } - - public static OpenApiActionBuilder openapi(OpenApiSpecification specification) { - return new OpenApiActionBuilder(specification); - } - - public static OpenApiActionBuilder openapi(String openApiAlias) { - return new OpenApiActionBuilder(openApiAlias); - } - - public OpenApiActionBuilder specification(OpenApiSpecification specification) { - this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); - return this; - } - - public OpenApiActionBuilder specificationByAlias(String openApiAlias) { - this.openApiSpecificationSource = new OpenApiSpecificationSource(openApiAlias); - return this; - } - - public OpenApiActionBuilder specification(URL specUrl) { - return specification(OpenApiSpecification.from(specUrl)); - } - - public OpenApiActionBuilder specification(String specUrl) { - return specification(OpenApiSpecification.from(specUrl)); - } - - public OpenApiClientActionBuilder client() { - assertSpecification(); - OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder( - openApiSpecificationSource) - .withReferenceResolver(referenceResolver); - this.delegate = clientActionBuilder; - return clientActionBuilder; - } - - /** - * Initiate http client action. - */ - public OpenApiClientActionBuilder client(HttpClient httpClient) { - assertSpecification(); - - if (httpClient.getEndpointConfiguration().getRequestUrl() != null) { - openApiSpecificationSource.setHttpClient(httpClient.getEndpointConfiguration().getRequestUrl()); - } - - OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, - openApiSpecificationSource) - .withReferenceResolver(referenceResolver); - this.delegate = clientActionBuilder; - return clientActionBuilder; - } - - /** - * Initiate http client action. - */ - public OpenApiClientActionBuilder client(String httpClient) { - assertSpecification(); - - openApiSpecificationSource.setHttpClient(httpClient); - - OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, - openApiSpecificationSource) - .withReferenceResolver(referenceResolver); - this.delegate = clientActionBuilder; - return clientActionBuilder; - } - - /** - * Initiate http server action. - */ - public OpenApiServerActionBuilder server(Endpoint endpoint) { - assertSpecification(); - - OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(endpoint, - openApiSpecificationSource) - .withReferenceResolver(referenceResolver); - this.delegate = serverActionBuilder; - return serverActionBuilder; - } - - private void assertSpecification() { - if (openApiSpecificationSource == null) { - throw new CitrusRuntimeException("Invalid OpenApiSpecificationSource - please set specification first"); - } - } - - /** - * Initiate http server action. - */ - public OpenApiServerActionBuilder server(String httpServer) { - assertSpecification(); - - OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(httpServer, - openApiSpecificationSource) - .withReferenceResolver(referenceResolver); - this.delegate = serverActionBuilder; - return serverActionBuilder; - } - - /** - * Sets the bean reference resolver. - */ - public OpenApiActionBuilder withReferenceResolver(ReferenceResolver referenceResolver) { - this.referenceResolver = referenceResolver; - return this; - } - - @Override - public TestAction build() { - ObjectHelper.assertNotNull(delegate, "Missing delegate action to build"); - return delegate.build(); - } + private OpenApiSpecificationSource openApiSpecificationSource; + + public OpenApiActionBuilder() { + } + + public OpenApiActionBuilder(OpenApiSpecification specification) { + this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); + } + + public OpenApiActionBuilder(String openApiAlias) { + this.openApiSpecificationSource = new OpenApiSpecificationSource(openApiAlias); + } + + /** + * Static entrance method for the OpenApi fluent action builder. + */ + public static OpenApiActionBuilder openapi() { + return new OpenApiActionBuilder(); + } + + public static OpenApiActionBuilder openapi(OpenApiSpecification specification) { + return new OpenApiActionBuilder(specification); + } + + public static OpenApiActionBuilder openapi(String openApiAlias) { + return new OpenApiActionBuilder(openApiAlias); + } + + public OpenApiActionBuilder specification(OpenApiSpecification specification) { + this.openApiSpecificationSource = new OpenApiSpecificationSource(specification); + return this; + } + + public OpenApiActionBuilder specification(URL specUrl) { + return specification(OpenApiSpecification.from(specUrl)); + } + + public OpenApiActionBuilder specification(String specUrl) { + return specification(OpenApiSpecification.from(specUrl)); + } + + public OpenApiClientActionBuilder client() { + assertSpecification(); + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = clientActionBuilder; + return clientActionBuilder; + } + + /** + * Initiate http client action. + */ + public OpenApiClientActionBuilder client(HttpClient httpClient) { + assertSpecification(); + + if (httpClient.getEndpointConfiguration().getRequestUrl() != null) { + openApiSpecificationSource.setHttpClient(httpClient.getEndpointConfiguration().getRequestUrl()); + } + + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = clientActionBuilder; + return clientActionBuilder; + } + + /** + * Initiate http client action. + */ + public OpenApiClientActionBuilder client(String httpClient) { + assertSpecification(); + + openApiSpecificationSource.setHttpClient(httpClient); + + OpenApiClientActionBuilder clientActionBuilder = new OpenApiClientActionBuilder(httpClient, openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = clientActionBuilder; + return clientActionBuilder; + } + + /** + * Initiate http server action. + */ + public OpenApiServerActionBuilder server(Endpoint endpoint) { + assertSpecification(); + + OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(endpoint, openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = serverActionBuilder; + return serverActionBuilder; + } + + private void assertSpecification() { + if (openApiSpecificationSource == null) { + throw new CitrusRuntimeException("Invalid OpenApiSpecificationSource - please set specification first"); + } + } + + /** + * Initiate http server action. + */ + public OpenApiServerActionBuilder server(String httpServer) { + assertSpecification(); + + OpenApiServerActionBuilder serverActionBuilder = new OpenApiServerActionBuilder(httpServer, openApiSpecificationSource) + .withReferenceResolver(referenceResolver); + this.delegate = serverActionBuilder; + return serverActionBuilder; + } + + /** + * Sets the bean reference resolver. + */ + public OpenApiActionBuilder withReferenceResolver(ReferenceResolver referenceResolver) { + this.referenceResolver = referenceResolver; + return this; + } + + @Override + public TestAction build() { + ObjectHelper.assertNotNull(delegate, "Missing delegate action to build"); + return delegate.build(); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java index ed1b099e6b..5ff12aa381 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilder.java @@ -18,12 +18,13 @@ import org.citrusframework.TestAction; import org.citrusframework.endpoint.Endpoint; -import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.spi.AbstractReferenceResolverAwareTestActionBuilder; import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.util.ObjectHelper; import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.OK; + /** * Action executes http client operations such as sending requests and receiving responses. * @@ -33,7 +34,9 @@ public class OpenApiClientActionBuilder extends AbstractReferenceResolverAwareTe private final OpenApiSpecificationSource openApiSpecificationSource; - /** Target http client instance */ + /** + * Target http client instance + */ private Endpoint httpClient; private String httpClientUri; @@ -61,8 +64,7 @@ public OpenApiClientActionBuilder(OpenApiSpecificationSource openApiSpecificatio * Sends Http requests as client. */ public OpenApiClientRequestActionBuilder send(String operationId) { - OpenApiClientRequestActionBuilder builder = new OpenApiClientRequestActionBuilder( - openApiSpecificationSource, operationId); + OpenApiClientRequestActionBuilder builder = new OpenApiClientRequestActionBuilder(openApiSpecificationSource, operationId); if (httpClient != null) { builder.endpoint(httpClient); } else { @@ -81,7 +83,7 @@ public OpenApiClientRequestActionBuilder send(String operationId) { * Uses default Http status 200 OK. */ public OpenApiClientResponseActionBuilder receive(String operationId) { - return receive(operationId, HttpStatus.OK); + return receive(operationId, OK); } /** @@ -95,8 +97,7 @@ public OpenApiClientResponseActionBuilder receive(String operationId, HttpStatus * Receives Http response messages as client. */ public OpenApiClientResponseActionBuilder receive(String operationId, String statusCode) { - OpenApiClientResponseActionBuilder builder = new OpenApiClientResponseActionBuilder( - openApiSpecificationSource, operationId, statusCode); + OpenApiClientResponseActionBuilder builder = new OpenApiClientResponseActionBuilder(openApiSpecificationSource, operationId, statusCode); if (httpClient != null) { builder.endpoint(httpClient); } else { @@ -111,6 +112,7 @@ public OpenApiClientResponseActionBuilder receive(String operationId, String sta /** * Sets the bean reference resolver. + * * @param referenceResolver */ public OpenApiClientActionBuilder withReferenceResolver(ReferenceResolver referenceResolver) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index 3bd3e484cb..4f148af59b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -16,15 +16,9 @@ package org.citrusframework.openapi.actions; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; -import static org.citrusframework.util.StringUtils.isNotEmpty; - import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.List; -import java.util.Locale; -import java.util.Optional; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; @@ -33,47 +27,50 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.OpenApiTestDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +import static org.citrusframework.openapi.OpenApiMessageType.REQUEST; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.citrusframework.util.StringUtils.isNotEmpty; + /** * @since 4.1 */ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBuilder { - private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecificationSource openApiSpecificationSource; - private final String operationId; - + private OpenApiOperationToMessageHeadersProcessor openApiOperationToMessageHeadersProcessor; private boolean schemaValidation = true; /** * Default constructor initializes http request message builder. */ - public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, - String operationId) { + public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, String operationId) { this(new HttpMessage(), openApiSpec, operationId); } public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { - this(openApiSpec, new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), - httpMessage, operationId); + OpenApiSpecificationSource openApiSpec, + String operationId) { + this(openApiSpec, new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage, operationId); } public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, - OpenApiClientRequestMessageBuilder messageBuilder, HttpMessage message, - String operationId) { + OpenApiClientRequestMessageBuilder messageBuilder, + HttpMessage message, + String operationId) { super(messageBuilder, message); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; @@ -81,8 +78,7 @@ public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, @Override public SendMessageAction doBuild() { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( - referenceResolver); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); // Honor default enablement of schema validation OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); @@ -90,10 +86,9 @@ public SendMessageAction doBuild() { schemaValidation = openApiValidationContext.isRequestValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { - openApiMessageProcessor = new OpenApiMessageProcessor(openApiSpecification, operationId, - OpenApiMessageType.REQUEST); - process(openApiMessageProcessor); + if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, REQUEST); + process(openApiOperationToMessageHeadersProcessor); } return super.doBuild(); @@ -121,8 +116,8 @@ public static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilde private final String operationId; public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { + OpenApiSpecificationSource openApiSpec, + String operationId) { super(httpMessage); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; @@ -130,16 +125,15 @@ public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, @Override public Message build(TestContext context, String messageType) { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( - context.getReferenceResolver()); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); openApiSpecification.getOperation(operationId, context) - .ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), - () -> { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpecification.getSpecUrl())); - }); + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), + () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); return super.build(context, messageType); } @@ -153,11 +147,11 @@ public Object buildMessagePayload(TestContext context, String messageType) { } private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, - OperationPathAdapter operationPathAdapter, TestContext context) { + OperationPathAdapter operationPathAdapter, + TestContext context) { OasOperation operation = operationPathAdapter.operation(); String path = operationPathAdapter.apiPath(); - HttpMethod method = HttpMethod.valueOf( - operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); + HttpMethod method = HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); if (operation.parameters != null) { setMissingRequiredHeadersToRandomValues(openApiSpecification, context, operation); @@ -168,7 +162,7 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification String randomizedPath = getMessage().getPath() != null ? getMessage().getPath() : path; if (operation.parameters != null) { List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; @@ -177,16 +171,15 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification parameterValue = "\\" + pathParameterValue; } else { parameterValue = createRandomValueExpression( - (OasSchema) parameter.schema); + (OasSchema) parameter.schema); } - randomizedPath = randomizedPath.replaceAll("\\{"+parameter.getName()+"}", parameterValue); + randomizedPath = randomizedPath.replaceAll("\\{" + parameter.getName() + "}", parameterValue); } } OasModelHelper.getRequestContentType(operation) - .ifPresent( - contentType -> getMessage().setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + .ifPresent(contentType -> getMessage().setHeader(HttpHeaders.CONTENT_TYPE, contentType)); getMessage().path(randomizedPath); getMessage().method(method); @@ -194,20 +187,15 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification protected String getDefinedPathParameter(TestContext context, String name) { if (context.getVariables().containsKey(name)) { - return CitrusSettings.VARIABLE_PREFIX + name - + CitrusSettings.VARIABLE_SUFFIX; + return CitrusSettings.VARIABLE_PREFIX + name + CitrusSettings.VARIABLE_SUFFIX; } return null; } private void setMissingRequiredBodyToRandomValue(OpenApiSpecification openApiSpecification, TestContext context, OasOperation operation) { - if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String p - && p.isEmpty())) { - Optional body = OasModelHelper.getRequestBodySchema( - openApiSpecification.getOpenApiDoc(context), operation); - body.ifPresent(oasSchema -> getMessage().setPayload( - OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - openApiSpecification))); + if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String payloadString && payloadString.isEmpty())) { + Optional body = OasModelHelper.getRequestBodySchema(openApiSpecification.getOpenApiDoc(context), operation); + body.ifPresent(oasSchema -> getMessage().setPayload(createOutboundPayload(oasSchema, openApiSpecification))); } } @@ -216,51 +204,47 @@ private void setMissingRequiredBodyToRandomValue(OpenApiSpecification openApiSpe */ private void setMissingRequiredQueryParametersToRandomValues(TestContext context, OasOperation operation) { operation.parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter( - param -> Boolean.TRUE.equals(param.required) || context.getVariables() - .containsKey(param.getName())) - .forEach(param -> { - // If not already configured explicitly, create a random value - if (!getMessage().getQueryParams().containsKey(param.getName())) { - try { - getMessage().queryParam(param.getName(), - createRandomValueExpression(param.getName(), - (OasSchema) param.schema, - context)); - } catch (Exception e) { - // Note that exploded object query parameter representation for example, cannot properly - // be randomized. - logger.warn("Unable to set missing required query parameter to random value: {}", param); + .filter(param -> "query".equals(param.in)) + .filter(param -> Boolean.TRUE.equals(param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> { + // If not already configured explicitly, create a random value + if (!getMessage().getQueryParams().containsKey(param.getName())) { + try { + getMessage().queryParam(param.getName(), + createRandomValueExpression(param.getName(), + (OasSchema) param.schema, + context)); + } catch (Exception e) { + // Note that exploded object query parameter representation for example, cannot properly + // be randomized. + logger.warn("Unable to set missing required query parameter to random value: {}", param); + } } - } - }); + }); } /** * Creates all required headers, if they have not already been specified. */ private void setMissingRequiredHeadersToRandomValues(OpenApiSpecification openApiSpecification, - TestContext context, OasOperation operation) { + TestContext context, OasOperation operation) { List configuredHeaders = getHeaderBuilders() - .stream() - .flatMap(b -> b.builderHeaders(context).keySet().stream()) - .toList(); + .stream() + .flatMap(b -> b.builderHeaders(context).keySet().stream()) + .toList(); operation.parameters.stream() - .filter(param -> "header".equals(param.in)) - .filter( - param -> Boolean.TRUE.equals(param.required) || context.getVariables() - .containsKey(param.getName())) - .forEach(param -> { - // If not already configured explicitly, create a random value - if (getMessage().getHeader(param.getName()) == null - && !configuredHeaders.contains(param.getName())) { - getMessage().setHeader(param.getName(), - createRandomValueExpression(param.getName(), - (OasSchema) param.schema, - openApiSpecification, context)); - } - }); + .filter(param -> "header".equals(param.in)) + .filter(param -> Boolean.TRUE.equals(param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> { + // If not already configured explicitly, create a random value + if (getMessage().getHeader(param.getName()) == null + && !configuredHeaders.contains(param.getName())) { + getMessage().setHeader(param.getName(), + createRandomValueExpression(param.getName(), + (OasSchema) param.schema, + openApiSpecification, context)); + } + }); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index 2cb4f16f1b..71d186915e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -16,18 +16,10 @@ package org.citrusframework.openapi.actions; -import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; -import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; - import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.context.TestContext; @@ -36,52 +28,83 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; -import org.citrusframework.message.MessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; + +import static org.citrusframework.message.MessageType.JSON; +import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; +import static org.citrusframework.openapi.model.OasModelHelper.resolveSchema; +import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; + /** * @since 4.1 */ public class OpenApiClientResponseActionBuilder extends HttpClientResponseActionBuilder { - private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecificationSource openApiSpecificationSource; - private final String operationId; - + private OpenApiOperationToMessageHeadersProcessor openApiOperationToMessageHeadersProcessor; private boolean schemaValidation = true; /** * Default constructor initializes http response message builder. */ - public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, String operationId, - String statusCode) { + public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, String operationId, String statusCode) { this(new HttpMessage(), openApiSpec, operationId, statusCode); } public OpenApiClientResponseActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, String statusCode) { - this(openApiSpecificationSource, new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, - statusCode), httpMessage, operationId); + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode) { + this(openApiSpecificationSource, new OpenApiClientResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, statusCode), httpMessage, operationId); } - public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage message, - String operationId) { + public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec, + OpenApiClientResponseMessageBuilder messageBuilder, + HttpMessage message, + String operationId) { super(messageBuilder, message); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; } + public static void fillMessageTypeFromResponse(OpenApiSpecification openApiSpecification, + HttpMessage httpMessage, + @Nullable OasOperation operation, + @Nullable OasResponse response) { + if (operation == null || response == null) { + return; + } + + Optional responseSchema = OasModelHelper.getSchema(response); + responseSchema.ifPresent(oasSchema -> { + OasSchema resolvedSchema = resolveSchema(openApiSpecification.getOpenApiDoc(null), oasSchema); + if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType(resolvedSchema)) { + Collection responseTypes = OasModelHelper.getResponseTypes(operation,response); + if (responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)) { + httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, + MediaType.APPLICATION_JSON_VALUE); + httpMessage.setType(JSON); + } + } + } + ); + } + /** * Overridden to change the default message type to JSON, as Json is more common in OpenAPI context. */ @@ -89,15 +112,14 @@ public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec protected HttpMessageBuilderSupport createHttpMessageBuilderSupport() { HttpMessageBuilderSupport support = super.createHttpMessageBuilderSupport(); support.type(CitrusSettings.getPropertyEnvOrDefault( - CitrusSettings.DEFAULT_MESSAGE_TYPE_PROPERTY, - CitrusSettings.DEFAULT_MESSAGE_TYPE_ENV, - MessageType.JSON.toString())); + CitrusSettings.DEFAULT_MESSAGE_TYPE_PROPERTY, + CitrusSettings.DEFAULT_MESSAGE_TYPE_ENV, + JSON.toString())); return support; } @Override public ReceiveMessageAction doBuild() { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); // Honor default enablement of schema validation @@ -106,17 +128,15 @@ public ReceiveMessageAction doBuild() { schemaValidation = openApiValidationContext.isResponseValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { - openApiMessageProcessor = new OpenApiMessageProcessor( - openApiSpecification, operationId, - RESPONSE); - process(openApiMessageProcessor); + if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, RESPONSE); + process(openApiOperationToMessageHeadersProcessor); } if (schemaValidation && getValidationContexts().stream().noneMatch(OpenApiMessageValidationContext.class::isInstance)) { validate(openApi(openApiSpecification) - .schemaValidation(schemaValidation) - .build()); + .schemaValidation(schemaValidation) + .build()); } return super.doBuild(); @@ -127,43 +147,17 @@ public OpenApiClientResponseActionBuilder schemaValidation(boolean enabled) { return this; } - public static void fillMessageTypeFromResponse(OpenApiSpecification openApiSpecification, - HttpMessage httpMessage, @Nullable OasOperation operation, - @Nullable OasResponse response) { - - if (operation == null || response == null) { - return; - } - - Optional responseSchema = OasModelHelper.getSchema(response); - responseSchema.ifPresent(oasSchema -> { - OasSchema resolvedSchema = OasModelHelper.resolveSchema( - openApiSpecification.getOpenApiDoc(null), oasSchema); - if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType( - resolvedSchema)) { - Collection responseTypes = OasModelHelper.getResponseTypes(operation, - response); - if (responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)) { - httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, - MediaType.APPLICATION_JSON_VALUE); - httpMessage.setType(MessageType.JSON); - } - } - } - ); - } - public static class OpenApiClientResponseMessageBuilder extends HttpMessageBuilder { private final OpenApiSpecificationSource openApiSpecificationSource; private final String operationId; - private String statusCode; - private final HttpMessage httpMessage; + private String statusCode; public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, String statusCode) { + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode) { super(httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; @@ -172,19 +166,19 @@ public OpenApiClientResponseMessageBuilder(HttpMessage httpMessage, } public OpenApiClientResponseMessageBuilder statusCode(String statusCode) { - this.statusCode =statusCode; + this.statusCode = statusCode; return this; } @Override public Message build(TestContext context, String messageType) { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); - openApiSpecification.getOperation(operationId, context).ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { - throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); - }); + openApiSpecification.getOperation(operationId, context) + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), () -> { + throw new CitrusRuntimeException("Unable to locate operation with id '%s' in OpenAPI specification %s".formatted(operationId, openApiSpecification.getSpecUrl())); + }); return super.build(context, messageType); } @@ -198,11 +192,10 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification if (operation.responses != null) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); + openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); responseForRandomGeneration.ifPresent( - oasResponse -> fillMessageTypeFromResponse(openApiSpecification, httpMessage, - operation, oasResponse)); + oasResponse -> fillMessageTypeFromResponse(openApiSpecification, httpMessage, operation, oasResponse)); } if (Pattern.compile("\\d+").matcher(statusCode).matches()) { @@ -213,6 +206,5 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification httpMessage.getHeaders().putAll(currentHeaders); } - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java index a08759d4ea..0460344ca2 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilder.java @@ -1,13 +1,14 @@ package org.citrusframework.openapi.actions; +import org.citrusframework.context.TestContext; +import org.citrusframework.message.builder.DefaultPayloadBuilder; +import org.springframework.util.MultiValueMap; + import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.citrusframework.context.TestContext; -import org.citrusframework.message.builder.DefaultPayloadBuilder; -import org.springframework.util.MultiValueMap; public class OpenApiPayloadBuilder extends DefaultPayloadBuilder { @@ -15,17 +16,6 @@ public OpenApiPayloadBuilder(Object payload) { super(payload); } - @Override - public Object buildPayload(TestContext context) { - - if (getPayload() instanceof MultiValueMap multiValueMap) { - replaceDynamicContentInMultiValueMap(context, - (MultiValueMap) multiValueMap); - } - - return super.buildPayload(context); - } - private static void replaceDynamicContentInMultiValueMap(TestContext context, MultiValueMap multiValueMap) { Set cache = new HashSet<>(multiValueMap.entrySet()); multiValueMap.clear(); @@ -36,13 +26,12 @@ private static void replaceDynamicContentInMultiValueMap(TestContext context, Mu } } - private static void replaceDynamicContentInEntry(TestContext context, MultiValueMap multiValueMap, - Entry entry) { + private static void replaceDynamicContentInEntry(TestContext context, MultiValueMap multiValueMap, Entry entry) { Object key = entry.getKey(); List list = (List) entry.getValue(); if (list != null) { - for (int i=0;i multiValueMap) { + replaceDynamicContentInMultiValueMap(context, (MultiValueMap) multiValueMap); + } + + return super.buildPayload(context); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java index e0404854e8..9afc29ca6b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilder.java @@ -18,7 +18,6 @@ import org.citrusframework.TestAction; import org.citrusframework.endpoint.Endpoint; -import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.spi.AbstractReferenceResolverAwareTestActionBuilder; import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.util.ObjectHelper; @@ -33,7 +32,9 @@ public class OpenApiServerActionBuilder extends AbstractReferenceResolverAwareTe private final OpenApiSpecificationSource openApiSpecificationSource; - /** Target http client instance */ + /** + * Target http client instance + */ private Endpoint httpServer; private String httpServerUri; @@ -57,8 +58,7 @@ public OpenApiServerActionBuilder(String httpServerUri, OpenApiSpecificationSour * Receive Http requests as server. */ public OpenApiServerRequestActionBuilder receive(String operationId) { - OpenApiServerRequestActionBuilder builder = new OpenApiServerRequestActionBuilder( - openApiSpecificationSource, operationId); + OpenApiServerRequestActionBuilder builder = new OpenApiServerRequestActionBuilder(openApiSpecificationSource, operationId); if (httpServer != null) { builder.endpoint(httpServer); } else { @@ -105,8 +105,7 @@ public OpenApiServerResponseActionBuilder send(String operationId, String status * Send Http response messages as server to client. */ public OpenApiServerResponseActionBuilder send(String operationId, String statusCode, String accept) { - OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder( - openApiSpecificationSource, operationId, statusCode, accept); + OpenApiServerResponseActionBuilder builder = new OpenApiServerResponseActionBuilder(openApiSpecificationSource, operationId, statusCode, accept); if (httpServer != null) { builder.endpoint(httpServer); } else { @@ -122,6 +121,7 @@ public OpenApiServerResponseActionBuilder send(String operationId, String status /** * Sets the Spring bean application context. + * * @param referenceResolver */ public OpenApiServerActionBuilder withReferenceResolver(ReferenceResolver referenceResolver) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java index a47de116ee..0adf5d7aff 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerRequestActionBuilder.java @@ -16,22 +16,9 @@ package org.citrusframework.openapi.actions; -import static java.lang.String.format; -import static org.citrusframework.message.MessageType.JSON; -import static org.citrusframework.message.MessageType.PLAINTEXT; -import static org.citrusframework.message.MessageType.XML; -import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; -import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; -import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; - import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.List; -import java.util.Optional; -import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.context.TestContext; @@ -40,27 +27,40 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; -import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.OpenApiTestValidationDataGenerator; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import java.util.List; +import java.util.Optional; +import java.util.regex.Pattern; + +import static java.lang.String.format; +import static org.citrusframework.message.MessageType.JSON; +import static org.citrusframework.message.MessageType.PLAINTEXT; +import static org.citrusframework.message.MessageType.XML; +import static org.citrusframework.openapi.OpenApiMessageType.REQUEST; +import static org.citrusframework.openapi.model.OasModelHelper.getRequestBodySchema; +import static org.citrusframework.openapi.model.OasModelHelper.getRequestContentType; +import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_XML_VALUE; + /** * @since 4.1 */ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBuilder { - private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecificationSource openApiSpecificationSource; - private final String operationId; + private OpenApiOperationToMessageHeadersProcessor openApiOperationToMessageHeadersProcessor; /** * Schema validation is enabled by default. @@ -70,26 +70,21 @@ public class OpenApiServerRequestActionBuilder extends HttpServerRequestActionBu /** * Default constructor initializes http request message builder. */ - public OpenApiServerRequestActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, - String operationId) { + public OpenApiServerRequestActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, String operationId) { this(new HttpMessage(), openApiSpecificationSource, operationId); } public OpenApiServerRequestActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId) { - super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpecificationSource, - operationId), - httpMessage); + OpenApiSpecificationSource openApiSpecificationSource, + String operationId) { + super(new OpenApiServerRequestMessageBuilder(httpMessage, openApiSpecificationSource, operationId), httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } @Override public ReceiveMessageAction doBuild() { - - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( - referenceResolver); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); // Honor default enablement of schema validation OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); @@ -97,17 +92,16 @@ public ReceiveMessageAction doBuild() { schemaValidation = openApiValidationContext.isRequestValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { - openApiMessageProcessor = new OpenApiMessageProcessor( - openApiSpecification, operationId, OpenApiMessageType.REQUEST); - process(openApiMessageProcessor); + if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, REQUEST); + process(openApiOperationToMessageHeadersProcessor); } if (schemaValidation && getValidationContexts().stream() - .noneMatch(OpenApiMessageValidationContext.class::isInstance)) { + .noneMatch(OpenApiMessageValidationContext.class::isInstance)) { validate(openApi(openApiSpecification) - .schemaValidation(schemaValidation) - .build()); + .schemaValidation(schemaValidation) + .build()); } return super.doBuild(); @@ -126,8 +120,8 @@ private static class OpenApiServerRequestMessageBuilder extends HttpMessageBuild private final HttpMessage httpMessage; public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { + OpenApiSpecificationSource openApiSpec, + String operationId) { super(httpMessage); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; @@ -136,25 +130,23 @@ public OpenApiServerRequestMessageBuilder(HttpMessage httpMessage, @Override public Message build(TestContext context, String messageType) { - - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( - context.getReferenceResolver()); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); openApiSpecification.getOperation(operationId, context) - .ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), - () -> { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpecification.getSpecUrl())); - }); + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), + () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); return super.build(context, messageType); } private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, - OperationPathAdapter operationPathAdapter, TestContext context) { - + OperationPathAdapter operationPathAdapter, + TestContext context) { setSpecifiedMessageType(operationPathAdapter); setSpecifiedHeaders(context, openApiSpecification, operationPathAdapter); setSpecifiedQueryParameters(context, openApiSpecification, operationPathAdapter); @@ -167,120 +159,107 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification private void setSpecifiedRequestContentType(OperationPathAdapter operationPathAdapter) { OasModelHelper.getRequestContentType(operationPathAdapter.operation()) - .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, - String.format("@startsWith(%s)@", contentType))); + .ifPresent(contentType -> httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, + format("@startsWith(%s)@", contentType))); } - private void setSpecifiedPath(TestContext context, - OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { + private void setSpecifiedPath(TestContext context, OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { String randomizedPath = - OasModelHelper.getBasePath(openApiSpecification.getOpenApiDoc(context)) - + operationPathAdapter.apiPath(); + OasModelHelper.getBasePath(openApiSpecification.getOpenApiDoc(context)) + + operationPathAdapter.apiPath(); randomizedPath = randomizedPath.replace("//", "/"); - randomizedPath = appendSegmentToUrlPath(openApiSpecification.getRootContextPath(), - randomizedPath); + randomizedPath = appendSegmentToUrlPath(openApiSpecification.getRootContextPath(), randomizedPath); if (operationPathAdapter.operation().parameters != null) { - randomizedPath = determinePath(context, operationPathAdapter.operation(), - randomizedPath); + randomizedPath = determinePath(context, operationPathAdapter.operation(), randomizedPath); } httpMessage.path(randomizedPath); } private void setSpecifiedBody(TestContext context, - OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter) { - Optional body = OasModelHelper.getRequestBodySchema( - openApiSpecification.getOpenApiDoc(context), operationPathAdapter.operation()); - body.ifPresent(oasSchema -> httpMessage.setPayload( - OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(context)), - openApiSpecification))); + OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter) { + Optional bodySchema = getRequestBodySchema(openApiSpecification.getOpenApiDoc(context), operationPathAdapter.operation()); + bodySchema.ifPresent(oasSchema -> httpMessage.setPayload( + OpenApiTestValidationDataGenerator.createInboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), + openApiSpecification))); } - private String determinePath(TestContext context, OasOperation operation, - String randomizedPath) { + private String determinePath(TestContext context, OasOperation operation, String randomizedPath) { List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; if (context.getVariables().containsKey(parameter.getName())) { - parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() - + CitrusSettings.VARIABLE_SUFFIX; + parameterValue = "\\" + CitrusSettings.VARIABLE_PREFIX + parameter.getName() + CitrusSettings.VARIABLE_SUFFIX; randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") - .matcher(randomizedPath) - .replaceAll(parameterValue); + .matcher(randomizedPath) + .replaceAll(parameterValue); } else { parameterValue = OpenApiTestValidationDataGenerator.createValidationRegex( - parameter.getName(), - OasModelHelper.getParameterSchema(parameter).orElse(null)); + parameter.getName(), + OasModelHelper.getParameterSchema(parameter).orElse(null)); randomizedPath = Pattern.compile("\\{" + parameter.getName() + "}") - .matcher(randomizedPath) - .replaceAll(parameterValue); + .matcher(randomizedPath) + .replaceAll(parameterValue); randomizedPath = format("@matches('%s')@", randomizedPath); } } + return randomizedPath; } private void setSpecifiedQueryParameters(TestContext context, - OpenApiSpecification openApiSpecification, - OperationPathAdapter operationPathAdapter) { - + OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { return; } operationPathAdapter.operation().parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter( - param -> (param.required != null && param.required) || context.getVariables() - .containsKey(param.getName())) - .forEach(param -> httpMessage.queryParam(param.getName(), - OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), - OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(context)), false, - openApiSpecification, - context))); + .filter(param -> "query".equals(param.in)) + .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> httpMessage.queryParam(param.getName(), + OpenApiTestValidationDataGenerator.createValidationExpression( + param.getName(), + OasModelHelper.getParameterSchema(param).orElse(null), + OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), + false, + openApiSpecification, + context))); } private void setSpecifiedHeaders(TestContext context, - OpenApiSpecification openApiSpecification, - OperationPathAdapter operationPathAdapter) { - + OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter) { if (operationPathAdapter.operation().parameters == null) { return; } operationPathAdapter.operation().parameters.stream() - .filter(param -> "header".equals(param.in)) - .filter( - param -> (param.required != null && param.required) || context.getVariables() - .containsKey(param.getName())) - .forEach(param -> httpMessage.setHeader(param.getName(), - OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), - OasModelHelper.getParameterSchema(param).orElse(null), - OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(context)), false, - openApiSpecification, - context))); + .filter(param -> "header".equals(param.in)) + .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) + .forEach(param -> httpMessage.setHeader(param.getName(), + OpenApiTestValidationDataGenerator.createValidationExpression(param.getName(), + OasModelHelper.getParameterSchema(param).orElse(null), + OasModelHelper.getSchemaDefinitions(openApiSpecification.getOpenApiDoc(context)), + false, + openApiSpecification, + context))); } private void setSpecifiedMessageType(OperationPathAdapter operationPathAdapter) { - Optional requestContentType = getRequestContentType( - operationPathAdapter.operation()); - if (requestContentType.isPresent() && APPLICATION_JSON_VALUE.equals( - requestContentType.get())) { + Optional requestContentType = getRequestContentType(operationPathAdapter.operation()); + if (requestContentType.isPresent() && APPLICATION_JSON_VALUE.equals(requestContentType.get())) { httpMessage.setType(JSON); - } else if (requestContentType.isPresent() && APPLICATION_XML_VALUE.equals( - requestContentType.get())) { + } else if (requestContentType.isPresent() && APPLICATION_XML_VALUE.equals(requestContentType.get())) { httpMessage.setType(XML); } else { httpMessage.setType(PLAINTEXT); @@ -288,8 +267,7 @@ private void setSpecifiedMessageType(OperationPathAdapter operationPathAdapter) } private void setSpecifiedMethod(OperationPathAdapter operationPathAdapter) { - httpMessage.method( - HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase())); + httpMessage.method(HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase())); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index dee3ccb155..64f2b3bb6b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -16,28 +16,10 @@ package org.citrusframework.openapi.actions; -import static java.lang.Integer.parseInt; -import static java.util.Collections.singletonMap; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; - import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; -import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -52,36 +34,56 @@ import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiMessageProcessor; +import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpStatus; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; + +import static java.lang.Integer.parseInt; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + /** * @since 4.1 */ public class OpenApiServerResponseActionBuilder extends HttpServerResponseActionBuilder { - private OpenApiMessageProcessor openApiMessageProcessor; - private final OpenApiSpecificationSource openApiSpecificationSource; - private final String operationId; - + private OpenApiOperationToMessageHeadersProcessor openApiOperationToMessageHeadersProcessor; private boolean schemaValidation = true; /** * Default constructor initializes http response message builder. */ - public OpenApiServerResponseActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, String operationId, - String statusCode, String accept) { + public OpenApiServerResponseActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode, + String accept) { this(new HttpMessage(), openApiSpecificationSource, operationId, statusCode, accept); } public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, String statusCode, String accept) { - super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, - statusCode, accept), httpMessage); + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode, + String accept) { + super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, statusCode, accept), httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } @@ -96,10 +98,9 @@ public SendMessageAction doBuild() { schemaValidation = openApiValidationContext.isResponseValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiMessageProcessor)) { - openApiMessageProcessor = new OpenApiMessageProcessor(openApiSpecification, operationId, - OpenApiMessageType.RESPONSE); - process(openApiMessageProcessor); + if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, RESPONSE); + process(openApiOperationToMessageHeadersProcessor); } return super.doBuild(); @@ -121,7 +122,7 @@ protected HttpMessageBuilderSupport createMessageBuilderSupport() { } public OpenApiServerResponseActionBuilder enableRandomGeneration(boolean enable) { - ((OpenApiServerResponseMessageBuilder)getMessageBuilderSupport().getMessageBuilder()).enableRandomGeneration(enable); + ((OpenApiServerResponseMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).enableRandomGeneration(enable); return this; } @@ -136,8 +137,10 @@ private static class OpenApiServerResponseMessageBuilder extends HttpMessageBuil private boolean randomGenerationEnabled = true; public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, String statusCode, String accept) { + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode, + String accept) { super(httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; @@ -152,7 +155,6 @@ public OpenApiServerResponseMessageBuilder enableRandomGeneration(boolean enable @Override public Message build(TestContext context, String messageType) { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); if (STATUS_CODE_PATTERN.matcher(statusCode).matches()) { getMessage().status(HttpStatus.valueOf(parseInt(statusCode))); @@ -165,12 +167,12 @@ public Message build(TestContext context, String messageType) { if (randomGenerationEnabled) { openApiSpecification.getOperation(operationId, context) - .ifPresentOrElse(operationPathAdapter -> - fillRandomData(openApiSpecification, operationPathAdapter, context), () -> { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpecification.getSpecUrl())); - }); + .ifPresentOrElse(operationPathAdapter -> + fillRandomData(openApiSpecification, operationPathAdapter, context), () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); } // Initial header builder need to be prepended, so that they can overwrite randomly generated headers. @@ -187,9 +189,8 @@ private void fillRandomData(OpenApiSpecification openApiSpecification, Operation } private void buildResponse(TestContext context, OpenApiSpecification openApiSpecification, OasOperation operation) { - Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); + openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); if (responseForRandomGeneration.isPresent()) { buildRandomHeaders(context, openApiSpecification, responseForRandomGeneration.get()); @@ -199,41 +200,37 @@ private void buildResponse(TestContext context, OpenApiSpecification openApiSpec private void buildRandomHeaders(TestContext context, OpenApiSpecification openApiSpecification, OasResponse response) { Set filteredHeaders = new HashSet<>(getMessage().getHeaders().keySet()); - Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains( - entry.getKey()); + Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains(entry.getKey()); - Map requiredHeaders = OasModelHelper.getRequiredHeaders( - response); + Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); requiredHeaders.entrySet().stream() - .filter(filteredHeadersPredicate) - .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( - singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), - entry.getValue(), - openApiSpecification, - context)))) - ); + .filter(filteredHeadersPredicate) + .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( + singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), + entry.getValue(), + openApiSpecification, + context)))) + ); // Also filter the required headers, as they have already been processed filteredHeaders.addAll(requiredHeaders.keySet()); Map headers = OasModelHelper.getHeaders(response); headers.entrySet().stream() - .filter(filteredHeadersPredicate) - .filter(entry -> context.getVariables().containsKey(entry.getKey())) - .forEach((entry -> addHeaderBuilder( - new DefaultHeaderBuilder(singletonMap(entry.getKey(), - CitrusSettings.VARIABLE_PREFIX + entry.getKey() - + CitrusSettings.VARIABLE_SUFFIX))))); + .filter(filteredHeadersPredicate) + .filter(entry -> context.getVariables().containsKey(entry.getKey())) + .forEach((entry -> addHeaderBuilder( + new DefaultHeaderBuilder(singletonMap(entry.getKey(), + CitrusSettings.VARIABLE_PREFIX + entry.getKey() + + CitrusSettings.VARIABLE_SUFFIX))))); } private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOperation operation, OasResponse response) { - Optional> schemaForMediaTypeOptional; if (statusCode.startsWith("2")) { // if status code is good, and we have an accept, try to get the media type. Note that only json and plain text can be generated randomly. - schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, - response, accept != null ? List.of(accept) : null); - } else { + schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, accept != null ? singletonList(accept) : null); + } else { // In the bad case, we cannot expect, that the accept type is the type which we must generate. // We request the type supported by the response and the random generator (json and plain text). schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, null); @@ -241,8 +238,7 @@ private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOp if (schemaForMediaTypeOptional.isPresent()) { OasAdapter schemaForMediaType = schemaForMediaTypeOptional.get(); - if (getMessage().getPayload() == null || ( - getMessage().getPayload() instanceof String string && string.isEmpty())) { + if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String string && string.isEmpty())) { createRandomPayload(getMessage(), openApiSpecification, schemaForMediaType); } @@ -255,24 +251,20 @@ private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOp } private void createRandomPayload(HttpMessage message, OpenApiSpecification openApiSpecification, OasAdapter schemaForMediaType) { - if (schemaForMediaType.node() == null) { // No schema means no payload, no type message.setPayload(null); } else { if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { // Schema but plain text - message.setPayload(createOutboundPayload(schemaForMediaType.node(), - openApiSpecification)); + message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.adapted())) { // Json Schema - message.setPayload(createOutboundPayload(schemaForMediaType.node(), - openApiSpecification)); + message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); } } } } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java index 86ec9af9ac..931e142156 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java @@ -1,14 +1,15 @@ package org.citrusframework.openapi.actions; -import static org.citrusframework.util.StringUtils.isEmpty; - -import java.util.Objects; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.util.OpenApiUtils; import org.citrusframework.spi.ReferenceResolver; +import java.util.Objects; + +import static org.citrusframework.util.StringUtils.isEmpty; + /** * The {@code OpenApiSpecificationSource} class is responsible for managing and resolving an * {@link OpenApiSpecification} instance. It can either directly contain an @@ -35,16 +36,18 @@ public OpenApiSpecification resolve(ReferenceResolver resolver) { if (!isEmpty(openApiAlias)) { openApiSpecification = resolver.resolveAll(OpenApiRepository.class).values() - .stream() - .map(openApiRepository -> openApiRepository.openApi(openApiAlias)).filter( - Objects::nonNull).findFirst().orElseThrow(() -> - new CitrusRuntimeException( - "Unable to resolve OpenApiSpecification from alias '%s'. Known aliases for open api specs are '%s'".formatted( - openApiAlias, OpenApiUtils.getKnownOpenApiAliases(resolver))) - ); + .stream() + .map(openApiRepository -> openApiRepository.openApi(openApiAlias)). + filter(Objects::nonNull). + findFirst() + .orElseThrow(() -> + new CitrusRuntimeException( + "Unable to resolve OpenApiSpecification from alias '%s'. Known aliases for open api specs are '%s'".formatted( + openApiAlias, OpenApiUtils.getKnownOpenApiAliases(resolver))) + ); } else { throw new CitrusRuntimeException( - "Unable to resolve OpenApiSpecification. Neither OpenAPI spec, nor OpenAPI alias are specified."); + "Unable to resolve OpenApiSpecification. Neither OpenAPI spec, nor OpenAPI alias are specified."); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index cfbffdf139..e69d67c6c7 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,10 +16,6 @@ package org.citrusframework.openapi.model; -import static java.util.Collections.singletonList; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; - import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; @@ -40,9 +36,12 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import jakarta.annotation.Nullable; +import org.citrusframework.openapi.model.v2.Oas20ModelHelper; +import org.citrusframework.openapi.model.v3.Oas30ModelHelper; +import org.citrusframework.util.StringUtils; + import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -52,10 +51,14 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; -import org.citrusframework.openapi.model.v2.Oas20ModelHelper; -import org.citrusframework.openapi.model.v3.Oas30ModelHelper; -import org.citrusframework.util.StringUtils; -import org.springframework.http.MediaType; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; public final class OasModelHelper { @@ -65,7 +68,7 @@ public final class OasModelHelper { * List of preferred media types in the order of priority, * used when no specific 'Accept' header is provided to determine the default response type. */ - public static final List DEFAULT_ACCEPTED_MEDIA_TYPES = List.of(MediaType.APPLICATION_JSON_VALUE, MediaType.TEXT_PLAIN_VALUE); + public static final List DEFAULT_ACCEPTED_MEDIA_TYPES = List.of(APPLICATION_JSON_VALUE, TEXT_PLAIN_VALUE); private OasModelHelper() { // utility class @@ -73,6 +76,7 @@ private OasModelHelper() { /** * Determines if given schema is of type object. + * * @param schema to check * @return true if given schema is an object. */ @@ -82,6 +86,7 @@ public static boolean isObjectType(@Nullable OasSchema schema) { /** * Determines if given schema is of type array. + * * @param schema to check * @return true if given schema is an array. */ @@ -91,19 +96,19 @@ public static boolean isArrayType(@Nullable OasSchema schema) { /** * 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(@Nullable OasSchema schema) { - if (schema == null || !TYPE_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)); } @@ -112,6 +117,7 @@ public static boolean isObjectArrayType(@Nullable OasSchema schema) { /** * Determines if given schema has a reference to another schema object. + * * @param schema to check * @return true if given schema has a reference. */ @@ -149,12 +155,13 @@ public static Map getSchemaDefinitions(OasDocument openApiDoc /** * Iterate through list of generic path items and collect path items of given type. + * * @param paths given path items. * @return typed list of path items. */ public static List getPathItems(OasPaths paths) { if (paths == null) { - return Collections.emptyList(); + return emptyList(); } return paths.getItems(); @@ -163,6 +170,7 @@ public static List getPathItems(OasPaths paths) { /** * Construct map of all specified operations for given path item. Only non-null operations are added to the * map where the key is the http method name. + * * @param pathItem path holding operations. * @return map of operations on the given path where Http method name is the key. */ @@ -204,6 +212,7 @@ public static Map getOperationMap(OasPathItem pathItem) { * Get pure name from reference path. Usually reference definitions start with '#/definitions/' for OpenAPI 2.x and * '#/components/schemas/' for OpenAPI 3.x and this method removes the basic reference path part and just returns the * reference object name. + * * @param reference path expression. * @return the name of the reference object. */ @@ -220,12 +229,12 @@ public static Optional getSchema(OasResponse response) { } public static Optional> getSchema(OasOperation oasOperation, OasResponse response, List acceptedMediaTypes) { - if (oasOperation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { + if (oasOperation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { return Oas20ModelHelper.getSchema(oas20Operation, oas20Response, acceptedMediaTypes); } else if (oasOperation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { return Oas30ModelHelper.getSchema(oas30Operation, oas30Response, acceptedMediaTypes); } - throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); + throw new IllegalArgumentException(format("Unsupported operation response type: %s", response.getClass())); } public static Optional getParameterSchema(OasParameter parameter) { @@ -263,24 +272,23 @@ public static Collection getResponseTypes(OasOperation operation, OasRes *
    • Fallback 3: Returns the first response object related to a 2xx status code even without a schema. This is for operations that simply do not return anything else than a status code.
    • *
    • Fallback 4: Returns the first response in the list of responses, no matter which schema.
    • * - * + *

      * Note that for Fallback 3 and 4, it is very likely, that there is no schema specified. It is expected, that an empty response is a viable response in these cases. * * @param openApiDoc The OpenAPI document containing the API specifications. - * @param operation The OAS operation for which to determine the response. + * @param operation The OAS operation for which to determine the response. * @param statusCode The specific status code to match against responses, or {@code null} to search for any acceptable response. - * @param accept The mediatype accepted by the request + * @param accept The mediatype accepted by the request * @return An {@link Optional} containing the resolved {@link OasResponse} if found, or {@link Optional#empty()} otherwise. */ public static Optional getResponseForRandomGeneration(OasDocument openApiDoc, OasOperation operation, @Nullable String statusCode, @Nullable String accept) { - if (operation.responses == null || operation.responses.getResponses().isEmpty()) { return Optional.empty(); } // Resolve all references Map responseMap = OasModelHelper.resolveResponses(openApiDoc, - operation.responses); + operation.responses); // For a given status code, do not fall back if (statusCode != null) { @@ -296,25 +304,25 @@ public static Optional getResponseForRandomGeneration(OasDocument o if (response.isEmpty()) { // Fallback 2: Pick the response object related to the first 2xx, providing an accepted schema response = responseMap.values().stream() - .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) - .map(OasResponse.class::cast) - .filter(acceptedSchemas) - .findFirst(); + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .filter(acceptedSchemas) + .findFirst(); } if (response.isEmpty()) { // Fallback 3: Pick the response object related to the first 2xx (even without schema) response = responseMap.values().stream() - .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) - .map(OasResponse.class::cast) - .findFirst(); + .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) + .map(OasResponse.class::cast) + .findFirst(); } if (response.isEmpty()) { // Fallback 4: Pick the first response no matter which schema response = operation.responses.getResponses().stream() - .map(resp -> responseMap.get(resp.getStatusCode())) - .filter(Objects::nonNull) + .map(resp -> responseMap.get(resp.getStatusCode())) + .filter(Objects::nonNull) .findFirst(); } @@ -323,10 +331,11 @@ public static Optional getResponseForRandomGeneration(OasDocument o /** * Delegate method to version specific model helpers for Open API v2 or v3. - * @param openApiDoc the open api document either v2 or v3 + * + * @param openApiDoc the open api document either v2 or v3 * @param oas20Function function to apply in case of v2 * @param oas30Function function to apply in case of v3 - * @param generic return value + * @param generic return value * @return */ private static T delegate(OasDocument openApiDoc, Function oas20Function, Function oas30Function) { @@ -336,15 +345,16 @@ private static T delegate(OasDocument openApiDoc, Function return oas30Function.apply((Oas30Document) openApiDoc); } - throw new IllegalArgumentException(String.format("Unsupported Open API document type: %s", openApiDoc.getClass())); + throw new IllegalArgumentException(format("Unsupported Open API document type: %s", openApiDoc.getClass())); } /** * Delegate method to version specific model helpers for Open API v2 or v3. + * * @param response * @param oas20Function function to apply in case of v2 * @param oas30Function function to apply in case of v3 - * @param generic return value + * @param generic return value * @return */ private static T delegate(OasResponse response, Function oas20Function, Function oas30Function) { @@ -354,33 +364,35 @@ private static T delegate(OasResponse response, Function o return oas30Function.apply(oas30Response); } - throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); + throw new IllegalArgumentException(format("Unsupported operation response type: %s", response.getClass())); } /** * Delegate method to version specific model helpers for Open API v2 or v3. + * * @param response * @param oas20Function function to apply in case of v2 * @param oas30Function function to apply in case of v3 - * @param generic return value + * @param generic return value * @return */ private static T delegate(OasOperation operation, OasResponse response, BiFunction oas20Function, BiFunction oas30Function) { - if (operation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { + if (operation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { return oas20Function.apply(oas20Operation, oas20Response); - } else if (operation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { + } else if (operation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { return oas30Function.apply(oas30Operation, oas30Response); } - throw new IllegalArgumentException(String.format("Unsupported operation response type: %s", response.getClass())); + throw new IllegalArgumentException(format("Unsupported operation response type: %s", response.getClass())); } /** * Delegate method to version specific model helpers for Open API v2 or v3. + * * @param parameter * @param oas20Function function to apply in case of v2 * @param oas30Function function to apply in case of v3 - * @param generic return value + * @param generic return value * @return */ private static T delegate(OasParameter parameter, Function oas20Function, Function oas30Function) { @@ -390,15 +402,16 @@ private static T delegate(OasParameter parameter, Function generic return value + * @param generic return value * @return */ private static T delegate(OasSchema schema, Function oas20Function, Function oas30Function) { @@ -408,15 +421,16 @@ private static T delegate(OasSchema schema, Function oas20Fu return oas30Function.apply(oas30Schema); } - throw new IllegalArgumentException(String.format("Unsupported operation parameter type: %s", schema.getClass())); + throw new IllegalArgumentException(format("Unsupported operation parameter type: %s", schema.getClass())); } /** * Delegate method to version specific model helpers for Open API v2 or v3. + * * @param operation * @param oas20Function function to apply in case of v2 * @param oas30Function function to apply in case of v3 - * @param generic return value + * @param generic return value * @return */ private static T delegate(OasOperation operation, Function oas20Function, Function oas30Function) { @@ -426,7 +440,7 @@ private static T delegate(OasOperation operation, Function T delegate(OasOperation operation, Function generic return value + * @param generic return value * @return */ private static T delegate(OasDocument openApiDoc, OasOperation operation, BiFunction oas20Function, BiFunction oas30Function) { @@ -446,7 +460,7 @@ private static T delegate(OasDocument openApiDoc, OasOperation operation, Bi return oas30Function.apply((Oas30Document) openApiDoc, (Oas30Operation) operation); } - throw new IllegalArgumentException(String.format("Unsupported Open API document type: %s", openApiDoc.getClass())); + throw new IllegalArgumentException(format("Unsupported Open API document type: %s", openApiDoc.getClass())); } private static boolean isOas30(OasDocument openApiDoc) { @@ -471,9 +485,7 @@ private static boolean isOas20(OasDocument openApiDoc) { * @return a {@link List} of {@link OasResponse} instances, where all references have been resolved. */ private static Map resolveResponses(OasDocument openApiDoc, OasResponses responses) { - - Function responseResolver = getResponseResolver( - openApiDoc); + Function responseResolver = getResponseResolver(openApiDoc); Map responseMap = new HashMap<>(); for (OasResponse response : responses.getResponses()) { @@ -502,11 +514,10 @@ private static Map resolveResponses(OasDocument openApiDoc, return responseMap; } - private static Function getResponseResolver( - OasDocument openApiDoc) { + private static Function getResponseResolver(OasDocument openApiDoc) { return delegate(openApiDoc, - doc -> (responseRef -> doc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))), - doc -> (responseRef -> doc.components.responses.get(OasModelHelper.getReferenceName(responseRef)))); + doc -> (responseRef -> doc.responses.getResponse(OasModelHelper.getReferenceName(responseRef))), + doc -> (responseRef -> doc.components.responses.get(OasModelHelper.getReferenceName(responseRef)))); } /** @@ -514,7 +525,7 @@ private static Function getResponseResolver( * This method uses the provided {@link OasOperationVisitor} to process each operation within the paths of the OAS document. * * @param oasDocument the OAS document to traverse - * @param visitor the visitor to apply to each OAS operation + * @param visitor the visitor to apply to each OAS operation */ public static void visitOasOperations(OasDocument oasDocument, OasOperationVisitor visitor) { if (oasDocument == null || visitor == null) { @@ -537,7 +548,7 @@ public void visitPathItem(OasPathItem oasPathItem) { } getOperationMap(oasPathItem).values() - .forEach(oasOperation -> visitor.visit(oasPathItem, oasOperation)); + .forEach(oasOperation -> visitor.visit(oasPathItem, oasOperation)); } }); @@ -553,11 +564,11 @@ public void visitPathItem(OasPathItem oasPathItem) { */ public static List resolveAllTypes(@Nullable List acceptedMediaTypes) { if (acceptedMediaTypes == null) { - return acceptedMediaTypes; + return null; } return acceptedMediaTypes.stream() - .flatMap(types -> Arrays.stream(types.split(","))).map(String::trim).toList(); + .flatMap(types -> Arrays.stream(types.split(","))).map(String::trim).toList(); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java index f9b9727b4c..dbfcee3270 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OpenApiVersion.java @@ -37,8 +37,8 @@ public enum OpenApiVersion { static OpenApiVersion fromDocumentType(OasDocument model) { return Arrays.stream(values()) - .filter(version -> version.documentType.isInstance(model)) - .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Unable get OpenAPI version from given document type")); + .filter(version -> version.documentType.isInstance(model)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unable get OpenAPI version from given document type")); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java index 4d63466c58..3a04d57a84 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OperationPathAdapter.java @@ -16,11 +16,11 @@ package org.citrusframework.openapi.model; +import io.apicurio.datamodels.openapi.models.OasOperation; + import static java.lang.String.format; import static org.citrusframework.openapi.util.OpenApiUtils.getMethodPath; -import io.apicurio.datamodels.openapi.models.OasOperation; - /** * Adapts the different paths associated with an OpenAPI operation to the {@link OasOperation}. * This record holds the API path, context path, full path, and the associated {@link OasOperation} object. diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index e454faef53..77839fdd93 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -21,6 +21,7 @@ import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Document; import io.apicurio.datamodels.openapi.v2.models.Oas20Header; +import io.apicurio.datamodels.openapi.v2.models.Oas20Items; import io.apicurio.datamodels.openapi.v2.models.Oas20Operation; import io.apicurio.datamodels.openapi.v2.models.Oas20Parameter; import io.apicurio.datamodels.openapi.v2.models.Oas20Response; @@ -28,6 +29,9 @@ import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20SchemaDefinition; import jakarta.annotation.Nullable; +import org.citrusframework.openapi.model.OasAdapter; +import org.citrusframework.openapi.model.OasModelHelper; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -35,8 +39,9 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import org.citrusframework.openapi.model.OasAdapter; -import org.citrusframework.openapi.model.OasModelHelper; + +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; public final class Oas20ModelHelper { @@ -71,7 +76,6 @@ public static Optional getSchema(Oas20Response response) { } public static Optional> getSchema(Oas20Operation oas20Operation, Oas20Response response, List acceptedMediaTypes) { - acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; @@ -79,9 +83,9 @@ public static Optional> getSchema(Oas20Operation o String selectedMediaType = null; if (oas20Operation.produces != null && !oas20Operation.produces.isEmpty()) { selectedMediaType = acceptedMediaTypes.stream() - .filter(type -> !isFormDataMediaType(type)) - .filter(type -> oas20Operation.produces.contains(type)).findFirst() - .orElse(null); + .filter(type -> !isFormDataMediaType(type)) + .filter(type -> oas20Operation.produces.contains(type)).findFirst() + .orElse(null); } return selectedSchema == null && selectedMediaType == null ? Optional.empty() : Optional.of(new OasAdapter<>(selectedSchema, selectedMediaType)); @@ -89,7 +93,7 @@ public static Optional> getSchema(Oas20Operation o public static boolean isCompositeSchema(Oas20Schema schema) { // Note that oneOf and anyOf is not supported by Oas20. - return schema instanceof Oas20AllOfSchema; + return schema instanceof Oas20AllOfSchema; } public static Optional getRequestBodySchema(@Nullable Oas20Document ignoredOpenApiDoc, Oas20Operation operation) { @@ -131,7 +135,7 @@ public static Map getHeaders(Oas20Response response) { } private static boolean isFormDataMediaType(String type) { - return Arrays.asList("application/x-www-form-urlencoded", "multipart/form-data").contains(type); + return Arrays.asList(APPLICATION_FORM_URLENCODED_VALUE, MULTIPART_FORM_DATA_VALUE).contains(type); } /** @@ -142,30 +146,7 @@ private static boolean isFormDataMediaType(String type) { * @return an {@link Optional} containing the extracted or newly created {@link OasSchema} */ private static OasSchema getHeaderSchema(Oas20Header header) { - Oas20Schema schema = new Oas20Schema(); - schema.title = header.getName(); - schema.type = header.type; - schema.format = header.format; - schema.items = header.items; - schema.multipleOf = header.multipleOf; - - schema.default_ = header.default_; - schema.enum_ = header.enum_; - - schema.pattern = header.pattern; - schema.description = header.description; - schema.uniqueItems = header.uniqueItems; - - schema.maximum = header.maximum; - schema.maxItems = header.maxItems; - schema.maxLength = header.maxLength; - schema.exclusiveMaximum = header.exclusiveMaximum; - - schema.minimum = header.minimum; - schema.minItems = header.minItems; - schema.minLength = header.minLength; - schema.exclusiveMinimum = header.exclusiveMinimum; - return schema; + return createOas20Schema(header.getName(), header.type, header.format, header.items, header.multipleOf, header.default_, header.enum_, header.pattern, header.description, header.uniqueItems, header.maximum, header.maxItems, header.maxLength, header.exclusiveMaximum, header.minimum, header.minItems, header.minLength, header.exclusiveMinimum); } /** @@ -180,31 +161,36 @@ public static Optional getParameterSchema(Oas20Parameter parameter) { return Optional.of(oasSchema); } + Oas20Schema schema = createOas20Schema(parameter.getName(), parameter.type, parameter.format, parameter.items, parameter.multipleOf, parameter.default_, parameter.enum_, parameter.pattern, parameter.description, parameter.uniqueItems, parameter.maximum, parameter.maxItems, parameter.maxLength, parameter.exclusiveMaximum, parameter.minimum, parameter.minItems, parameter.minLength, parameter.exclusiveMinimum); + return Optional.of(schema); + } + + private static Oas20Schema createOas20Schema(String name, String type, String format, Oas20Items items, Number multipleOf, Object aDefault, List anEnum, String pattern, String description, Boolean uniqueItems, Number maximum, Number maxItems, Number maxLength, Boolean exclusiveMaximum, Number minimum, Number minItems, Number minLength, Boolean exclusiveMinimum) { Oas20Schema schema = new Oas20Schema(); - schema.title = parameter.getName(); - schema.type = parameter.type; - schema.format = parameter.format; - schema.items = parameter.items; - schema.multipleOf = parameter.multipleOf; - schema.default_ = parameter.default_; - schema.enum_ = parameter.enum_; + schema.title = name; + schema.type = type; + schema.format = format; + schema.items = items; + schema.multipleOf = multipleOf; - schema.pattern = parameter.pattern; - schema.description = parameter.description; - schema.uniqueItems = parameter.uniqueItems; + schema.default_ = aDefault; + schema.enum_ = anEnum; - schema.maximum = parameter.maximum; - schema.maxItems = parameter.maxItems; - schema.maxLength = parameter.maxLength; - schema.exclusiveMaximum = parameter.exclusiveMaximum; + schema.pattern = pattern; + schema.description = description; + schema.uniqueItems = uniqueItems; - schema.minimum = parameter.minimum; - schema.minItems = parameter.minItems; - schema.minLength = parameter.minLength; - schema.exclusiveMinimum = parameter.exclusiveMinimum; + schema.maximum = maximum; + schema.maxItems = maxItems; + schema.maxLength = maxLength; + schema.exclusiveMaximum = exclusiveMaximum; - return Optional.of(schema); - } + schema.minimum = minimum; + schema.minItems = minItems; + schema.minLength = minLength; + schema.exclusiveMinimum = exclusiveMinimum; + return schema; + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 746f97f1e5..b0796ce5b0 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -35,18 +35,23 @@ import java.net.URI; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; -import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toMap; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; public final class Oas30ModelHelper { - /** Logger */ - private static final Logger LOG = LoggerFactory.getLogger(Oas30ModelHelper.class); + private static final Logger logger = LoggerFactory.getLogger(Oas30ModelHelper.class); + public static final String NO_URL_ERROR_MESSAGE = "Unable to determine base path from server URL: %s"; private Oas30ModelHelper() { @@ -68,7 +73,7 @@ public static String getHost(Oas30Document openApiDoc) { public static List getSchemes(Oas30Document openApiDoc) { if (openApiDoc.servers == null || openApiDoc.servers.isEmpty()) { - return Collections.emptyList(); + return emptyList(); } return openApiDoc.servers.stream() @@ -77,12 +82,12 @@ public static List getSchemes(Oas30Document openApiDoc) { try { return URI.create(serverUrl).toURL().getProtocol(); } catch (MalformedURLException e) { - LOG.warn(String.format(NO_URL_ERROR_MESSAGE, serverUrl)); + logger.warn(NO_URL_ERROR_MESSAGE, serverUrl); return null; } }) - .filter(Objects::nonNull) - .toList(); + .filter(Objects::nonNull) + .toList(); } public static boolean isCompositeSchema(Oas30Schema schema) { @@ -109,12 +114,12 @@ public static String getBasePath(Oas30Document openApiDoc) { public static Map getSchemaDefinitions(Oas30Document openApiDoc) { if (openApiDoc.components == null || openApiDoc.components.schemas == null) { - return Collections.emptyMap(); + return emptyMap(); } return openApiDoc.components.schemas.entrySet() .stream() - .collect(Collectors.toMap(Map.Entry::getKey, Entry::getValue)); + .collect(toMap(Map.Entry::getKey, Entry::getValue)); } public static Optional getSchema(Oas30Response response) { @@ -131,9 +136,7 @@ public static Optional getSchema(Oas30Response response) { .findFirst(); } - public static Optional> getSchema( - Oas30Operation ignoredOas30Operation, Oas30Response response, List acceptedMediaTypes) { - + public static Optional> getSchema(Oas30Operation ignoredOas30Operation, Oas30Response response, List acceptedMediaTypes) { acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; @@ -198,46 +201,48 @@ public static Optional getRequestContentType(Oas30Operation operation) { public static Collection getResponseTypes(Oas30Operation operation, Oas30Response response) { if (operation == null) { - return Collections.emptySet(); + return emptySet(); } - return response.content != null ? response.content.keySet() : Collections.emptyList(); + + return response.content != null ? response.content.keySet() : emptyList(); } public static Map getRequiredHeaders(Oas30Response response) { if (response.headers == null) { - return Collections.emptyMap(); + return emptyMap(); } return response.headers.entrySet() .stream() .filter(entry -> Boolean.TRUE.equals(entry.getValue().required)) - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema)); + .collect(toMap(Map.Entry::getKey, entry -> entry.getValue().schema)); } public static Map getHeaders(Oas30Response response) { if (response.headers == null) { - return Collections.emptyMap(); + return emptyMap(); } return response.headers.entrySet() - .stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().schema)); + .stream() + .collect(toMap(Map.Entry::getKey, entry -> entry.getValue().schema)); } private static boolean isFormDataMediaType(String type) { - return Arrays.asList("application/x-www-form-urlencoded", "multipart/form-data").contains(type); + return Arrays.asList(APPLICATION_FORM_URLENCODED_VALUE, MULTIPART_FORM_DATA_VALUE).contains(type); } /** * Resolve given server url and replace variable placeholders if any with default variable values. Open API 3.x * supports variables with placeholders in form {variable_name} (e.g. "http://{hostname}:{port}/api/v1"). + * * @param server the server holding a URL with maybe variable placeholders. * @return the server URL with all placeholders resolved or "/" by default. */ private static String resolveUrl(Server server) { String url = Optional.ofNullable(server.url).orElse("/"); if (server.variables != null) { - for (Map.Entry variable: server.variables.entrySet()) { + for (Map.Entry variable : server.variables.entrySet()) { String defaultValue = Optional.ofNullable(variable.getValue().default_).orElse(""); url = url.replaceAll(String.format("\\{%s\\}", variable.getKey()), defaultValue); } @@ -249,5 +254,4 @@ private static String resolveUrl(Server server) { public static Optional getParameterSchema(Oas30Parameter parameter) { return Optional.ofNullable((OasSchema) parameter.schema); } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java index afee6f3f68..0f78f9c7d8 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomArrayGenerator.java @@ -1,9 +1,10 @@ package org.citrusframework.openapi.random; import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.concurrent.ThreadLocalRandom; import org.citrusframework.openapi.model.OasModelHelper; +import java.util.concurrent.ThreadLocalRandom; + /** * A generator for producing random arrays based on an OpenAPI schema. This class extends the * {@link RandomGenerator} and provides a specific implementation for generating random arrays @@ -11,10 +12,25 @@ * *

      The generator supports arrays with items of a single schema type. If the array's items have * different schemas, an {@link UnsupportedOperationException} will be thrown.

      s - * */ public class RandomArrayGenerator extends RandomGenerator { + private static void createRandomArrayValueWithSchemaItem(RandomContext randomContext, + OasSchema schema, + OasSchema itemsSchema) { + Number minItems = schema.minItems != null ? schema.minItems : 1; + Number maxItems = schema.maxItems != null ? schema.maxItems : 10; + + int nItems = ThreadLocalRandom.current() + .nextInt(minItems.intValue(), maxItems.intValue() + 1); + + randomContext.getRandomModelBuilder().array(() -> { + for (int i = 0; i < nItems; i++) { + randomContext.generate(itemsSchema); + } + }); + } + @Override public boolean handles(OasSchema other) { return OasModelHelper.isArrayType(other); @@ -28,24 +44,7 @@ void generate(RandomContext randomContext, OasSchema schema) { createRandomArrayValueWithSchemaItem(randomContext, schema, itemsSchema); } else { throw new UnsupportedOperationException( - "Random array creation for an array with items having different schema is currently not supported!"); + "Random array creation for an array with items having different schema is currently not supported!"); } } - - private static void createRandomArrayValueWithSchemaItem(RandomContext randomContext, - OasSchema schema, - OasSchema itemsSchema) { - - Number minItems = schema.minItems != null ? schema.minItems : 1; - Number maxItems = schema.maxItems != null ? schema.maxItems : 10; - - int nItems = ThreadLocalRandom.current() - .nextInt(minItems.intValue(), maxItems.intValue() + 1); - - randomContext.getRandomModelBuilder().array(() -> { - for (int i = 0; i < nItems; i++) { - randomContext.generate(itemsSchema); - } - }); - } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java index 6a7877ca39..7406c632f6 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomCompositeGenerator.java @@ -1,14 +1,15 @@ package org.citrusframework.openapi.random; -import static org.springframework.util.CollectionUtils.isEmpty; - import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.model.OasModelHelper; + import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; -import org.citrusframework.openapi.model.OasModelHelper; + +import static org.springframework.util.CollectionUtils.isEmpty; /** * A generator for producing random composite schemas based on an OpenAPI schema. This class extends @@ -19,31 +20,12 @@ */ public class RandomCompositeGenerator extends RandomGenerator { - @Override - public boolean handles(OasSchema other) { - return OasModelHelper.isCompositeSchema(other); - } - - @Override - void generate(RandomContext randomContext, OasSchema schema) { - - if (!isEmpty(schema.allOf)) { - createAllOff(randomContext, schema); - } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.anyOf)) { - createAnyOf(randomContext, oas30Schema); - } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.oneOf)) { - createOneOf(randomContext, oas30Schema.oneOf); - } - } - private static void createOneOf(RandomContext randomContext, List schemas) { int schemaIndex = ThreadLocalRandom.current().nextInt(schemas.size()); - randomContext.getRandomModelBuilder().object(() -> - randomContext.generate(schemas.get(schemaIndex))); + randomContext.getRandomModelBuilder().object(() -> randomContext.generate(schemas.get(schemaIndex))); } private static void createAnyOf(RandomContext randomContext, Oas30Schema schema) { - randomContext.getRandomModelBuilder().object(() -> { boolean anyAdded = false; for (OasSchema oneSchema : schema.anyOf) { @@ -60,7 +42,7 @@ private static void createAnyOf(RandomContext randomContext, Oas30Schema schema) }); } - private static Map createAllOff(RandomContext randomContext, OasSchema schema) { + private static Map createAllOf(RandomContext randomContext, OasSchema schema) { Map allOf = new HashMap<>(); randomContext.getRandomModelBuilder().object(() -> { @@ -71,4 +53,20 @@ private static Map createAllOff(RandomContext randomContext, Oas return allOf; } + + @Override + public boolean handles(OasSchema other) { + return OasModelHelper.isCompositeSchema(other); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + if (!isEmpty(schema.allOf)) { + createAllOf(randomContext, schema); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.anyOf)) { + createAnyOf(randomContext, oas30Schema); + } else if (schema instanceof Oas30Schema oas30Schema && !isEmpty(oas30Schema.oneOf)) { + createOneOf(randomContext, oas30Schema.oneOf); + } + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java index c986a16eb3..f4f9f7f5a1 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java @@ -1,18 +1,19 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE; import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE_TIME; import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; import static org.citrusframework.openapi.OpenApiConstants.TYPE_BOOLEAN; import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; import static org.citrusframework.openapi.random.RandomGenerator.ANY; -import static org.citrusframework.openapi.random.RandomGenerator.NULL_GENERATOR; -import static org.citrusframework.openapi.random.RandomGeneratorBuilder.builder; - -import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import static org.citrusframework.openapi.random.RandomGenerator.NOOP_RANDOM_GENERATOR; +import static org.citrusframework.openapi.random.RandomGeneratorBuilder.randomGeneratorBuilder; /** * Configuration class that initializes and manages a list of random generators @@ -21,31 +22,30 @@ */ public class RandomConfiguration { + public static final RandomConfiguration RANDOM_CONFIGURATION = new RandomConfiguration(); + private static final String EMAIL_PATTERN = "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}"; private static final String URI_PATTERN = "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})"; private static final String HOSTNAME_PATTERN = "(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])"; private static final String IPV4_PATTERN = "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"; private static final String IPV6_PATTERN = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"; - private final List randomGenerators; - public static final RandomConfiguration RANDOM_CONFIGURATION = new RandomConfiguration(); - private RandomConfiguration() { List generators = new ArrayList<>(); // Note that the order of generators in the list is relevant, as the list is traversed from start to end, to find the first matching generator for a schema, and some generators match for less significant schemas. generators.add(new RandomEnumGenerator()); - generators.add(builder(TYPE_STRING, FORMAT_DATE).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd')"))); - generators.add(builder(TYPE_STRING, FORMAT_DATE_TIME).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')"))); - generators.add(builder(TYPE_STRING, FORMAT_UUID).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomUUID()"))); - generators.add(builder(TYPE_STRING, "email").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+EMAIL_PATTERN+"')"))); - generators.add(builder(TYPE_STRING, "uri").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+URI_PATTERN+"')"))); - generators.add(builder(TYPE_STRING, "hostname").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+HOSTNAME_PATTERN+"')"))); - generators.add(builder(TYPE_STRING, "ipv4").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+IPV4_PATTERN+"')"))); - generators.add(builder(TYPE_STRING,"ipv6").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+IPV6_PATTERN+"')"))); - generators.add(builder().withType(TYPE_STRING).withPattern(ANY).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('"+schema.pattern+"')"))); - generators.add(builder().withType(TYPE_BOOLEAN).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimple("citrus:randomEnumValue('true', 'false')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE_TIME).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_UUID).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomUUID()"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "email").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + EMAIL_PATTERN + "')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "uri").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + URI_PATTERN + "')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "hostname").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + HOSTNAME_PATTERN + "')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "ipv4").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV4_PATTERN + "')"))); + generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "ipv6").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV6_PATTERN + "')"))); + generators.add(randomGeneratorBuilder().withType(TYPE_STRING).withPattern(ANY).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + schema.pattern + "')"))); + generators.add(randomGeneratorBuilder().withType(TYPE_BOOLEAN).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimple("citrus:randomEnumValue('true', 'false')"))); generators.add(new RandomStringGenerator()); generators.add(new RandomCompositeGenerator()); generators.add(new RandomNumberGenerator()); @@ -57,7 +57,7 @@ private RandomConfiguration() { public RandomGenerator getGenerator(OasSchema oasSchema) { return randomGenerators.stream().filter(generator -> generator.handles(oasSchema)) - .findFirst() - .orElse(NULL_GENERATOR); + .findFirst() + .orElse(NOOP_RANDOM_GENERATOR); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java index 978d3b666b..7262f57aff 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomContext.java @@ -1,14 +1,16 @@ package org.citrusframework.openapi.random; -import static org.citrusframework.openapi.random.RandomConfiguration.RANDOM_CONFIGURATION; - import io.apicurio.datamodels.openapi.models.OasSchema; +import jakarta.annotation.Nullable; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.model.OasModelHelper; + import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.function.Function; -import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.model.OasModelHelper; + +import static org.citrusframework.openapi.random.RandomConfiguration.RANDOM_CONFIGURATION; /** * Context class for generating random values based on an OpenAPI specification. @@ -18,20 +20,17 @@ public class RandomContext { private final OpenApiSpecification specification; - - private Map schemaDefinitions; - private final RandomModelBuilder randomModelBuilder; /** * Cache for storing variable during random value generation. */ private final Map contextVariables = new HashMap<>(); + private Map schemaDefinitions; /** * Constructs a default RandomContext backed by no specification. Note, that this context can not * resolve referenced schemas, as no specification is available. - * */ public RandomContext() { this.randomModelBuilder = new RandomModelBuilder(false); @@ -42,13 +41,31 @@ public RandomContext() { * Constructs a new RandomContext with the specified OpenAPI specification and quote option. * * @param specification the OpenAPI specification - * @param quote whether to quote the generated random values + * @param quote whether to quote the generated random values */ public RandomContext(OpenApiSpecification specification, boolean quote) { this.specification = specification; this.randomModelBuilder = new RandomModelBuilder(quote); } + /** + * Returns the OpenAPI specification associated with this context. + * + * @return the OpenAPI specification + */ + public OpenApiSpecification getSpecification() { + return specification; + } + + /** + * Returns the RandomModelBuilder associated with this context. + * + * @return the RandomModelBuilder + */ + public RandomModelBuilder getRandomModelBuilder() { + return randomModelBuilder; + } + /** * Generates random values based on the specified schema. * @@ -68,7 +85,7 @@ void doGenerate(OasSchema resolvedSchema) { * @param schema the schema to resolve * @return the resolved schema */ - OasSchema resolveSchema(OasSchema schema) { + @Nullable OasSchema resolveSchema(OasSchema schema) { if (OasModelHelper.isReferenceType(schema)) { if (schemaDefinitions == null) { schemaDefinitions = getSchemaDefinitions(); @@ -78,38 +95,20 @@ OasSchema resolveSchema(OasSchema schema) { return schema; } - /** - * Returns the RandomModelBuilder associated with this context. - * - * @return the RandomModelBuilder - */ - public RandomModelBuilder getRandomModelBuilder() { - return randomModelBuilder; - } - - /** - * Returns the OpenAPI specification associated with this context. - * - * @return the OpenAPI specification - */ - public OpenApiSpecification getSpecification() { - return specification; - } - /** * Returns the schema definitions from the specified OpenAPI document. * * @return a map of schema definitions */ Map getSchemaDefinitions() { - return specification != null ?OasModelHelper.getSchemaDefinitions(specification.getOpenApiDoc(null)) : Collections.emptyMap(); + return specification != null ? OasModelHelper.getSchemaDefinitions(specification.getOpenApiDoc(null)) : Collections.emptyMap(); } /** * Retrieves a context variable by key, computing its value if necessary using the provided mapping function. * - * @param the type of the context variable - * @param key the key of the context variable + * @param the type of the context variable + * @param key the key of the context variable * @param mappingFunction the function to compute the value if it is not present * @return the context variable value */ diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java index 67b46e8be7..994b78227e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomEnumGenerator.java @@ -1,11 +1,12 @@ package org.citrusframework.openapi.random; import io.apicurio.datamodels.openapi.models.OasSchema; + import java.util.List; -import java.util.stream.Collectors; -public class RandomEnumGenerator extends RandomGenerator { +import static java.util.stream.Collectors.joining; +public class RandomEnumGenerator extends RandomGenerator { @Override public boolean handles(OasSchema other) { @@ -16,10 +17,10 @@ public boolean handles(OasSchema other) { void generate(RandomContext randomContext, OasSchema schema) { List anEnum = schema.enum_; if (anEnum != null) { - String enumValues = schema.enum_.stream().map(value -> "'" + value + "'") - .collect(Collectors.joining(",")); + String enumValues = schema.enum_.stream() + .map(value -> "'" + value + "'") + .collect(joining(",")); randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomEnumValue(%s)".formatted(enumValues)); } } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java index 9f74422e48..8a2bfa0bce 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGenerator.java @@ -1,6 +1,7 @@ package org.citrusframework.openapi.random; import io.apicurio.datamodels.openapi.models.OasSchema; + import java.util.Objects; /** @@ -13,7 +14,13 @@ public abstract class RandomGenerator { public static final String ANY = "$ANY$"; + public static final RandomGenerator NOOP_RANDOM_GENERATOR = new RandomGenerator() { + @Override + void generate(RandomContext randomContext, OasSchema schema) { + // Do nothing + } + }; private final OasSchema schema; protected RandomGenerator() { @@ -31,11 +38,11 @@ public boolean handles(OasSchema other) { if (ANY.equals(schema.type) || Objects.equals(schema.type, other.type)) { if (schema.format != null) { - return (ANY.equals(schema.format) && other.format != null)|| Objects.equals(schema.format, other.format); + return (ANY.equals(schema.format) && other.format != null) || Objects.equals(schema.format, other.format); } if (schema.pattern != null) { - return (ANY.equals(schema.pattern) && other.pattern != null) || Objects.equals(schema.pattern, other.pattern); + return (ANY.equals(schema.pattern) && other.pattern != null) || Objects.equals(schema.pattern, other.pattern); } if (schema.enum_ != null && other.enum_ != null) { @@ -50,12 +57,4 @@ public boolean handles(OasSchema other) { abstract void generate(RandomContext randomContext, OasSchema schema); - public static final RandomGenerator NULL_GENERATOR = new RandomGenerator() { - - @Override - void generate(RandomContext randomContext, OasSchema schema) { - // Do nothing - } - }; - } \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java index 8fbeac3ef4..7cf024b672 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomGeneratorBuilder.java @@ -2,6 +2,7 @@ import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; + import java.util.Collections; import java.util.function.BiConsumer; @@ -15,11 +16,11 @@ public class RandomGeneratorBuilder { private RandomGeneratorBuilder() { } - static RandomGeneratorBuilder builder() { + static RandomGeneratorBuilder randomGeneratorBuilder() { return new RandomGeneratorBuilder(); } - static RandomGeneratorBuilder builder(String type, String format) { + static RandomGeneratorBuilder randomGeneratorBuilder(String type, String format) { return new RandomGeneratorBuilder().with(type, format); } @@ -29,7 +30,6 @@ RandomGeneratorBuilder with(String type, String format) { return this; } - RandomGeneratorBuilder withType(String type) { schema.type = type; return this; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java index c2ff6bbfea..790e943ec0 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelBuilder.java @@ -16,16 +16,17 @@ package org.citrusframework.openapi.random; -import java.util.ArrayDeque; -import java.util.Deque; import org.citrusframework.openapi.random.RandomElement.RandomList; import org.citrusframework.openapi.random.RandomElement.RandomObject; import org.citrusframework.openapi.random.RandomElement.RandomValue; +import java.util.ArrayDeque; +import java.util.Deque; + /** * RandomModelBuilder is a class for building random JSON models. It supports adding simple values, * objects, properties, and arrays to the JSON structure. The final model can be converted to a JSON - * string using the `writeToJson` method. I + * string using the `writeToJson` method. *

      * The builder is able to build nested structures and can also handle native string, number, and * boolean elements, represented as functions for later dynamic string conversion by Citrus. @@ -79,7 +80,8 @@ public void appendSimple(String simpleValue) { /** * If the builder is in quoting mode, the native value will be quoted, otherwise it will be * added as ist. - *s + * s + * * @param simpleValue */ public void appendSimpleQuoted(String simpleValue) { @@ -87,23 +89,15 @@ public void appendSimpleQuoted(String simpleValue) { } public void object(Runnable objectBuilder) { - if (deque.isEmpty()) { - throwIllegalState(); - } + assertItemsInDequeOrThrow(); RandomObject randomObject = new RandomObject(); deque.peek().push(randomObject); objectBuilder.run(); } - private static void throwIllegalState() { - throw new IllegalStateException("Encountered empty stack!"); - } - public void property(String key, Runnable valueBuilder) { - if (deque.isEmpty()) { - throwIllegalState(); - } + assertItemsInDequeOrThrow(); RandomValue randomValue = new RandomValue(); deque.peek().push(key, randomValue); @@ -114,9 +108,8 @@ public void property(String key, Runnable valueBuilder) { } public void array(Runnable arrayBuilder) { - if (deque.isEmpty()) { - throwIllegalState(); - } + assertItemsInDequeOrThrow(); + RandomList randomList = new RandomList(); deque.peek().push(randomList); @@ -128,8 +121,13 @@ public void array(Runnable arrayBuilder) { deque.pop(); } - public String quote(String text) { + private String quote(String text) { return quote ? String.format("\"%s\"", text) : text; } + private void assertItemsInDequeOrThrow() { + if (deque.isEmpty()) { + throw new IllegalStateException("Encountered empty stack!"); + } + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java index 2c37e621e5..c48dbbaa27 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomModelWriter.java @@ -16,41 +16,38 @@ package org.citrusframework.openapi.random; -import static org.citrusframework.util.StringUtils.trimTrailingComma; +import org.citrusframework.openapi.random.RandomElement.RandomValue; import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import org.citrusframework.openapi.random.RandomElement.RandomValue; + +import static org.citrusframework.util.StringUtils.trimTrailingComma; /** * Utility class for converting a {@link RandomModelBuilder} to its string representation. * This class provides static methods to serialize the model built by {@link RandomModelBuilder}. */ -class RandomModelWriter { +final class RandomModelWriter { private RandomModelWriter() { // static access only } static String toString(RandomModelBuilder randomModelBuilder) { - StringBuilder builder = new StringBuilder(); appendObject(builder, randomModelBuilder.deque); return builder.toString(); } private static void appendObject(StringBuilder builder, Object object) { - if (object instanceof Deque deque) { while (!deque.isEmpty()) { appendObject(builder, deque.pop()); } - return; - } - if (object instanceof Map map) { - //noinspection unchecked + } else if (object instanceof Map map) { + // noinspection unchecked appendMap(builder, (Map) map); } else if (object instanceof List list) { appendArray(builder, list); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java index a9c0742259..131f3c949e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomNumberGenerator.java @@ -1,19 +1,20 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import org.citrusframework.openapi.util.OpenApiUtils; + +import java.math.BigDecimal; + import static java.lang.Boolean.TRUE; import static java.lang.String.format; import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; -import io.apicurio.datamodels.openapi.models.OasSchema; -import java.math.BigDecimal; -import org.citrusframework.openapi.util.OpenApiUtils; - /** * A generator for producing random numbers based on an OpenAPI schema. This class extends the * {@link RandomGenerator} and provides a specific implementation for generating random numbers with * constraints defined in the schema. - * - *

      Supported constraints: + *

      + * Supported constraints: *

        *
      • minimum: The minimum value for the generated number.
      • *
      • maximum: The maximum value for the generated number.
      • @@ -21,13 +22,13 @@ *
      • exclusiveMaximum: If true, the generated number will be strictly less than the maximum.
      • *
      • multipleOf: The generated number will be a multiple of this value.
      • *
      - * - *

      The generator supports generating numbers for both integer and floating-point types, including + *

      + * The generator supports generating numbers for both integer and floating-point types, including * int32, int64, double, and float. This support * extends to the multipleOf constraint, ensuring that the generated numbers can be precise * multiples of the specified value. - * - *

      The generator determines the appropriate bounds and constraints based on the provided schema + *

      + * The generator determines the appropriate bounds and constraints based on the provided schema * and generates a random number accordingly. */ public class RandomNumberGenerator extends RandomGenerator { @@ -36,66 +37,6 @@ public class RandomNumberGenerator extends RandomGenerator { public static final BigDecimal HUNDRED = java.math.BigDecimal.valueOf(100); public static final BigDecimal MINUS_THOUSAND = new BigDecimal(-1000); - @Override - public boolean handles(OasSchema other) { - return OpenApiUtils.isAnyNumberScheme(other); - } - - @Override - void generate(RandomContext randomContext, OasSchema schema) { - - boolean exclusiveMaximum = TRUE.equals(schema.exclusiveMaximum); - boolean exclusiveMinimum = TRUE.equals(schema.exclusiveMinimum); - - BigDecimal[] bounds = determineBounds(schema); - - BigDecimal minimum = bounds[0]; - BigDecimal maximum = bounds[1]; - - if (schema.multipleOf != null) { - randomContext.getRandomModelBuilder().appendSimple(format( - "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s', '%s')", - determineDecimalPlaces(schema, minimum, maximum), - minimum, - maximum, - exclusiveMinimum, - exclusiveMaximum, - schema.multipleOf - )); - } else { - randomContext.getRandomModelBuilder().appendSimple(format( - "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s')", - determineDecimalPlaces(schema, minimum, maximum), - minimum, - maximum, - exclusiveMinimum, - exclusiveMaximum - )); - } - } - - /** - * Determines the number of decimal places to use based on the given schema and - * minimum/maximum/multipleOf values. For integer types, it returns 0. For other types, it - * returns the maximum number of decimal places found between the minimum and maximum values, - * with a minimum of 2 decimal places. - */ - private int determineDecimalPlaces(OasSchema schema, BigDecimal minimum, - BigDecimal maximum) { - if (TYPE_INTEGER.equals(schema.type)) { - return 0; - } else { - Number multipleOf = schema.multipleOf; - if (multipleOf != null) { - return findLeastSignificantDecimalPlace(new BigDecimal(multipleOf.toString())); - } - - return Math.max(2, Math.max(findLeastSignificantDecimalPlace(minimum), - findLeastSignificantDecimalPlace(maximum))); - - } - } - /** * Determine some reasonable bounds for a random number */ @@ -140,6 +81,63 @@ static BigDecimal calculateMaxRelativeToMin(BigDecimal min, Number multipleOf) { } } + @Override + public boolean handles(OasSchema other) { + return OpenApiUtils.isAnyNumberScheme(other); + } + + @Override + void generate(RandomContext randomContext, OasSchema schema) { + boolean exclusiveMaximum = TRUE.equals(schema.exclusiveMaximum); + boolean exclusiveMinimum = TRUE.equals(schema.exclusiveMinimum); + + BigDecimal[] bounds = determineBounds(schema); + + BigDecimal minimum = bounds[0]; + BigDecimal maximum = bounds[1]; + + if (schema.multipleOf != null) { + randomContext.getRandomModelBuilder().appendSimple(format( + "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s', '%s')", + determineDecimalPlaces(schema, minimum, maximum), + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum, + schema.multipleOf + )); + } else { + randomContext.getRandomModelBuilder().appendSimple(format( + "citrus:randomNumberGenerator('%d', '%s', '%s', '%s', '%s')", + determineDecimalPlaces(schema, minimum, maximum), + minimum, + maximum, + exclusiveMinimum, + exclusiveMaximum + )); + } + } + + /** + * Determines the number of decimal places to use based on the given schema and + * minimum/maximum/multipleOf values. For integer types, it returns 0. For other types, it + * returns the maximum number of decimal places found between the minimum and maximum values, + * with a minimum of 2 decimal places. + */ + private int determineDecimalPlaces(OasSchema schema, BigDecimal minimum, BigDecimal maximum) { + if (TYPE_INTEGER.equals(schema.type)) { + return 0; + } else { + Number multipleOf = schema.multipleOf; + if (multipleOf != null) { + return findLeastSignificantDecimalPlace(new BigDecimal(multipleOf.toString())); + } + + return Math.max(2, Math.max(findLeastSignificantDecimalPlace(minimum), + findLeastSignificantDecimalPlace(maximum))); + } + } + int findLeastSignificantDecimalPlace(BigDecimal number) { number = number.stripTrailingZeros(); @@ -151,5 +149,4 @@ int findLeastSignificantDecimalPlace(BigDecimal number) { return parts[1].length(); } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java index 8b7ef2b9d4..bfd85f1ada 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomObjectGenerator.java @@ -2,18 +2,20 @@ import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.util.OpenApiUtils; + import java.util.ArrayDeque; import java.util.Deque; import java.util.Map; -import org.citrusframework.openapi.OpenApiConstants; -import org.citrusframework.openapi.util.OpenApiUtils; + +import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; /** * A generator for producing random objects based on an OpenAPI schema. This class extends * the {@link RandomGenerator} and provides a specific implementation for generating objects * with properties defined in the schema. - * - *

      The generator supports object schemas and prevents recursion by keeping track of the + *

      + * The generator supports object schemas and prevents recursion by keeping track of the * schemas being processed.

      */ public class RandomObjectGenerator extends RandomGenerator { @@ -23,7 +25,7 @@ public class RandomObjectGenerator extends RandomGenerator { private static final OasSchema OBJECT_SCHEMA = new Oas30Schema(); static { - OBJECT_SCHEMA.type = OpenApiConstants.TYPE_OBJECT; + OBJECT_SCHEMA.type = TYPE_OBJECT; } public RandomObjectGenerator() { @@ -32,7 +34,6 @@ public RandomObjectGenerator() { @Override void generate(RandomContext randomContext, OasSchema schema) { - Deque objectStack = randomContext.get(OBJECT_STACK, k -> new ArrayDeque<>()); if (objectStack.contains(schema)) { @@ -44,15 +45,15 @@ void generate(RandomContext randomContext, OasSchema schema) { randomContext.getRandomModelBuilder().object(() -> { if (schema.properties != null) { for (Map.Entry entry : schema.properties.entrySet()) { - if (randomContext.getSpecification().isGenerateOptionalFields() || OpenApiUtils.isRequired(schema, - entry.getKey())) { - randomContext.getRandomModelBuilder().property(entry.getKey(), () -> - randomContext.generate(entry.getValue())); + if (randomContext.getSpecification().isGenerateOptionalFields() + || OpenApiUtils.isRequired(schema, entry.getKey())) { + randomContext.getRandomModelBuilder() + .property(entry.getKey(), () -> randomContext.generate(entry.getValue())); } } } }); + objectStack.pop(); } - } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java index cc30c220eb..3a592bb3e4 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomStringGenerator.java @@ -2,7 +2,8 @@ import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import org.citrusframework.openapi.OpenApiConstants; + +import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; /** * A generator for producing random strings based on an OpenAPI schema. @@ -14,7 +15,7 @@ public class RandomStringGenerator extends RandomGenerator { private static final OasSchema STRING_SCHEMA = new Oas30Schema(); static { - STRING_SCHEMA.type = OpenApiConstants.TYPE_STRING; + STRING_SCHEMA.type = TYPE_STRING; } public RandomStringGenerator() { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java index 1e0916a40f..2fc57f6723 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/util/OpenApiUtils.java @@ -16,18 +16,19 @@ package org.citrusframework.openapi.util; -import static java.lang.String.format; -import static org.citrusframework.util.StringUtils.hasText; - import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nonnull; -import java.util.stream.Collectors; +import jakarta.annotation.Nullable; import org.citrusframework.openapi.OpenApiConstants; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.spi.ReferenceResolver; -public class OpenApiUtils { +import static java.lang.String.format; +import static java.util.stream.Collectors.joining; +import static org.citrusframework.util.StringUtils.hasText; + +public final class OpenApiUtils { private OpenApiUtils() { // Static access only @@ -44,7 +45,7 @@ public static String getMethodPath(@Nonnull String method, @Nonnull String path) * @return a unique scenario id for the {@link OasOperation} */ public static String createFullPathOperationIdentifier(OasOperation oasOperation, String path) { - return format("%s_%s", oasOperation.getMethod().toUpperCase(), path); + return createFullPathOperationIdentifier(oasOperation.getMethod().toUpperCase(), path); } /** @@ -54,12 +55,10 @@ public static String createFullPathOperationIdentifier(String method, String pat return format("%s_%s", method.toUpperCase(), path); } - public static boolean isAnyNumberScheme(OasSchema schema) { - return ( - schema != null && - (OpenApiConstants.TYPE_INTEGER.equalsIgnoreCase(schema.type) || - OpenApiConstants.TYPE_NUMBER.equalsIgnoreCase(schema.type)) - ); + public static boolean isAnyNumberScheme(@Nullable OasSchema schema) { + return schema != null + && (OpenApiConstants.TYPE_INTEGER.equalsIgnoreCase(schema.type) + || OpenApiConstants.TYPE_NUMBER.equalsIgnoreCase(schema.type)); } /** @@ -82,9 +81,9 @@ public static boolean isRequired(OasSchema schema, String field) { */ public static String getKnownOpenApiAliases(ReferenceResolver resolver) { return resolver.resolveAll(OpenApiRepository.class).values() - .stream().flatMap( - openApiRepository -> openApiRepository.getOpenApiSpecifications() - .stream()).flatMap(spec -> spec.getAliases().stream()).collect( - Collectors.joining(", ")); + .stream() + .flatMap(openApiRepository -> openApiRepository.getOpenApiSpecifications().stream()) + .flatMap(spec -> spec.getAliases().stream()) + .collect(joining(", ")); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java index 6a3a18a76c..a73a250650 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageValidationContext.java @@ -11,8 +11,7 @@ * * @since 4.3 */ -public class OpenApiMessageValidationContext extends DefaultValidationContext implements - SchemaValidationContext { +public class OpenApiMessageValidationContext extends DefaultValidationContext implements SchemaValidationContext { /** * Should message be validated with its schema definition. This is enabled with respect to @@ -29,9 +28,8 @@ public OpenApiMessageValidationContext(Builder builder) { // If not explicitly specified, goe for the default. this.schemaValidation = builder.schemaValidation != null ? builder.schemaValidation - : builder.openApiSpecification.isApiRequestValidationEnabled() + : builder.openApiSpecification.isApiRequestValidationEnabled() || builder.openApiSpecification.isApiResponseValidationEnabled(); - } @Override @@ -53,8 +51,8 @@ public String getSchema() { * Fluent builder */ public static final class Builder implements - ValidationContext.Builder, - SchemaValidationContext.Builder { + ValidationContext.Builder, + SchemaValidationContext.Builder { private OpenApiSpecification openApiSpecification; @@ -67,8 +65,7 @@ public static final class Builder implements */ private Boolean schemaValidation = OpenApiSettings.isRequestValidationEnabledGlobally(); - public static OpenApiMessageValidationContext.Builder openApi( - OpenApiSpecification openApiSpecification) { + public static OpenApiMessageValidationContext.Builder openApi(OpenApiSpecification openApiSpecification) { Builder builder = new Builder(); builder.openApiSpecification = openApiSpecification; return builder; @@ -78,8 +75,7 @@ public OpenApiMessageValidationContext.Builder expressions() { return new OpenApiMessageValidationContext.Builder(); } - public OpenApiMessageValidationContext.Builder expression(String path, - Object expectedValue) { + public OpenApiMessageValidationContext.Builder expression(String path, Object expectedValue) { return new OpenApiMessageValidationContext.Builder().expression(path, expectedValue); } @@ -103,8 +99,7 @@ public OpenApiMessageValidationContext.Builder schema(final String schemaName) { * Not used for open api validation. Schema is automatically be derived from associated openApiSpecification. */ @Override - public OpenApiMessageValidationContext.Builder schemaRepository( - final String schemaRepository) { + public OpenApiMessageValidationContext.Builder schemaRepository(final String schemaRepository) { return this; } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessor.java similarity index 60% rename from connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java rename to connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessor.java index d20c899fc2..9d41d50551 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiMessageProcessor.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessor.java @@ -16,18 +16,20 @@ package org.citrusframework.openapi.validation; -import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.context.TestContext; import org.citrusframework.message.Message; import org.citrusframework.message.MessageProcessor; -import org.citrusframework.openapi.OpenApiMessageHeaders; +import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; +import static org.citrusframework.openapi.OpenApiMessageHeaders.OAS_MESSAGE_TYPE; +import static org.citrusframework.openapi.OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID; + /** * {@code MessageProcessor} that prepares the message for OpenAPI validation by setting respective * message headers. */ -public class OpenApiMessageProcessor implements MessageProcessor { +public class OpenApiOperationToMessageHeadersProcessor implements MessageProcessor { private final OpenApiSpecification openApiSpecification; @@ -35,8 +37,9 @@ public class OpenApiMessageProcessor implements MessageProcessor { private final OpenApiMessageType type; - public OpenApiMessageProcessor(OpenApiSpecification openApiSpecification, - String operationId, OpenApiMessageType type) { + public OpenApiOperationToMessageHeadersProcessor(OpenApiSpecification openApiSpecification, + String operationId, + OpenApiMessageType type) { this.operationId = operationId; this.openApiSpecification = openApiSpecification; this.type = type; @@ -44,13 +47,12 @@ public OpenApiMessageProcessor(OpenApiSpecification openApiSpecification, @Override public void process(Message message, TestContext context) { - openApiSpecification - .getOperation(operationId, context) - .ifPresent(operationPathAdapter -> { - // Store the uniqueId of the operation, rather than the operationId, to avoid clashes. - message.setHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID, operationPathAdapter.uniqueOperationId()); - message.setHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE, type.toHeaderName()); - }); + .getOperation(operationId, context) + .ifPresent(operationPathAdapter -> { + // Store the uniqueId of the operation, rather than the operationId, to avoid clashes. + message.setHeader(OAS_UNIQUE_OPERATION_ID, operationPathAdapter.uniqueOperationId()); + message.setHeader(OAS_MESSAGE_TYPE, type.toHeaderName()); + }); } -} \ No newline at end of file +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java index a3809f1858..a924470547 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiRequestValidator.java @@ -19,24 +19,28 @@ import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.SimpleRequest; import com.atlassian.oai.validator.report.ValidationReport; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageHeaders; import org.citrusframework.http.message.HttpMessageUtils; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.util.FileUtils; import org.springframework.util.MultiValueMap; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; + +import static org.citrusframework.util.FileUtils.getDefaultCharset; + /** - * Specific validator that uses atlassian and is responsible for validating HTTP requests - * against an OpenAPI specification using the provided {@code OpenApiInteractionValidator}. + * Specific validator that uses Atlassian's Swagger Request Validator + * underneath. It is responsible for validating HTTP requests against + * an OpenAPI specification using the + * provided {@code OpenApiInteractionValidator}. */ public class OpenApiRequestValidator extends OpenApiValidator { @@ -49,32 +53,29 @@ protected String getType() { return "request"; } - public void validateRequest(OperationPathAdapter operationPathAdapter, - HttpMessage requestMessage) { - + public void validateRequest(OperationPathAdapter operationPathAdapter, HttpMessage requestMessage) { if (openApiInteractionValidator != null) { ValidationReport validationReport = openApiInteractionValidator.validateRequest( - createRequestFromMessage(operationPathAdapter, requestMessage)); + createRequestFromMessage(operationPathAdapter, requestMessage)); if (validationReport.hasErrors()) { throw new ValidationException( - constructErrorMessage(operationPathAdapter, validationReport)); + constructErrorMessage(operationPathAdapter, validationReport)); } } } public ValidationReport validateRequestToReport(OperationPathAdapter operationPathAdapter, - HttpMessage requestMessage) { - + HttpMessage requestMessage) { if (openApiInteractionValidator != null) { return openApiInteractionValidator.validateRequest( - createRequestFromMessage(operationPathAdapter, requestMessage)); + createRequestFromMessage(operationPathAdapter, requestMessage)); } return ValidationReport.empty(); } Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, - HttpMessage httpMessage) { + HttpMessage httpMessage) { var payload = httpMessage.getPayload(); String contextPath = operationPathAdapter.contextPath(); @@ -84,7 +85,7 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, } SimpleRequest.Builder requestBuilder = new SimpleRequest.Builder( - httpMessage.getRequestMethod().asHttpMethod().name(), requestUri + httpMessage.getRequestMethod().asHttpMethod().name(), requestUri ); if (payload != null) { @@ -95,27 +96,24 @@ Request createRequestFromMessage(OperationPathAdapter operationPathAdapter, finalRequestBuilder.withAccept(httpMessage.getAccept()); HttpMessageUtils.getQueryParameterMap(httpMessage) - .forEach((key, value) -> finalRequestBuilder.withQueryParam(key, new ArrayList<>( - value))); + .forEach((key, value) -> finalRequestBuilder.withQueryParam(key, new ArrayList<>(value))); httpMessage.getHeaders().forEach((key, value) -> { if (value instanceof Collection collection) { - collection.forEach( v -> finalRequestBuilder.withHeader(key, v != null ? v.toString() : null)); + collection.forEach(v -> finalRequestBuilder.withHeader(key, v != null ? v.toString() : null)); } else { - finalRequestBuilder.withHeader(key, - value != null ? value.toString() : null); + finalRequestBuilder.withHeader(key, value != null ? value.toString() : null); } }); - httpMessage.getCookies().forEach(cookie -> finalRequestBuilder.withHeader("Cookie", URLDecoder.decode(cookie.getName()+"="+cookie.getValue(), - FileUtils.getDefaultCharset()))); + httpMessage.getCookies().forEach(cookie -> finalRequestBuilder.withHeader("Cookie", URLDecoder.decode(cookie.getName() + "=" + cookie.getValue(), + getDefaultCharset()))); return requestBuilder.build(); } private String convertPayload(Object payload) { - - if (payload instanceof MultiValueMap multiValueMap) { + if (payload instanceof MultiValueMap multiValueMap) { return serializeForm(multiValueMap, StandardCharsets.UTF_8); } @@ -125,7 +123,7 @@ private String convertPayload(Object payload) { /** * We cannot validate a MultiValueMap. The map will later on be converted to a string representation * by Spring. For validation, we need to mimic this transformation here. - + * * @see org.springframework.http.converter.FormHttpMessageConverter */ private String serializeForm(MultiValueMap formData, Charset charset) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java index c7af584c62..9d7a64bc37 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiResponseValidator.java @@ -42,16 +42,14 @@ protected String getType() { } public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { - if (openApiInteractionValidator != null) { HttpStatusCode statusCode = httpMessage.getStatusCode(); - Response response = createResponseFromMessage(httpMessage, - statusCode != null ? statusCode.value() : null); + Response response = createResponseFromMessage(httpMessage, statusCode != null ? statusCode.value() : null); ValidationReport validationReport = openApiInteractionValidator.validateResponse( - operationPathAdapter.apiPath(), - Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), - response); + operationPathAdapter.apiPath(), + Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), + response); if (validationReport.hasErrors()) { throw new ValidationException(constructErrorMessage(operationPathAdapter, validationReport)); } @@ -59,18 +57,16 @@ public void validateResponse(OperationPathAdapter operationPathAdapter, HttpMess } public ValidationReport validateResponseToReport(OperationPathAdapter operationPathAdapter, HttpMessage httpMessage) { - if (openApiInteractionValidator != null) { HttpStatusCode statusCode = httpMessage.getStatusCode(); - Response response = createResponseFromMessage(httpMessage, - statusCode != null ? statusCode.value() : null); + Response response = createResponseFromMessage(httpMessage, statusCode != null ? statusCode.value() : null); return openApiInteractionValidator.validateResponse( - operationPathAdapter.apiPath(), - Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), - response); - + operationPathAdapter.apiPath(), + Method.valueOf(operationPathAdapter.operation().getMethod().toUpperCase()), + response); } + return ValidationReport.empty(); } @@ -84,7 +80,7 @@ Response createResponseFromMessage(HttpMessage message, Integer statusCode) { SimpleResponse.Builder finalResponseBuilder = responseBuilder; message.getHeaders().forEach((key, value) -> finalResponseBuilder.withHeader(key, - value != null ? value.toString() : null)); + value != null ? value.toString() : null)); return responseBuilder.build(); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index 9bfe3affbd..40cbfac92b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -2,9 +2,6 @@ import com.atlassian.oai.validator.report.ValidationReport; import jakarta.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -21,16 +18,29 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class OpenApiSchemaValidation extends AbstractMessageValidator implements - SchemaValidator { +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +public class OpenApiSchemaValidation extends AbstractMessageValidator implements SchemaValidator { + + private static final Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); private static final Set FILTERED_ERROR_MESSAGE_KEYS = Set.of( - // Filtered because in general OpenAPI is not required to specify all response codes. - // So this should not be considered as validation error. - "validation.response.status.unknown" + // Filtered because in general OpenAPI is not required to specify all response codes. + // So this should not be considered as validation error. + "validation.response.status.unknown" ); - private static final Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); + /** + * Filter specific messages from the report which are considered irrelevant. + * See {@link OpenApiSchemaValidation#FILTERED_ERROR_MESSAGE_KEYS} for more details. + */ + private static ValidationReport filterIrrelevantMessages(ValidationReportData validationReportData) { + return ValidationReport.from( + validationReportData.report.getMessages().stream() + .filter(msg -> !FILTERED_ERROR_MESSAGE_KEYS.contains(msg.getKey())).toList()); + } @Override protected Class getRequiredValidationContextType() { @@ -38,34 +48,31 @@ protected Class getRequiredValidationContextTyp } @Override - public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, - OpenApiMessageValidationContext validationContext) { + public void validateMessage(Message receivedMessage, + Message controlMessage, + TestContext context, + OpenApiMessageValidationContext validationContext) { // No control message validation, only schema validation validate(receivedMessage, context, validationContext); } @Override - public void validate( - Message message, TestContext context, OpenApiMessageValidationContext validationContext) { + public void validate(Message message, TestContext context, OpenApiMessageValidationContext validationContext) { logger.debug("Starting OpenApi schema validation ..."); if (!(message instanceof HttpMessage httpMessage)) { return; } - ValidationReportData validationReportData = validate(context, httpMessage, - findSchemaRepositories(context), - validationContext); + ValidationReportData validationReportData = validate(context, + httpMessage, + findSchemaRepositories(context), + validationContext); if (validationReportData != null && validationReportData.report != null) { - - ValidationReport filteredReport = filterIrrelevantMessages( - validationReportData); + ValidationReport filteredReport = filterIrrelevantMessages(validationReportData); if (filteredReport.hasErrors()) { - if (logger.isErrorEnabled()) { - logger.error("Failed to validate Json schema for message:\n{}", - message.getPayload(String.class)); - } + logger.error("Failed to validate Json schema for message:\n{}", message.getPayload(String.class)); throw new ValidationException(constructErrorMessage(validationReportData)); } } @@ -73,16 +80,6 @@ public void validate( logger.debug("Json schema validation successful: All values OK"); } - /** - * Filter specific messages from the report which are considered irrelevant. - * See {@link OpenApiSchemaValidation#FILTERED_ERROR_MESSAGE_KEYS} for more details. - */ - private static ValidationReport filterIrrelevantMessages(ValidationReportData validationReportData) { - return ValidationReport.from( - validationReportData.report.getMessages().stream() - .filter(msg -> !FILTERED_ERROR_MESSAGE_KEYS.contains(msg.getKey())).toList()); - } - @Override public boolean supportsMessageType(String messageType, Message message) { return message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null; @@ -94,8 +91,7 @@ private String constructErrorMessage(ValidationReportData validationReportData) stringBuilder.append(validationReportData.type); stringBuilder.append(" validation failed for operation: "); stringBuilder.append(validationReportData.operationPathAdapter); - validationReportData.report.getMessages() - .forEach(message -> stringBuilder.append("\n\t").append(message)); + validationReportData.report.getMessages().forEach(message -> stringBuilder.append("\n\t").append(message)); return stringBuilder.toString(); } @@ -103,55 +99,50 @@ private String constructErrorMessage(ValidationReportData validationReportData) * Find json schema repositories in test context. */ private List findSchemaRepositories(TestContext context) { - return new ArrayList<>( - context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); + return new ArrayList<>(context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); } @Nullable - private ValidationReportData validate(TestContext context, HttpMessage message, - List schemaRepositories, - OpenApiMessageValidationContext validationContext) { + private ValidationReportData validate(TestContext context, + HttpMessage message, + List schemaRepositories, + OpenApiMessageValidationContext validationContext) { if (!validationContext.isSchemaValidationEnabled()) { return null; - } - if (schemaRepositories.isEmpty()) { + } else if (schemaRepositories.isEmpty()) { return null; } else { - // Is it request or response? - String uniqueOperationId = (String) message.getHeader( - OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); + String uniqueOperationId = (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); OpenApiSpecification openApiSpecification = schemaRepositories - .stream() - .flatMap(repository -> repository.getOpenApiSpecifications().stream()) - .filter(spec -> spec.getOperation(uniqueOperationId, - context).isPresent()).findFirst().orElse(null); + .stream() + .flatMap(repository -> repository.getOpenApiSpecifications().stream()) + .filter(spec -> spec.getOperation(uniqueOperationId, context).isPresent()) + .findFirst() + .orElse(null); if (openApiSpecification == null) { throw new CitrusRuntimeException(""" - Unable to derive OpenAPI spec for operation '%s' for validation of message from available " - schema repositories. Known repository aliases are: %s""".formatted( - uniqueOperationId, OpenApiUtils.getKnownOpenApiAliases( - context.getReferenceResolver()))); + Unable to derive OpenAPI spec for operation '%s' for validation of message from available " + schema repositories. Known repository aliases are: %s""".formatted( + uniqueOperationId, OpenApiUtils.getKnownOpenApiAliases(context.getReferenceResolver()))); } - OperationPathAdapter operationPathAdapter = openApiSpecification.getOperation( - uniqueOperationId, context).orElseThrow(() -> new CitrusRuntimeException( - "Unexpectedly could not resolve operation path adapter for operationId: " - + uniqueOperationId)); + OperationPathAdapter operationPathAdapter = openApiSpecification.getOperation(uniqueOperationId, context) + .orElseThrow(() -> new CitrusRuntimeException( + "Unexpectedly could not resolve operation path adapter for operationId: " + + uniqueOperationId)); ValidationReportData validationReportData = null; if (isRequestMessage(message)) { - ValidationReport validationReport = new OpenApiRequestValidator( - openApiSpecification).validateRequestToReport(operationPathAdapter, message); - validationReportData = new ValidationReportData(operationPathAdapter, "request", - validationReport); + ValidationReport validationReport = new OpenApiRequestValidator(openApiSpecification) + .validateRequestToReport(operationPathAdapter, message); + validationReportData = new ValidationReportData(operationPathAdapter, "request", validationReport); } else if (isResponseMessage(message)) { - ValidationReport validationReport = new OpenApiResponseValidator( - openApiSpecification).validateResponseToReport(operationPathAdapter, message); - validationReportData = new ValidationReportData(operationPathAdapter, "response", - validationReport); + ValidationReport validationReport = new OpenApiResponseValidator(openApiSpecification) + .validateResponseToReport(operationPathAdapter, message); + validationReportData = new ValidationReportData(operationPathAdapter, "response", validationReport); } return validationReportData; } @@ -159,37 +150,34 @@ private ValidationReportData validate(TestContext context, HttpMessage message, private boolean isResponseMessage(HttpMessage message) { return OpenApiMessageHeaders.RESPONSE_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); } private boolean isRequestMessage(HttpMessage message) { return OpenApiMessageHeaders.REQUEST_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); - } - - private record ValidationReportData(OperationPathAdapter operationPathAdapter, String type, - ValidationReport report) { - + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)); } @Override public boolean canValidate(Message message, boolean schemaValidationEnabled) { - return schemaValidationEnabled && - message instanceof HttpMessage httpMessage && (isRequestMessage(httpMessage) - || isResponseMessage(httpMessage)); + return schemaValidationEnabled + && message instanceof HttpMessage httpMessage + && (isRequestMessage(httpMessage) || isResponseMessage(httpMessage)); } @Override - public void validate(Message message, TestContext context, String schemaRepository, - String schema) { - + public void validate(Message message, TestContext context, String schemaRepository, String schema) { if (!(message instanceof HttpMessage)) { return; } validate(message, context, - new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) - .build()); + new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) + .build()); } + + private record ValidationReportData(OperationPathAdapter operationPathAdapter, String type, + ValidationReport report) { + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java index 832f063b6f..aa029ccd3f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContext.java @@ -16,14 +16,15 @@ package org.citrusframework.openapi.validation; -import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.report.MessageResolver; import com.atlassian.oai.validator.schema.SchemaValidator; import com.atlassian.oai.validator.schema.SwaggerV20Library; import io.swagger.v3.oas.models.OpenAPI; +import jakarta.annotation.Nonnull; + +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; /** * Represents the context for OpenAPI validation, providing configuration and validators for request and response validation. @@ -50,14 +51,14 @@ public OpenAPI getSwaggerOpenApi() { return openApi; } - public synchronized OpenApiInteractionValidator getOpenApiInteractionValidator() { + public synchronized @Nonnull OpenApiInteractionValidator getOpenApiInteractionValidator() { if (openApiInteractionValidator == null) { openApiInteractionValidator = new OpenApiInteractionValidator.Builder().withApi(openApi).build(); } return openApiInteractionValidator; } - public synchronized SchemaValidator getSchemaValidator() { + public synchronized @Nonnull SchemaValidator getSchemaValidator() { if (schemaValidator == null) { schemaValidator = new SchemaValidator(openApi, new MessageResolver(), SwaggerV20Library::schemaFactory); } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java index a541c3948f..349cdf25c9 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java @@ -21,19 +21,22 @@ import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.parser.core.models.ParseOptions; import jakarta.annotation.Nonnull; -import java.net.URL; -import java.util.Collections; import org.citrusframework.openapi.OpenApiResourceLoader; import org.citrusframework.spi.Resource; +import java.net.URL; + +import static java.util.Collections.emptyList; + /** - * Utility class for creation of {@link OpenApiValidationContext}. + * Utility class for creation of an {@link OpenApiValidationContext}. */ -public abstract class OpenApiValidationContextLoader { +public final class OpenApiValidationContextLoader { private OpenApiValidationContextLoader() { // Static access only } + /** * Creates an OpenApiValidationContext from a secured OpenAPI web resource. * @@ -41,7 +44,7 @@ private OpenApiValidationContextLoader() { * @return the OpenApiValidationContext */ public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), Collections.emptyList(), defaultParseOptions())); + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), emptyList(), defaultParseOptions())); } /** @@ -51,17 +54,17 @@ public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) * @return the OpenApiValidationContext */ public static OpenApiValidationContext fromWebResource(@Nonnull URL url) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), Collections.emptyList(), defaultParseOptions())); + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), emptyList(), defaultParseOptions())); } /** - * Creates an OpenApiValidationContext from an OpenAPI file. + * Creates an OpenApiValidationContext from an OpenAPI file. * * @param resource the file resource containing the OpenAPI specification * @return the OpenApiValidationContext */ public static OpenApiValidationContext fromFile(@Nonnull Resource resource) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), Collections.emptyList(), defaultParseOptions())); + return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), emptyList(), defaultParseOptions())); } private static OpenApiValidationContext createValidationContext(OpenAPI openApi) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java index 61766421db..fe1532339a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidator.java @@ -29,7 +29,7 @@ protected OpenApiValidator(OpenApiSpecification openApiSpecification) { OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); if (openApiValidationContext != null) { openApiInteractionValidator = openApiSpecification.getOpenApiValidationContext() - .getOpenApiInteractionValidator(); + .getOpenApiInteractionValidator(); } else { openApiInteractionValidator = null; } @@ -44,8 +44,7 @@ protected OpenApiValidator(OpenApiSpecification openApiSpecification) { * @param report The report containing the error message * @return A string representation of all messages contained in the report */ - protected String constructErrorMessage(OperationPathAdapter operationPathAdapter, - ValidationReport report) { + protected String constructErrorMessage(OperationPathAdapter operationPathAdapter, ValidationReport report) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("OpenApi "); stringBuilder.append(getType()); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/ObjectFactory.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/ObjectFactory.java index 2f1bdbad34..ed36b5601f 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/ObjectFactory.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/ObjectFactory.java @@ -30,21 +30,18 @@ * type definitions, element declarations and model * groups. Factory methods for each of these are * provided in this class. - * */ @XmlRegistry public class ObjectFactory { /** * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.citrusframework.xml.actions - * */ public ObjectFactory() { } /** * Create an instance of {@link OpenApi } - * */ public OpenApi createOpenApi() { return new OpenApi(); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java index 41eed4a77e..01615e438b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java @@ -257,6 +257,7 @@ public void setReferenceResolver(ReferenceResolver referenceResolver) { /** * Converts current builder to client builder. + * * @return */ private OpenApiClientActionBuilder asClientBuilder() { @@ -270,6 +271,7 @@ private OpenApiClientActionBuilder asClientBuilder() { /** * Converts current builder to server builder. + * * @return */ private OpenApiServerActionBuilder asServerBuilder() { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java index 4a67110219..dc2f59e92b 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java @@ -232,6 +232,7 @@ public void setReferenceResolver(ReferenceResolver referenceResolver) { /** * Converts current builder to client builder. + * * @return */ private OpenApiClientActionBuilder asClientBuilder() { @@ -245,6 +246,7 @@ private OpenApiClientActionBuilder asClientBuilder() { /** * Converts current builder to server builder. + * * @return */ private OpenApiServerActionBuilder asServerBuilder() { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java index 2c15ea89c3..d42811ce18 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiMessageTypeTest.java @@ -1,9 +1,9 @@ package org.citrusframework.openapi; -import static org.testng.Assert.assertEquals; - import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + public class OpenApiMessageTypeTest { @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index 15f6fa113e..cae6358684 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Optional; +import static java.util.Collections.singletonList; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -41,8 +42,7 @@ public class OpenApiRepositoryTest { public void shouldInitializeOpenApiRepository() { OpenApiRepository openApiRepository = new OpenApiRepository(); openApiRepository.setRootContextPath(ROOT); - openApiRepository.setLocations( - List.of("org/citrusframework/openapi/petstore/petstore**.json")); + openApiRepository.setLocations(singletonList("org/citrusframework/openapi/petstore/petstore**.json")); openApiRepository.initialize(); List openApiSpecifications = openApiRepository.getOpenApiSpecifications(); @@ -55,11 +55,11 @@ public void shouldInitializeOpenApiRepository() { assertEquals(openApiSpecifications.get(1).getRootContextPath(), ROOT); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); } @Test @@ -115,7 +115,5 @@ public void shouldSetAndProvideProperties() { assertFalse(openApiRepository.isRequestValidationEnabled()); assertEquals(openApiRepository.getRootContextPath(), "/otherRoot"); assertEquals(openApiRepository.getLocations(), List.of("l3", "l4")); - } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java index 41f612b495..2c3d3082d1 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -31,15 +31,11 @@ public class OpenApiSettingsTest { - private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); - private static final boolean REQUEST_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isRequestValidationEnabledGlobally(); - private static final boolean RESPONSE_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isResponseValidationEnabledGlobally(); - private static final boolean VALIDATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isValidateOptionalFieldsGlobally(); - private static final boolean GENERATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isGenerateOptionalFieldsGlobally(); + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeMethod public void beforeMethod() { @@ -107,7 +103,7 @@ public void testRequestValidationDisabledByEnvVar() throws Exception { } @Test - public void testRequestValidationEnabledByDefault() { + public void testRequestValidationEnabledByDefault() { assertTrue(OpenApiSettings.isRequestValidationEnabledGlobally()); } @@ -140,7 +136,7 @@ public void testResponseValidationDisabledByEnvVar() throws Exception { } @Test - public void testResponseValidationEnabledByDefault() { + public void testResponseValidationEnabledByDefault() { assertTrue(OpenApiSettings.isResponseValidationEnabledGlobally()); } @@ -173,7 +169,7 @@ public void testGenerateOptionalFieldsDisabledByEnvVar() throws Exception { } @Test - public void testGenerateOptionalFieldsEnabledByDefault() { + public void testGenerateOptionalFieldsEnabledByDefault() { assertTrue(OpenApiSettings.isGenerateOptionalFieldsGlobally()); } @@ -206,7 +202,7 @@ public void testValidateOptionalFieldsDisabledByEnvVar() throws Exception { } @Test - public void testValidateOptionalFieldsEnabledByDefault() { + public void testValidateOptionalFieldsEnabledByDefault() { assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java deleted file mode 100644 index 65c1433bc4..0000000000 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationAdapterTest.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.citrusframework.openapi; - -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; - -public class OpenApiSpecificationAdapterTest { - - @Mock - private OpenApiSpecification openApiSpecificationMock; - - @Mock - private Object entityMock; - - private OpenApiSpecificationAdapter openApiSpecificationAdapter; - - private AutoCloseable mockCloseable; - - @BeforeMethod - public void setUp() { - mockCloseable = MockitoAnnotations.openMocks(this); - openApiSpecificationAdapter = new OpenApiSpecificationAdapter<>(openApiSpecificationMock, entityMock); - } - - @AfterMethod - public void tearDown() throws Exception { - mockCloseable.close(); - } - - @Test - public void shouldProvideOpenApiSpecification() { - OpenApiSpecification specification = openApiSpecificationAdapter.openApiSpecification(); - assertNotNull(specification, "OpenApiSpecification should not be null"); - assertEquals(specification, openApiSpecificationMock, "OpenApiSpecification should match the mock"); - } - - @Test - public void shouldProvideEntity() { - Object entity = openApiSpecificationAdapter.entity(); - assertNotNull(entity, "Entity should not be null"); - assertEquals(entity, entityMock, "Entity should match the mock"); - } - -} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index bbe892c193..39b873410e 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -81,15 +81,49 @@ public class OpenApiSpecificationTest { @InjectMocks private OpenApiSpecification openApiSpecification; + @DataProvider(name = "protocollDataProvider") + public static Object[][] protocolls() { + return new Object[][]{{PING_API_HTTP_URL_STRING}, {PING_API_HTTPS_URL_STRING}}; + } + + @DataProvider(name = "lazyInitializationDataprovider") + public static Object[][] specSources() { + return new Object[][]{ + {null, "classpath:org/citrusframework/openapi/ping/ping-api.yaml"}, + {null, PING_API_HTTP_URL_STRING}, + {null, PING_API_HTTPS_URL_STRING}, + {null, "/ping-api.yaml"}, + {"http://org.citrus.sample", "/ping-api.yaml"} + }; + } + + private static URL mockUrlConnection(String urlString) { + try { + HttpsURLConnection httpsURLConnectionMock = mock(); + when(httpsURLConnectionMock.getResponseCode()).thenReturn(200); + when(httpsURLConnectionMock.getInputStream()).thenAnswer( + invocation -> new ByteArrayInputStream(PING_API_STRING.getBytes( + StandardCharsets.UTF_8))); + + URL urlMock = mock(); + when(urlMock.getProtocol()).thenReturn(urlString.substring(0, urlString.indexOf(":"))); + when(urlMock.toString()).thenReturn(urlString); + when(urlMock.openConnection()).thenReturn(httpsURLConnectionMock); + return urlMock; + } catch (Exception e) { + throw new CitrusRuntimeException("Unable to mock spec url!", e); + } + } + @BeforeClass public void beforeClass() throws IOException { PING_API_STRING = readToString( - new ClasspathResource( - "classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + new ClasspathResource( + "classpath:org/citrusframework/openapi/ping/ping-api.yaml")); } + @BeforeMethod public void setUp() { - mockCloseable = MockitoAnnotations.openMocks(this); testContextMock.setReferenceResolver(referenceResolverMock); @@ -100,11 +134,6 @@ public void tearDown() throws Exception { mockCloseable.close(); } - @DataProvider(name = "protocollDataProvider") - public static Object[][] protocolls() { - return new Object[][] {{PING_API_HTTP_URL_STRING}, {PING_API_HTTPS_URL_STRING}}; - } - @Test(dataProvider = "protocollDataProvider") public void shouldInitializeFromUrl(String urlString) { // Given @@ -122,16 +151,16 @@ private void assertPingApi(OpenApiSpecification specification) { assertNotNull(specification); assertNotNull(specification.getOpenApiValidationContext()); Optional pingOperationPathAdapter = specification.getOperation( - PING_OPERATION_ID, - testContextMock); + PING_OPERATION_ID, + testContextMock); assertTrue(pingOperationPathAdapter.isPresent()); assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); assertNull(pingOperationPathAdapter.get().contextPath()); assertEquals(pingOperationPathAdapter.get().fullPath(), "/ping/{id}"); Optional pongOperationPathAdapter = specification.getOperation( - PONG_OPERATION_ID, - testContextMock); + PONG_OPERATION_ID, + testContextMock); assertTrue(pongOperationPathAdapter.isPresent()); assertEquals(pongOperationPathAdapter.get().apiPath(), "/pong/{id}"); assertNull(pongOperationPathAdapter.get().contextPath()); @@ -141,7 +170,7 @@ private void assertPingApi(OpenApiSpecification specification) { @Test public void shouldInitializeFromResource() { // Given - Resource resource= new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml"); + Resource resource = new ClasspathResource("classpath:org/citrusframework/openapi/ping/ping-api.yaml"); // When OpenApiSpecification specification = OpenApiSpecification.from(resource); @@ -172,7 +201,7 @@ public void shouldReturnOpenApiDocWhenInitialized() { public void shouldReturnEmptyOptionalWhenOperationIdIsNull() { // When Optional result = openApiSpecification.getOperation(null, - testContextMock); + testContextMock); // Then assertTrue(result.isEmpty()); @@ -190,32 +219,21 @@ public void shouldReturnOperationWhenExists() { @Test public void shouldInitializeDocumentWhenRequestingOperation() { // Given/When - when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(answer-> - answer.getArgument(0) + when(testContextMock.replaceDynamicContentInString(isA(String.class))).thenAnswer(answer -> + answer.getArgument(0) ); OpenApiSpecification specification = OpenApiSpecification.from("classpath:org/citrusframework/openapi/ping/ping-api.yaml"); // Then Optional pingOperationPathAdapter = specification.getOperation( - PING_OPERATION_ID, - testContextMock); + PING_OPERATION_ID, + testContextMock); assertTrue(pingOperationPathAdapter.isPresent()); assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); assertNull(pingOperationPathAdapter.get().contextPath()); assertEquals(pingOperationPathAdapter.get().fullPath(), "/ping/{id}"); } - @DataProvider(name = "lazyInitializationDataprovider") - public static Object[][] specSources() { - return new Object[][]{ - {null, "classpath:org/citrusframework/openapi/ping/ping-api.yaml"}, - {null, PING_API_HTTP_URL_STRING}, - {null, PING_API_HTTPS_URL_STRING}, - {null, "/ping-api.yaml"}, - {"http://org.citrus.sample", "/ping-api.yaml"} - }; - } - @Test(dataProvider = "lazyInitializationDataprovider") public void shouldDisableEnableRequestValidationWhenSet(String requestUrl, String specSource) { @@ -262,24 +280,6 @@ URL toSpecUrl(String resolvedSpecUrl) { } - private static URL mockUrlConnection(String urlString) { - try { - HttpsURLConnection httpsURLConnectionMock = mock(); - when(httpsURLConnectionMock.getResponseCode()).thenReturn(200); - when(httpsURLConnectionMock.getInputStream()).thenAnswer( - invocation -> new ByteArrayInputStream(PING_API_STRING.getBytes( - StandardCharsets.UTF_8))); - - URL urlMock = mock(); - when(urlMock.getProtocol()).thenReturn(urlString.substring(0,urlString.indexOf(":"))); - when(urlMock.toString()).thenReturn(urlString); - when(urlMock.openConnection()).thenReturn(httpsURLConnectionMock); - return urlMock; - } catch (Exception e) { - throw new CitrusRuntimeException("Unable to mock spec url!", e); - } - } - @Test public void shouldDisableEnableResponseValidationWhenSet() { // Given @@ -302,13 +302,13 @@ public void shouldDisableEnableResponseValidationWhenSet() { } - @Test - public void shouldAddAlias() { - String alias = "alias1"; - openApiSpecification.addAlias(alias); + @Test + public void shouldAddAlias() { + String alias = "alias1"; + openApiSpecification.addAlias(alias); - assertTrue(openApiSpecification.getAliases().contains(alias)); - } + assertTrue(openApiSpecification.getAliases().contains(alias)); + } @Test public void shouldReturnSpecUrl() { @@ -333,16 +333,16 @@ public void shouldSetRootContextPathAndReinitialize() { specification.setRootContextPath("/root"); Optional pingOperationPathAdapter = specification.getOperation( - PING_OPERATION_ID, - testContextMock); + PING_OPERATION_ID, + testContextMock); assertTrue(pingOperationPathAdapter.isPresent()); assertEquals(pingOperationPathAdapter.get().apiPath(), "/ping/{id}"); assertEquals(pingOperationPathAdapter.get().contextPath(), "/root"); assertEquals(pingOperationPathAdapter.get().fullPath(), "/root/ping/{id}"); Optional pongOperationPathAdapter = specification.getOperation( - PONG_OPERATION_ID, - testContextMock); + PONG_OPERATION_ID, + testContextMock); assertTrue(pongOperationPathAdapter.isPresent()); assertEquals(pongOperationPathAdapter.get().apiPath(), "/pong/{id}"); assertEquals(pongOperationPathAdapter.get().contextPath(), "/root"); @@ -365,7 +365,6 @@ public void shouldSeAndProvideProperties() { assertFalse(openApiSpecification.isValidateOptionalFields()); assertFalse(openApiSpecification.isGenerateOptionalFields()); - } @Test @@ -381,6 +380,5 @@ public void shouldReturnSpecUrlInAbsenceOfRequestUrl() { assertEquals(openApiSpecification.getSpecUrl(), "/ping-api.yaml"); assertEquals(openApiSpecification.getRequestUrl(), "http://or.citrus.sample"); - } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java index a0e89a4e6e..3f8ff4f9d8 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java @@ -16,44 +16,43 @@ package org.citrusframework.openapi; -import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DOUBLE; -import static org.citrusframework.openapi.OpenApiConstants.FORMAT_FLOAT; -import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT32; -import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT64; -import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_NUMBER; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - import com.atlassian.oai.validator.report.ValidationReport; import com.atlassian.oai.validator.report.ValidationReport.Message; import com.atlassian.oai.validator.schema.SchemaValidator; -import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import io.swagger.v3.oas.models.media.Schema; -import java.io.IOException; -import java.math.BigDecimal; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.citrusframework.context.TestContext; import org.citrusframework.functions.DefaultFunctionRegistry; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.spi.Resources; -import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DOUBLE; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_FLOAT; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT32; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_INT64; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_NUMBER; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + public class OpenApiTestDataGeneratorTest { private static final TestContext testContext = new TestContext(); @@ -67,13 +66,136 @@ public static void beforeClass() { testContext.setFunctionRegistry(new DefaultFunctionRegistry()); openApiSpecification = OpenApiSpecification.from( - Resources.fromClasspath("org/citrusframework/openapi/ping/ping-api.yaml")); + Resources.fromClasspath("org/citrusframework/openapi/ping/ping-api.yaml")); schemaValidator = openApiSpecification.getOpenApiValidationContext() - .getSchemaValidator(); + .getSchemaValidator(); + } + + @DataProvider(name = "testRandomNumber") + public static Object[][] testRandomNumber() { + return new Object[][]{ + {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, null, 0, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 11, 0, 12, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 12, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 13, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 14, 0, 14, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 15, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 16, -16, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 17, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 18, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 19, -20, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT32, 20, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT32, 21, 21, 21, false, false}, + + {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, null, 0, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 11, 0, 12, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 12, null, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 13, 0, 100, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 14, 0, 14, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 15, -100, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 16, -16, 0, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 17, 0, 100, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 18, -100, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 19, -20, 0, true, true}, + {TYPE_INTEGER, FORMAT_INT64, 20, 0, null, false, false}, + {TYPE_INTEGER, FORMAT_INT64, 21, 21, 21, false, false}, + + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, null, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 11.123f, 0, 13, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 12.123f, null, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 13.123f, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 14.123f, 0, 14, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 15.123f, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 16.123f, -16, 0, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 17.123f, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 18.123f, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 19.123f, -21, 0, true, true}, + {TYPE_NUMBER, FORMAT_FLOAT, 20.123f, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_FLOAT, 21.123f, 21.122f, 21.124f, false, false}, + + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, null, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 11.123d, 0, 13, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 12.123d, null, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 13.123d, 0, 100, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 14.123d, 0, 14, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 15.123d, -100, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 16.123d, -16, 0, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 17.123d, 0, 100, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 18.123d, -100, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 19.123d, -21, 0, true, true}, + {TYPE_NUMBER, FORMAT_DOUBLE, 20.123d, 0, null, false, false}, + {TYPE_NUMBER, FORMAT_DOUBLE, 21.123d, 21.122d, 21.124d, false, false}, + }; + } + + @DataProvider(name = "testPingApiSchemas") + public static Object[][] testPingApiSchemas() { + return new Object[][]{ + // Composites currently do not work properly - validation fails + //{"AnyOfType"}, + //{"AllOfType"}, + //{"PingRespType"}, + {"OneOfType"}, + {"StringsType"}, + {"DatesType"}, + {"NumbersType"}, + {"PingReqType"}, + {"Detail1"}, + {"Detail2"}, + {"BooleanType"}, + {"EnumType"}, + {"NestedType"}, + {"MultipleOfType"}, + {"SimpleArrayType"}, + {"ComplexArrayType"}, + {"ArrayOfArraysType"}, + {"NullableType"}, + {"DefaultValueType"}, + }; } @Test - void testUuidFormat() { + public void testUuidFormat() { Oas30Schema stringSchema = new Oas30Schema(); stringSchema.type = TYPE_STRING; stringSchema.format = FORMAT_UUID; @@ -81,111 +203,19 @@ void testUuidFormat() { String uuidRandomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema); String finalUuidRandomValue = testContext.replaceDynamicContentInString(uuidRandomValue); Pattern uuidPattern = Pattern.compile( - "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); + "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); assertTrue(uuidPattern.matcher(finalUuidRandomValue).matches()); } - @DataProvider(name = "testRandomNumber") - public static Object[][] testRandomNumber() { - return new Object[][]{ - {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, true, true}, - {TYPE_INTEGER, FORMAT_INT32, null, null, null, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, 0, 2, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, 0, 100, true, true}, - {TYPE_INTEGER, FORMAT_INT32, null, -100, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT32, null, -2, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT32, null, 0, null, false, false}, - {TYPE_INTEGER, FORMAT_INT32, null, 0, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 11, 0, 12, true, true}, - {TYPE_INTEGER, FORMAT_INT32, 12, null, null, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 13, 0, 100, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 14, 0, 14, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 15, -100, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 16, -16, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 17, 0, 100, true, true}, - {TYPE_INTEGER, FORMAT_INT32, 18, -100, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT32, 19, -20, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT32, 20, 0, null, false, false}, - {TYPE_INTEGER, FORMAT_INT32, 21, 21, 21, false, false}, - - {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, true, true}, - {TYPE_INTEGER, FORMAT_INT64, null, null, null, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, 0, 2, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, 0, 100, true, true}, - {TYPE_INTEGER, FORMAT_INT64, null, -100, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT64, null, -2, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT64, null, 0, null, false, false}, - {TYPE_INTEGER, FORMAT_INT64, null, 0, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 11, 0, 12, true, true}, - {TYPE_INTEGER, FORMAT_INT64, 12, null, null, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 13, 0, 100, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 14, 0, 14, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 15, -100, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 16, -16, 0, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 17, 0, 100, true, true}, - {TYPE_INTEGER, FORMAT_INT64, 18, -100, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT64, 19, -20, 0, true, true}, - {TYPE_INTEGER, FORMAT_INT64, 20, 0, null, false, false}, - {TYPE_INTEGER, FORMAT_INT64, 21, 21, 21, false, false}, - - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, null, null, null, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 2, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 100, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, null, -100, 0, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, null, -2, 0, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, null, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, null, 0, 0, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 11.123f, 0, 13, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, 12.123f, null, null, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 13.123f, 0, 100, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 14.123f, 0, 14, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 15.123f, -100, 0, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 16.123f, -16, 0, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 17.123f, 0, 100, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, 18.123f, -100, 0, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, 19.123f, -21, 0, true, true}, - {TYPE_NUMBER, FORMAT_FLOAT, 20.123f, 0, null, false, false}, - {TYPE_NUMBER, FORMAT_FLOAT, 21.123f, 21.122f, 21.124f, false, false}, - - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, null, null, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 2, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 100, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, -100, 0, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, -2, 0, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, null, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, null, 0, 0, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 11.123d, 0, 13, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, 12.123d, null, null, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 13.123d, 0, 100, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 14.123d, 0, 14, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 15.123d, -100, 0, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 16.123d, -16, 0, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 17.123d, 0, 100, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, 18.123d, -100, 0, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, 19.123d, -21, 0, true, true}, - {TYPE_NUMBER, FORMAT_DOUBLE, 20.123d, 0, null, false, false}, - {TYPE_NUMBER, FORMAT_DOUBLE, 21.123d, 21.122d, 21.124d, false, false}, - }; - } - @Test(dataProvider = "testRandomNumber") - void testRandomNumber(String type, String format, Number multipleOf, Number minimum, - Number maximum, boolean exclusiveMinimum, boolean exclusiveMaximum) { + public void testRandomNumber(String type, + String format, + Number multipleOf, + Number minimum, + Number maximum, + boolean exclusiveMinimum, + boolean exclusiveMaximum) { Oas30Schema testSchema = new Oas30Schema(); testSchema.type = type; testSchema.format = format; @@ -195,54 +225,50 @@ void testRandomNumber(String type, String format, Number multipleOf, Number mini testSchema.exclusiveMinimum = exclusiveMinimum; testSchema.exclusiveMaximum = exclusiveMaximum; - try { - for (int i = 0; i < 1000; i++) { - String randomValue = OpenApiTestDataGenerator.createOutboundPayload( + for (int i = 0; i < 1000; i++) { + String randomValue = OpenApiTestDataGenerator.createOutboundPayload( testSchema, openApiSpecification); - String finalRandomValue = testContext.resolveDynamicValue(randomValue); - BigDecimal value = new BigDecimal(finalRandomValue); + String finalRandomValue = testContext.resolveDynamicValue(randomValue); + BigDecimal value = new BigDecimal(finalRandomValue); - if (multipleOf != null) { - BigDecimal remainder = value.remainder(new BigDecimal(multipleOf.toString())); + if (multipleOf != null) { + BigDecimal remainder = value.remainder(new BigDecimal(multipleOf.toString())); - assertEquals( + assertEquals( remainder.compareTo(BigDecimal.ZERO), 0, "Expected %s to be a multiple of %s! Remainder is %s".formatted( - finalRandomValue, multipleOf, - remainder)); - } + finalRandomValue, multipleOf, + remainder)); + } - if (maximum != null) { - if (exclusiveMaximum) { - assertTrue(value.doubleValue() < testSchema.maximum.doubleValue(), + if (maximum != null) { + if (exclusiveMaximum) { + assertTrue(value.doubleValue() < testSchema.maximum.doubleValue(), "Expected %s to be lower than %s!".formatted( - finalRandomValue, maximum)); - } else { - assertTrue(value.doubleValue() <= testSchema.maximum.doubleValue(), + finalRandomValue, maximum)); + } else { + assertTrue(value.doubleValue() <= testSchema.maximum.doubleValue(), "Expected %s to be lower or equal than %s!".formatted( - finalRandomValue, maximum)); - } + finalRandomValue, maximum)); } + } - if (minimum != null) { - if (exclusiveMinimum) { - assertTrue(value.doubleValue() > testSchema.minimum.doubleValue(), + if (minimum != null) { + if (exclusiveMinimum) { + assertTrue(value.doubleValue() > testSchema.minimum.doubleValue(), "Expected %s to be larger than %s!".formatted( - finalRandomValue, minimum)); - } else { - assertTrue(value.doubleValue() >= testSchema.minimum.doubleValue(), + finalRandomValue, minimum)); + } else { + assertTrue(value.doubleValue() >= testSchema.minimum.doubleValue(), "Expected %s to be larger or equal than %s!".formatted( - finalRandomValue, minimum)); - } + finalRandomValue, minimum)); } } - } catch (Exception e) { - Assert.fail("Creation of multiple float threw an exception: " + e.getMessage(), e); } } @Test - void testPattern() { + public void testPattern() { Oas30Schema stringSchema = new Oas30Schema(); stringSchema.type = TYPE_STRING; @@ -251,77 +277,42 @@ void testPattern() { String randomValue = OpenApiTestDataGenerator.createRandomValueExpression(stringSchema); String finalRandomValue = testContext.replaceDynamicContentInString(randomValue); - assertTrue(finalRandomValue.matches(exp), - "Value '%s' does not match expression '%s'".formatted(finalRandomValue, exp)); - } - - @DataProvider(name = "testPingApiSchemas") - public static Object[][] testPingApiSchemas() { - return new Object[][]{ - - // Composites currently do not work properly - validation fails - //{"AnyOfType"}, - //{"AllOfType"}, - //{"PingRespType"}, - {"OneOfType"}, - {"StringsType"}, - {"DatesType"}, - {"NumbersType"}, - {"PingReqType"}, - {"Detail1"}, - {"Detail2"}, - {"BooleanType"}, - {"EnumType"}, - {"NestedType"}, - {"MultipleOfType"}, - {"SimpleArrayType"}, - {"ComplexArrayType"}, - {"ArrayOfArraysType"}, - {"NullableType"}, - {"DefaultValueType"}, - }; + assertTrue(finalRandomValue.matches(exp), "Value '%s' does not match expression '%s'".formatted(finalRandomValue, exp)); } - @Test(dataProvider = "testPingApiSchemas") - void testPingApiSchemas(String schemaType) throws IOException { - + public void testPingApiSchemas(String schemaType) throws IOException { OasSchema schema = OasModelHelper.getSchemaDefinitions( - openApiSpecification.getOpenApiDoc(null)).get(schemaType); + openApiSpecification.getOpenApiDoc(null)).get(schemaType); Schema swaggerValidationSchema = openApiSpecification.getOpenApiValidationContext() - .getSwaggerOpenApi().getComponents().getSchemas().get(schemaType); + .getSwaggerOpenApi().getComponents().getSchemas().get(schemaType); assertNotNull(schema); - for (int i=0;i<100;i++) { - - String randomValue = OpenApiTestDataGenerator.createOutboundPayload(schema, - openApiSpecification); + for (int i = 0; i < 100; i++) { + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(schema, openApiSpecification); assertNotNull(randomValue); String finalJsonAsText = testContext.replaceDynamicContentInString(randomValue); - try { - JsonNode valueNode = new ObjectMapper().readTree( + + JsonNode valueNode = new ObjectMapper().readTree( testContext.replaceDynamicContentInString(finalJsonAsText)); - ValidationReport validationReport = schemaValidator.validate(() -> valueNode, + ValidationReport validationReport = schemaValidator.validate(() -> valueNode, swaggerValidationSchema, null); - String message = """ - Json is invalid according to schema. - Message: %s - Report: %s - """.formatted(finalJsonAsText, validationReport.getMessages().stream().map( + String message = """ + Json is invalid according to schema. + Message: %s + Report: %s + """.formatted(finalJsonAsText, validationReport.getMessages().stream().map( Message::getMessage).collect(Collectors.joining("\n"))); - assertFalse(validationReport.hasErrors(), message); - } catch (JsonParseException e) { - Assert.fail("Unable to read generated schema to json: "+finalJsonAsText); - } + assertFalse(validationReport.hasErrors(), message); } } @Test - void testArray() { + public void testArray() { Oas30Schema arraySchema = new Oas30Schema(); arraySchema.type = TYPE_ARRAY; @@ -333,15 +324,14 @@ void testArray() { arraySchema.items = stringSchema; for (int i = 0; i < 10; i++) { - String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, - openApiSpecification); + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification); int nElements = StringUtils.countMatches(randomValue, "citrus:randomString"); assertTrue(nElements > 0); } } @Test - void testArrayMinItems() { + public void testArrayMinItems() { Oas30Schema arraySchema = new Oas30Schema(); arraySchema.type = TYPE_ARRAY; arraySchema.minItems = 5; @@ -354,15 +344,14 @@ void testArrayMinItems() { arraySchema.items = stringSchema; for (int i = 0; i < 10; i++) { - String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, - openApiSpecification); + String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification); int nElements = StringUtils.countMatches(randomValue, "citrus:randomString(15)"); assertTrue(nElements <= 5); } } @Test - void testArrayMaxItems() { + public void testArrayMaxItems() { Oas30Schema arraySchema = new Oas30Schema(); arraySchema.type = TYPE_ARRAY; arraySchema.minItems = 2; @@ -377,8 +366,7 @@ void testArrayMaxItems() { Pattern pattern = Pattern.compile("citrus:randomString\\(1[0-5],MIXED,true,10\\)"); for (int i = 0; i < 100; i++) { - String randomArrayValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, - openApiSpecification); + String randomArrayValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification); Matcher matcher = pattern.matcher(randomArrayValue); int matches = 0; @@ -387,9 +375,8 @@ void testArrayMaxItems() { } assertTrue(2 <= matches && matches <= 5, - "Expected random array string with number of elements between 2 and 4 but found %s: %s".formatted( - matches, randomArrayValue)); + "Expected random array string with number of elements between 2 and 4 but found %s: %s".formatted( + matches, randomArrayValue)); } } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java index 3461d46b60..29ba5f4dbb 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestValidationDataGeneratorTest.java @@ -16,63 +16,24 @@ package org.citrusframework.openapi; -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationExpression; -import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationRegex; -import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertEquals; - import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema; import io.apicurio.datamodels.openapi.v2.models.Oas20Schema.Oas20AllOfSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.HashMap; -import java.util.List; -import java.util.regex.Pattern; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -public class OpenApiTestValidationDataGeneratorTest { - - @Test - public void anyOfIsIgnoredForOas3() { - - Oas30Schema anyOfSchema = new Oas30Schema(); - anyOfSchema.anyOf = List.of(new Oas30Schema(), new Oas30Schema()); - - assertEquals(createValidationExpression( - anyOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); - } - - @Test - public void allOfIsIgnoredForOas3() { - - Oas30Schema allOfSchema = new Oas30Schema(); - allOfSchema.allOf = List.of(new Oas30Schema(), new Oas30Schema()); - - assertEquals(createValidationExpression( - allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); - } - - @Test - public void oneOfIsIgnoredForOas3() { - - Oas30Schema oneOfSchema = new Oas30Schema(); - oneOfSchema.oneOf = List.of(new Oas30Schema(), new Oas30Schema()); - - assertEquals(createValidationExpression( - oneOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); - } - - @Test - public void allOfIsIgnoredForOas2() { +import java.util.HashMap; +import java.util.List; +import java.util.regex.Pattern; - Oas20AllOfSchema allOfSchema = new Oas20AllOfSchema(); - allOfSchema.allOf = List.of(new Oas20Schema(), new Oas20Schema()); +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationExpression; +import static org.citrusframework.openapi.OpenApiTestValidationDataGenerator.createValidationRegex; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertEquals; - assertEquals(createValidationExpression( - allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); - } +public class OpenApiTestValidationDataGeneratorTest { @DataProvider(name = "createValidationRegexDataProvider") public static Object[][] createValidationRegexDataProvider() { @@ -107,49 +68,85 @@ public static Object[][] createValidationRegexDataProvider() { Oas30Schema enumSchema = new Oas30Schema(); enumSchema.type = OpenApiConstants.TYPE_STRING; - enumSchema.enum_ = List.of("A","B","C"); + enumSchema.enum_ = List.of("A", "B", "C"); return new Object[][]{ - {stringSchema, "xyz", true}, - {uuidSchema, "123e4567-e89b-12d3-a456-426614174000", true}, - {uuidSchema, "123e4567-e89b-12d3-a456-42661417400", false}, - {dateSchema, "2023-05-15", true}, - {dateSchema, "2023-15-15", false}, - {dateTimeSchema, "2023-05-15T10:15:30Z", true}, - {dateTimeSchema, "2023-05-15T25:15:30Z", false}, - {integerSchema, "2023", true}, - {integerSchema, "2023.05", false}, - {numberSchema, "2023", true}, - {numberSchema, "2023.xx", false}, - {booleanSchema, "true", true}, - {booleanSchema, "false", true}, - {booleanSchema, "yes", false}, - {booleanSchema, "no", false}, - {booleanSchema, "yes", false}, - {booleanSchema, "no", false}, - {regexSchema, "156", true}, - {regexSchema, "651", false}, - {enumSchema, "A", true}, - {enumSchema, "B", true}, - {enumSchema, "C", true}, - {enumSchema, "a", false}, - {enumSchema, "D", false}, + {stringSchema, "xyz", true}, + {uuidSchema, "123e4567-e89b-12d3-a456-426614174000", true}, + {uuidSchema, "123e4567-e89b-12d3-a456-42661417400", false}, + {dateSchema, "2023-05-15", true}, + {dateSchema, "2023-15-15", false}, + {dateTimeSchema, "2023-05-15T10:15:30Z", true}, + {dateTimeSchema, "2023-05-15T25:15:30Z", false}, + {integerSchema, "2023", true}, + {integerSchema, "2023.05", false}, + {numberSchema, "2023", true}, + {numberSchema, "2023.xx", false}, + {booleanSchema, "true", true}, + {booleanSchema, "false", true}, + {booleanSchema, "yes", false}, + {booleanSchema, "no", false}, + {booleanSchema, "yes", false}, + {booleanSchema, "no", false}, + {regexSchema, "156", true}, + {regexSchema, "651", false}, + {enumSchema, "A", true}, + {enumSchema, "B", true}, + {enumSchema, "C", true}, + {enumSchema, "a", false}, + {enumSchema, "D", false}, }; } + @Test + public void anyOfIsIgnoredForOas3() { + Oas30Schema anyOfSchema = new Oas30Schema(); + anyOfSchema.anyOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + anyOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void allOfIsIgnoredForOas3() { + Oas30Schema allOfSchema = new Oas30Schema(); + allOfSchema.allOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void oneOfIsIgnoredForOas3() { + Oas30Schema oneOfSchema = new Oas30Schema(); + oneOfSchema.oneOf = List.of(new Oas30Schema(), new Oas30Schema()); + + assertEquals(createValidationExpression( + oneOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + + @Test + public void allOfIsIgnoredForOas2() { + Oas20AllOfSchema allOfSchema = new Oas20AllOfSchema(); + allOfSchema.allOf = List.of(new Oas20Schema(), new Oas20Schema()); + + assertEquals(createValidationExpression( + allOfSchema, new HashMap<>(), true, mock()), "\"@ignore@\""); + } + @Test(dataProvider = "createValidationRegexDataProvider") - void createValidationRegex_shouldValidateRealDataCorrectly(OasSchema schema, String toValidate, boolean result) { + public void createValidationRegex_shouldValidateRealDataCorrectly(OasSchema schema, String toValidate, boolean result) { String regex = createValidationRegex(schema); assertThat(Pattern.matches(regex, toValidate)).isEqualTo(result); } @Test - void validationRegexOfNullIsEmpty() { + public void validationRegexOfNullIsEmpty() { assertThat(createValidationRegex(null)).isEmpty(); } @Test - void defaultvalidationRegexIsEmpty() { + public void defaultvalidationRegexIsEmpty() { Oas30Schema oas30Schema = new Oas30Schema(); oas30Schema.type = "xxxx"; assertThat(createValidationRegex(oas30Schema)).isEmpty(); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java index cc222f3f67..887237cbf8 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiUtilsTest.java @@ -16,6 +16,17 @@ package org.citrusframework.openapi; +import org.citrusframework.spi.ReferenceResolver; +import org.mockito.MockitoAnnotations; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Map; +import java.util.Set; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.citrusframework.openapi.util.OpenApiUtils.getKnownOpenApiAliases; import static org.citrusframework.openapi.util.OpenApiUtils.getMethodPath; import static org.mockito.Mockito.mock; @@ -23,15 +34,6 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.citrusframework.spi.ReferenceResolver; -import org.mockito.MockitoAnnotations; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class OpenApiUtilsTest { private AutoCloseable mockCloseable; @@ -80,14 +82,14 @@ public void testGetKnownOpenApiAliases() { OpenApiSpecification spec2 = mock(); when(resolver.resolveAll(OpenApiRepository.class)).thenReturn( - Map.of( - "repo1", repository1, - "repo2", repository2 - ) + Map.of( + "repo1", repository1, + "repo2", repository2 + ) ); - when(repository1.getOpenApiSpecifications()).thenReturn(List.of(spec1)); - when(repository2.getOpenApiSpecifications()).thenReturn(List.of(spec2)); + when(repository1.getOpenApiSpecifications()).thenReturn(singletonList(spec1)); + when(repository2.getOpenApiSpecifications()).thenReturn(singletonList(spec2)); when(spec1.getAliases()).thenReturn(Set.of("alias1", "alias2")); when(spec2.getAliases()).thenReturn(Set.of("alias3")); @@ -106,14 +108,14 @@ public void testGetKnownOpenApiAliasesNoAliases() { OpenApiRepository repository2 = mock(); when(resolver.resolveAll(OpenApiRepository.class)).thenReturn( - Map.of( - "repo1", repository1, - "repo2", repository2 - ) + Map.of( + "repo1", repository1, + "repo2", repository2 + ) ); - when(repository1.getOpenApiSpecifications()).thenReturn(List.of()); - when(repository2.getOpenApiSpecifications()).thenReturn(List.of()); + when(repository1.getOpenApiSpecifications()).thenReturn(emptyList()); + when(repository2.getOpenApiSpecifications()).thenReturn(emptyList()); // Call the method under test String result = getKnownOpenApiAliases(resolver); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java index 1cf06d73a0..e739fc9b65 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientActionBuilderTest.java @@ -1,12 +1,12 @@ package org.citrusframework.openapi.actions; -import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertNotNull; - import org.citrusframework.endpoint.Endpoint; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertNotNull; + public class OpenApiClientActionBuilderTest { private OpenApiClientActionBuilder fixture; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java index 856a39ce6f..f4ed6a3b05 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiPayloadBuilderTest.java @@ -3,10 +3,12 @@ import org.citrusframework.context.TestContext; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; -import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + public class OpenApiPayloadBuilderTest { private TestContext context; @@ -36,15 +38,15 @@ public void testBuildPayloadWithMultiValueMap() { Object payload = payloadBuilder.buildPayload(context); // Then - Assert.assertTrue(payload instanceof MultiValueMap); + assertTrue(payload instanceof MultiValueMap); MultiValueMap result = (MultiValueMap) payload; - - Assert.assertEquals(result.get("key1").get(0), "value1"); - Assert.assertEquals(result.get("key2").get(0), "Hello John, welcome!"); - Assert.assertEquals(result.get("key2").get(1), "Another John message"); - Assert.assertEquals(result.get("key3").get(0), "a"); - Assert.assertEquals(result.get("key3").get(1), "b"); - Assert.assertEquals(result.get("key3").get(2), "John"); + + assertEquals(result.get("key1").get(0), "value1"); + assertEquals(result.get("key2").get(0), "Hello John, welcome!"); + assertEquals(result.get("key2").get(1), "Another John message"); + assertEquals(result.get("key3").get(0), "a"); + assertEquals(result.get("key3").get(1), "b"); + assertEquals(result.get("key3").get(2), "John"); } @Test @@ -59,7 +61,7 @@ public void testBuildPayloadWithPlainObject() { Object payload = payloadBuilder.buildPayload(context); // Then - Assert.assertTrue(payload instanceof String); - Assert.assertEquals(payload, "This is a simple test"); + assertTrue(payload instanceof String); + assertEquals(payload, "This is a simple test"); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java index 86fcf00504..23e387ab17 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiServerActionBuilderTest.java @@ -1,13 +1,13 @@ package org.citrusframework.openapi.actions; -import static org.mockito.Mockito.mock; -import static org.testng.Assert.assertTrue; - import org.citrusframework.endpoint.Endpoint; import org.citrusframework.spi.AbstractReferenceResolverAwareTestActionBuilder; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertTrue; + public class OpenApiServerActionBuilderTest { private OpenApiServerActionBuilder fixture; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/AbstractGroovyActionDslTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/AbstractGroovyActionDslTest.java index b1c9bc7ad9..430d00ea25 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/AbstractGroovyActionDslTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/AbstractGroovyActionDslTest.java @@ -62,7 +62,7 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); - doAnswer(invocationOnMock-> { + doAnswer(invocationOnMock -> { context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); return null; }).when(citrusContext).addComponent(anyString(), any()); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index d9d06aabf3..811e29d354 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -47,17 +47,21 @@ import org.mockito.Mockito; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; -import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.io.IOException; import java.util.Map; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; public class OpenApiClientTest extends AbstractGroovyActionDslTest { @@ -72,13 +76,10 @@ public class OpenApiClientTest extends AbstractGroovyActionDslTest { private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; - - private HttpServer httpServer; - private HttpClient httpClient; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); - private final Queue responses = new ArrayBlockingQueue<>(6); + private HttpServer httpServer; + private HttpClient httpClient; @BeforeClass public void setupEndpoints() { @@ -138,39 +139,39 @@ public void shouldLoadOpenApiClientActions() { ], "status": "available" } - """).status(HttpStatus.OK).contentType("application/json")); + """).status(HttpStatus.OK).contentType(APPLICATION_JSON_VALUE)); responses.add(new HttpMessage().status(HttpStatus.CREATED)); testLoader.load(); TestCase result = testLoader.getTestCase(); - Assert.assertEquals(result.getName(), "OpenApiClientTest"); - Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); - Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); - Assert.assertEquals(result.getActionCount(), 4L); - Assert.assertEquals(result.getTestAction(0).getClass(), SendMessageAction.class); - Assert.assertEquals(result.getTestAction(0).getName(), "openapi:send-request"); + assertEquals(result.getName(), "OpenApiClientTest"); + assertEquals(result.getMetaInfo().getAuthor(), "Christoph"); + assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL); + assertEquals(result.getActionCount(), 4L); + assertEquals(result.getTestAction(0).getClass(), SendMessageAction.class); + assertEquals(result.getTestAction(0).getName(), "openapi:send-request"); - Assert.assertEquals(result.getTestAction(1).getClass(), ReceiveMessageAction.class); - Assert.assertEquals(result.getTestAction(1).getName(), "openapi:receive-response"); + assertEquals(result.getTestAction(1).getClass(), ReceiveMessageAction.class); + assertEquals(result.getTestAction(1).getName(), "openapi:receive-response"); int actionIndex = 0; SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); - Assert.assertFalse(sendMessageAction.isForkMode()); - Assert.assertTrue(sendMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet/${petId}"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet/${petId}"); - Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); - Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); - Assert.assertEquals(sendMessageAction.getEndpoint(), httpClient); + assertFalse(sendMessageAction.isForkMode()); + assertTrue(sendMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); + assertNotNull(httpMessageBuilder); + assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); + assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet/${petId}"); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet/${petId}"); + assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); + assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); + assertEquals(sendMessageAction.getEndpoint(), httpClient); Message controlMessage = new DefaultMessage(""); Message request = inboundQueue.receive(); @@ -178,61 +179,61 @@ public void shouldLoadOpenApiClientActions() { validator.validateMessage(request, controlMessage, context, new DefaultValidationContext()); ReceiveMessageAction receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex++); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); - Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); - - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); - Assert.assertNull(receiveMessageAction.getEndpoint()); - Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); - Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); - Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); + assertEquals(receiveMessageAction.getValidationContexts().size(), 4); + assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); + assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); + assertNotNull(httpMessageBuilder); + + assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); + assertNull(receiveMessageAction.getEndpoint()); + assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); + assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); + assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); - Assert.assertFalse(sendMessageAction.isForkMode()); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertFalse(sendMessageAction.isForkMode()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); + assertNotNull(httpMessageBuilder); + assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Map requestHeaders = httpMessageBuilder.buildMessageHeaders(context); - Assert.assertEquals(requestHeaders.size(), 4L); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); - Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); - Assert.assertNull(sendMessageAction.getEndpointUri()); - Assert.assertEquals(sendMessageAction.getEndpoint(), httpClient); + assertEquals(requestHeaders.size(), 4L); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); + assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); + assertNull(sendMessageAction.getEndpointUri()); + assertEquals(sendMessageAction.getEndpoint(), httpClient); receiveMessageAction = (ReceiveMessageAction) result.getTestAction(actionIndex); - Assert.assertEquals(receiveMessageAction.getValidationContexts().size(), 4); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); - Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); - - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); - Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); - Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); + assertEquals(receiveMessageAction.getValidationContexts().size(), 4); + assertTrue(receiveMessageAction.getValidationContexts().get(0) instanceof HeaderValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof XmlMessageValidationContext); + assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof JsonMessageValidationContext); + + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); + assertNotNull(httpMessageBuilder); + assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); + assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Map responseHeaders = httpMessageBuilder.buildMessageHeaders(context); - Assert.assertEquals(responseHeaders.size(), 2L); - Assert.assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_STATUS_CODE), 201); - Assert.assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_REASON_PHRASE), "CREATED"); - Assert.assertNull(receiveMessageAction.getEndpoint()); - Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); + assertEquals(responseHeaders.size(), 2L); + assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_STATUS_CODE), 201); + assertEquals(responseHeaders.get(HttpMessageHeaders.HTTP_REASON_PHRASE), "CREATED"); + assertNull(receiveMessageAction.getEndpoint()); + assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); - Assert.assertEquals(receiveMessageAction.getVariableExtractors().size(), 0L); + assertEquals(receiveMessageAction.getVariableExtractors().size(), 0L); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java index d3a844c00a..338b832d89 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiServerTest.java @@ -48,6 +48,7 @@ import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -56,15 +57,13 @@ public class OpenApiServerTest extends AbstractGroovyActionDslTest { @BindToRegistry final TestActor testActor = Mockito.mock(TestActor.class); - - private HttpServer httpServer; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); private final EndpointAdapter endpointAdapter = new DirectEndpointAdapter(direct() .synchronous() .timeout(100L) .queue(inboundQueue) .build()); + private HttpServer httpServer; @BeforeClass public void setupEndpoints() { @@ -85,32 +84,32 @@ public void shouldLoadOpenApiServerActions() { context.getReferenceResolver().bind("httpServer", httpServer); endpointAdapter.handleMessage(new HttpMessage() - .method(HttpMethod.GET) - .path("/petstore/v3/pet/12345") - .version("HTTP/1.1") - .accept("application/json") - .contentType("application/json")); + .method(HttpMethod.GET) + .path("/petstore/v3/pet/12345") + .version("HTTP/1.1") + .accept(APPLICATION_JSON_VALUE) + .contentType(APPLICATION_JSON_VALUE)); endpointAdapter.handleMessage(new HttpMessage(""" - { - "id": 1000, - "name": "hasso", - "category": { - "id": 1000, - "name": "dog" - }, - "photoUrls": [ "http://localhost:8080/photos/1000" ], - "tags": [ - { - "id": 1000, - "name": "generated" - } - ], - "status": "available" - } - """) - .method(HttpMethod.POST) - .path("/petstore/v3/pet") - .contentType("application/json")); + { + "id": 1000, + "name": "hasso", + "category": { + "id": 1000, + "name": "dog" + }, + "photoUrls": [ "http://localhost:8080/photos/1000" ], + "tags": [ + { + "id": 1000, + "name": "generated" + } + ], + "status": "available" + } + """) + .method(HttpMethod.POST) + .path("/petstore/v3/pet") + .contentType(APPLICATION_JSON_VALUE)); testLoader.load(); @@ -136,7 +135,7 @@ public void shouldLoadOpenApiServerActions() { assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); assertNotNull(httpMessageBuilder); assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -151,7 +150,7 @@ public void shouldLoadOpenApiServerActions() { assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); assertNotNull(httpMessageBuilder); assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); @@ -160,7 +159,7 @@ public void shouldLoadOpenApiServerActions() { assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); @@ -174,7 +173,7 @@ public void shouldLoadOpenApiServerActions() { assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); assertNotNull(httpMessageBuilder); assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); @@ -191,7 +190,7 @@ public void shouldLoadOpenApiServerActions() { assertEquals(receiveMessageAction.getEndpoint(), httpServer); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); assertNotNull(httpMessageBuilder); assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index 14bfb26f55..80295a9a86 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -31,7 +31,6 @@ import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.citrusframework.util.SocketUtils; -import org.junit.jupiter.api.BeforeEach; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,35 +40,34 @@ import org.testng.annotations.Ignore; import org.testng.annotations.Test; -import java.util.List; - +import static java.util.Collections.singletonList; import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.testng.Assert.assertThrows; import static org.testng.Assert.fail; @Test -@ContextConfiguration(classes = {Config.class}) +@ContextConfiguration(classes = {Config.class}) public class OpenApiClientIT extends TestNGCitrusSpringSupport { public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; - public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; + private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + private final OpenApiSpecification pingSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); + @Autowired private HttpServer httpServer; @Autowired private HttpClient httpClient; - private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); - - private final OpenApiSpecification pingSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/ping/ping-api.yaml")); - - @BeforeEach - void beforeEach() { + @DataProvider(name = "pingApiOperationDataprovider") + public static Object[][] pingApiOperationDataprovider() { + return new Object[][]{{"doPing"}, {"doPong"}, {"doPung"}}; } @CitrusTest @@ -91,7 +89,7 @@ public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { } private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String responseFile, - boolean valid, boolean schemaValidation) { + boolean valid, boolean schemaValidation) { variable("petId", "1001"); @@ -112,11 +110,11 @@ private void shouldExecuteGetPetById(OpenApiActionBuilder openapi, String respon .response(HttpStatus.OK) .message() .body(Resources.create(responseFile)) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi - .client(httpClient).receive("getPetById", HttpStatus.OK) - .schemaValidation(schemaValidation); + .client(httpClient).receive("getPetById", HttpStatus.OK) + .schemaValidation(schemaValidation); if (valid) { then(clientResponseActionBuilder); @@ -137,11 +135,11 @@ public void shouldFailOnMissingNameInRequest() { variable("petId", "1001"); HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) - .client(httpClient) - .send("addPet") - .message().body(Resources.create(INVALID_PET_PATH)); + .client(httpClient) + .send("addPet") + .message().body(Resources.create(INVALID_PET_PATH)); - assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); + assertThrows(TestCaseFailedException.class, () -> when(addPetBuilder)); } @CitrusTest @@ -149,10 +147,10 @@ public void shouldFailOnMissingNameInRequest() { public void shouldFailOnWrongQueryIdType() { variable("petId", "xxxx"); HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) - .client(httpClient) - .send("addPet") - .message().body(Resources.create(VALID_PET_PATH)); - assertThrows(TestCaseFailedException.class, () ->when(addPetBuilder)); + .client(httpClient) + .send("addPet") + .message().body(Resources.create(VALID_PET_PATH)); + assertThrows(TestCaseFailedException.class, () -> when(addPetBuilder)); } @CitrusTest @@ -160,10 +158,10 @@ public void shouldFailOnWrongQueryIdType() { public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { variable("petId", "xxxx"); HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) - .client(httpClient) - .send("addPet") - .schemaValidation(false) - .message().body(Resources.create(VALID_PET_PATH)); + .client(httpClient) + .send("addPet") + .schemaValidation(false) + .message().body(Resources.create(VALID_PET_PATH)); try { when(addPetBuilder); @@ -174,7 +172,6 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { } private void shouldExecuteGetAndAddPet(OpenApiActionBuilder openapi) { - variable("petId", "1001"); when(openapi @@ -187,18 +184,18 @@ private void shouldExecuteGetAndAddPet(OpenApiActionBuilder openapi) { .post("/pet") .message() .body(""" - { - "id": "@isNumber()@", - "name": "@notEmpty()@", - "category": { - "id": "@isNumber()@", - "name": "@notEmpty()@" - }, - "photoUrls": "@notEmpty()@", - "tags": "@ignore@", - "status": "@matches(sold|pending|available)@" - } - """) + { + "id": "@isNumber()@", + "name": "@notEmpty()@", + "category": { + "id": "@isNumber()@", + "name": "@notEmpty()@" + }, + "photoUrls": "@notEmpty()@", + "tags": "@ignore@", + "status": "@matches(sold|pending|available)@" + } + """) .contentType("application/json;charset=UTF-8")); then(http().server(httpServer) @@ -211,11 +208,6 @@ private void shouldExecuteGetAndAddPet(OpenApiActionBuilder openapi) { .receive("addPet", HttpStatus.CREATED)); } - @DataProvider(name="pingApiOperationDataprovider") - public static Object[][] pingApiOperationDataprovider() { - return new Object[][]{{"doPing"}, {"doPong"}, {"doPung"}}; - } - @Test(dataProvider = "pingApiOperationDataprovider") @CitrusTest @Ignore @@ -223,25 +215,25 @@ public void shouldPerformRoundtripPingOperation(String pingApiOperation) { variable("id", 2001); when(openapi(pingSpec) - .client(httpClient) - .send(pingApiOperation) - .message() - .fork(true)); + .client(httpClient) + .send(pingApiOperation) + .message() + .fork(true)); then(openapi(pingSpec).server(httpServer) - .receive(pingApiOperation) - .message() - .accept("@contains('application/json')@")); + .receive(pingApiOperation) + .message() + .accept("@contains('application/json')@")); then(openapi(pingSpec).server(httpServer) - .send(pingApiOperation) - .message() - .contentType("application/json")); + .send(pingApiOperation) + .message() + .contentType(APPLICATION_JSON_VALUE)); OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi(pingSpec) - .client(httpClient).receive(pingApiOperation, HttpStatus.OK); + .client(httpClient).receive(pingApiOperation, HttpStatus.OK); - then(clientResponseActionBuilder); + then(clientResponseActionBuilder); } @Configuration @@ -253,24 +245,24 @@ public static class Config { public HttpServer httpServer() { return new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); } @Bean public HttpClient httpClient() { return new HttpClientBuilder() - .requestUrl("http://localhost:%d".formatted(port)) - .build(); + .requestUrl("http://localhost:%d".formatted(port)) + .build(); } @Bean public OpenApiRepository petstoreOpenApiRepository() { return new OpenApiRepository() - .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + .locations(singletonList("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); } } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index d87831c3f9..13339f059c 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -38,15 +38,15 @@ import org.springframework.test.context.ContextConfiguration; import org.testng.annotations.Test; -import java.util.List; - +import static java.util.Collections.singletonList; import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.testng.Assert.assertThrows; import static org.testng.Assert.fail; @Test -@ContextConfiguration(classes = {Config.class}) +@ContextConfiguration(classes = {Config.class}) public class OpenApiServerIT extends TestNGCitrusSpringSupport { public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; @@ -67,13 +67,13 @@ public void shouldExecuteGetPetById() { .send() .get("/pet/${petId}") .message() - .accept("application/json") + .accept(APPLICATION_JSON_VALUE) .fork(true)); then(openapi("petstore-v3") .server(httpServer) .receive("getPetById") - .message() + .message() ); then(openapi("petstore-v3") @@ -86,59 +86,58 @@ public void shouldExecuteGetPetById() { .response(HttpStatus.OK) .message() .body(""" - { - "id": "@isNumber()@", - "name": "@notEmpty()@", - "category": { - "id": "@isNumber()@", - "name": "@notEmpty()@" - }, - "photoUrls": "@notEmpty()@", - "tags": "@ignore@", - "status": "@matches(sold|pending|available)@" - } - """)); + { + "id": "@isNumber()@", + "name": "@notEmpty()@", + "category": { + "id": "@isNumber()@", + "name": "@notEmpty()@" + }, + "photoUrls": "@notEmpty()@", + "tags": "@ignore@", + "status": "@matches(sold|pending|available)@" + } + """)); } @CitrusTest public void shouldExecuteGetPetByIdWithRandomizedId() { - when(http() - .client(httpClient) - .send() - .get("/pet/726354") - .message() - .accept("application/json") - .fork(true)); + .client(httpClient) + .send() + .get("/pet/726354") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); then(openapi("petstore-v3") - .server(httpServer) - .receive("getPetById") - .message() + .server(httpServer) + .receive("getPetById") + .message() ); then(openapi("petstore-v3") - .server(httpServer) - .send("getPetById", HttpStatus.OK)); + .server(httpServer) + .send("getPetById", HttpStatus.OK)); then(http() - .client(httpClient) - .receive() - .response(HttpStatus.OK) - .message() - .body(""" - { - "id": "@isNumber()@", - "name": "@notEmpty()@", - "category": { - "id": "@isNumber()@", - "name": "@notEmpty()@" - }, - "photoUrls": "@notEmpty()@", - "tags": "@ignore@", - "status": "@matches(sold|pending|available)@" - } - """)); + .client(httpClient) + .receive() + .response(HttpStatus.OK) + .message() + .body(""" + { + "id": "@isNumber()@", + "name": "@notEmpty()@", + "category": { + "id": "@isNumber()@", + "name": "@notEmpty()@" + }, + "photoUrls": "@notEmpty()@", + "tags": "@ignore@", + "status": "@matches(sold|pending|available)@" + } + """)); } @CitrusTest @@ -146,34 +145,34 @@ public void executeGetPetByIdShouldFailOnInvalidResponse() { variable("petId", "1001"); when(http() - .client(httpClient) - .send() - .get("/pet/${petId}") - .message() - .accept("application/json") - .fork(true)); + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); then(openapi("petstore-v3") - .server(httpServer) - .receive("getPetById")); + .server(httpServer) + .receive("getPetById")); HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") - .server(httpServer) - .send("getPetById", HttpStatus.OK) - .message().body(""" - { - "id": "xxxx", - "name": "Garfield", - "category": { - "id": 111, - "name": "Comic" - }, - "photoUrls": [], - "tags": [], - "status": "available" - } - """); - assertThrows(TestCaseFailedException.class, () ->then(getPetByIdResponseBuilder)); + .server(httpServer) + .send("getPetById", HttpStatus.OK) + .message().body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """); + assertThrows(TestCaseFailedException.class, () -> then(getPetByIdResponseBuilder)); } @CitrusTest @@ -181,54 +180,54 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable variable("petId", "1001"); when(http() - .client(httpClient) - .send() - .get("/pet/${petId}") - .message() - .accept("application/json") - .fork(true)); + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); then(openapi("petstore-v3") - .server(httpServer) - .receive("getPetById")); + .server(httpServer) + .receive("getPetById")); HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") - .server(httpServer) - .send("getPetById", HttpStatus.OK) - .schemaValidation(false) - .message().body(""" - { - "id": "xxxx", - "name": "Garfield", - "category": { - "id": 111, - "name": "Comic" - }, - "photoUrls": [], - "tags": [], - "status": "available" - } - """); + .server(httpServer) + .send("getPetById", HttpStatus.OK) + .schemaValidation(false) + .message().body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """); then(getPetByIdResponseBuilder); then(http() - .client(httpClient) - .receive() - .response(HttpStatus.OK) - .message() - .body(""" - { - "id": "xxxx", - "name": "Garfield", - "category": { - "id": 111, - "name": "Comic" - }, - "photoUrls": [], - "tags": [], - "status": "available" - } - """)); + .client(httpClient) + .receive() + .response(HttpStatus.OK) + .message() + .body(""" + { + "id": "xxxx", + "name": "Garfield", + "category": { + "id": 111, + "name": "Comic" + }, + "photoUrls": [], + "tags": [], + "status": "available" + } + """)); } @CitrusTest @@ -251,24 +250,23 @@ public void shouldFailOnMissingNameInResponse() { variable("petId", "1001"); when(http() - .client(httpClient) - .send() - .get("/pet/${petId}") - .message() - .accept("application/json") - .fork(true)); + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); then(openapi("petstore-v3") - .server(httpServer) - .receive("getPetById")); + .server(httpServer) + .receive("getPetById")); OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi("petstore-v3") - .server(httpServer) - .send("getPetById", HttpStatus.OK); + .server(httpServer) + .send("getPetById", HttpStatus.OK); sendMessageActionBuilder.message().body(Resources.create(INVALID_PET_PATH)); assertThrows(TestCaseFailedException.class, () -> then(sendMessageActionBuilder)); - } @CitrusTest @@ -276,17 +274,17 @@ public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { variable("petId", "xxx"); when(http() - .client(httpClient) - .send() - .post("/pet") - .message() - .body(Resources.create(VALID_PET_PATH)) - .contentType("application/json") - .fork(true)); + .client(httpClient) + .send() + .post("/pet") + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType(APPLICATION_JSON_VALUE) + .fork(true)); OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") - .server(httpServer) - .receive("addPet"); + .server(httpServer) + .receive("addPet"); assertThrows(TestCaseFailedException.class, () -> then(addPetBuilder)); } @@ -296,18 +294,18 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { variable("petId", -1); when(http() - .client(httpClient) - .send() - .post("/pet") - .message() - .body(Resources.create(VALID_PET_PATH)) - .contentType("application/json") - .fork(true)); + .client(httpClient) + .send() + .post("/pet") + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType(APPLICATION_JSON_VALUE) + .fork(true)); OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") - .server(httpServer) - .receive("addPet") - .schemaValidation(false); + .server(httpServer) + .receive("addPet") + .schemaValidation(false); try { when(addPetBuilder); @@ -325,29 +323,28 @@ private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFil .post("/pet") .message() .body(Resources.create(requestFile)) - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .fork(true)); OpenApiServerRequestActionBuilder receiveActionBuilder = openapi - .server(httpServer) - .receive("addPet"); + .server(httpServer) + .receive("addPet"); + if (valid) { then(receiveActionBuilder); then(openapi - .server(httpServer) - .send("addPet", HttpStatus.CREATED)); + .server(httpServer) + .send("addPet", HttpStatus.CREATED)); then(http() - .client(httpClient) - .receive() - .response(HttpStatus.CREATED)); + .client(httpClient) + .receive() + .response(HttpStatus.CREATED)); } else { assertThrows(() -> then(receiveActionBuilder)); } - - } @Configuration @@ -358,25 +355,24 @@ public static class Config { @Bean public HttpServer httpServer() { return new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); } @Bean public HttpClient httpClient() { return new HttpClientBuilder() - .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) - .build(); + .requestUrl("http://localhost:%d/petstore/v3".formatted(port)) + .build(); } @Bean public OpenApiRepository petstoreOpenApiRepository() { return new OpenApiRepository() - .locations(List.of("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + .locations(singletonList("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); } } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java index 68c5da1786..fd7322ff44 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OperationPathAdapterTest.java @@ -31,8 +31,7 @@ public void shouldReturnFormattedStringWhenToStringIsCalled() { Oas30Operation oas30Operation = new Oas30Operation("get"); oas30Operation.operationId = "operationId"; - OperationPathAdapter adapter = new OperationPathAdapter("/api/path", "/context/path", "/full/path", oas30Operation, - oas30Operation.operationId); + OperationPathAdapter adapter = new OperationPathAdapter("/api/path", "/context/path", "/full/path", oas30Operation, oas30Operation.operationId); // When String expectedString = format("%s (%s)", OpenApiUtils.getMethodPath("GET", "/api/path"), "operationId"); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java index 501c497f7c..cfa0b69440 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v2/Oas20ModelHelperTest.java @@ -38,7 +38,7 @@ public void shouldFindRandomResponseWithGoodStatusCode() { operation.responses.addResponse("200", okResponse); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(okResponse, responseForRandomGeneration.get()); } @@ -60,7 +60,7 @@ public void shouldFindFirstResponseInAbsenceOfAGoodOne() { operation.responses.addResponse("407", nokResponse407); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(responseForRandomGeneration.get().getStatusCode(), "403"); } @@ -83,7 +83,7 @@ public void shouldFindDefaultResponseInAbsenceOfAGoodOne() { operation.responses.addResponse("407", nokResponse407); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(responseForRandomGeneration.get().getStatusCode(), "407"); } @@ -141,7 +141,5 @@ public void shouldFindSchemaFromParameter() { assertEquals(parameter.minItems, parameterSchema.minItems); assertEquals(parameter.minLength, parameterSchema.minLength); assertEquals(parameter.exclusiveMinimum, parameterSchema.exclusiveMinimum); - } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java index b26f2f7780..dd00a89dfc 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/v3/Oas30ModelHelperTest.java @@ -71,8 +71,8 @@ public void shouldFindAllRequestTypesForOperation() { Oas30Response response = new Oas30Response("200"); response.content = Map.of(MediaType.APPLICATION_JSON_VALUE, - new Oas30MediaType(MediaType.APPLICATION_JSON_VALUE), - MediaType.APPLICATION_XML_VALUE, new Oas30MediaType(MediaType.APPLICATION_XML_VALUE)); + new Oas30MediaType(MediaType.APPLICATION_JSON_VALUE), + MediaType.APPLICATION_XML_VALUE, new Oas30MediaType(MediaType.APPLICATION_XML_VALUE)); operation.responses = new Oas30Responses(); operation.responses.addResponse("200", response); @@ -81,7 +81,6 @@ public void shouldFindAllRequestTypesForOperation() { assertTrue(responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)); assertTrue(responseTypes.contains(MediaType.APPLICATION_XML_VALUE)); - } @Test @@ -104,14 +103,14 @@ public void shouldFindRandomResponseWithGoodStatusCode() { xmlMediaType.schema = new Oas30Schema(); okResponse.content = Map.of(MediaType.APPLICATION_JSON_VALUE, jsonMediaType, - MediaType.APPLICATION_XML_VALUE, xmlMediaType); + MediaType.APPLICATION_XML_VALUE, xmlMediaType); operation.responses = new Oas30Responses(); operation.responses.addResponse("403", nokResponse); operation.responses.addResponse("200", okResponse); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(okResponse, responseForRandomGeneration.get()); } @@ -136,10 +135,9 @@ public void shouldFindFirstResponseInAbsenceOfAGoodOne() { operation.responses.addResponse("407", nokResponse407); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(responseForRandomGeneration.get().getStatusCode(), "403"); - } @Test @@ -163,7 +161,7 @@ public void shouldFindDefaultResponseInAbsenceOfAGoodOne() { operation.responses.addResponse("407", nokResponse407); Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - document, operation, null, null); + document, operation, null, null); assertTrue(responseForRandomGeneration.isPresent()); assertEquals(responseForRandomGeneration.get().getStatusCode(), "407"); } @@ -185,5 +183,4 @@ public void shouldNotFindParameterSchema() { Optional parameterSchema = Oas30ModelHelper.getParameterSchema(parameter); assertTrue(parameterSchema.isEmpty()); } - -} \ No newline at end of file +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java index 43fd6d628b..6af97c566f 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/OasRandomConfigurationTest.java @@ -7,7 +7,11 @@ import java.util.List; -import static org.citrusframework.openapi.OpenApiConstants.*; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_DATE_TIME; +import static org.citrusframework.openapi.OpenApiConstants.FORMAT_UUID; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_BOOLEAN; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; import static org.testng.Assert.assertTrue; @@ -174,6 +178,6 @@ public void testGetGeneratorForNullSchema() { OasSchema schema = new Oas30Schema(); RandomGenerator generator = randomConfiguration.getGenerator(schema); assertNotNull(generator); - assertSame(generator, RandomGenerator.NULL_GENERATOR); + assertSame(generator, RandomGenerator.NOOP_RANDOM_GENERATOR); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java index c361e0f1f6..da923caa77 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomArrayGeneratorTest.java @@ -1,5 +1,11 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.OpenApiConstants; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; @@ -9,12 +15,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import org.citrusframework.openapi.OpenApiConstants; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomArrayGeneratorTest { private RandomArrayGenerator generator; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java index 160c6d9f91..818f6488ae 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomCompositeGeneratorTest.java @@ -1,5 +1,13 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.any; import static org.mockito.Mockito.assertArg; @@ -12,13 +20,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.Collections; -import java.util.List; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomCompositeGeneratorTest { private RandomCompositeGenerator generator; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java index 78d47bb52e..9e9ac1ae60 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomContextTest.java @@ -1,5 +1,15 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.OpenApiSpecification; +import org.springframework.test.util.ReflectionTestUtils; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.HashMap; +import java.util.Map; + import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -8,15 +18,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertSame; -import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.HashMap; -import java.util.Map; -import org.citrusframework.openapi.OpenApiSpecification; -import org.springframework.test.util.ReflectionTestUtils; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomContextTest { private OpenApiSpecification specificationMock; @@ -30,7 +31,7 @@ public void setUp() { RandomModelBuilder randomModelBuilderMock = mock(); specificationMock = mock(); - schemaDefinitions =new HashMap<>(); + schemaDefinitions = new HashMap<>(); randomContext = spy(new RandomContext(specificationMock, true)); ReflectionTestUtils.setField(randomContext, "randomModelBuilder", randomModelBuilderMock); @@ -68,8 +69,8 @@ public void testGetSpecification() { @Test public void testCacheVariable() { - HashMap cachedValue1 = randomContext.get("testKey", k -> new HashMap<>()); - HashMap cachedValue2 = randomContext.get("testKey", k -> new HashMap<>()); + HashMap cachedValue1 = randomContext.get("testKey", k -> new HashMap<>()); + HashMap cachedValue2 = randomContext.get("testKey", k -> new HashMap<>()); assertSame(cachedValue1, cachedValue2); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java index 0f17bd143e..b122832165 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomElementTest.java @@ -16,11 +16,11 @@ package org.citrusframework.openapi.random; -import static org.testng.Assert.assertEquals; - import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + public class RandomElementTest { private RandomElement.RandomList randomList; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java index 8d4d7a14e9..3aaa86f541 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomEnumGeneratorTest.java @@ -1,5 +1,12 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.List; + +import static java.util.Collections.emptyList; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -8,11 +15,6 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.List; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomEnumGeneratorTest { private RandomEnumGenerator generator; @@ -59,7 +61,7 @@ public void testGenerateWithEnum() { @Test public void testGenerateWithEmptyEnum() { - mockSchema.enum_ = List.of(); + mockSchema.enum_ = emptyList(); generator.generate(mockContext, mockSchema); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java index 01d1c253e6..a5d442a73d 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorBuilderTest.java @@ -1,17 +1,17 @@ package org.citrusframework.openapi.random; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - import io.apicurio.datamodels.openapi.models.OasSchema; -import java.util.function.BiConsumer; import org.springframework.test.util.ReflectionTestUtils; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.function.BiConsumer; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; public class RandomGeneratorBuilderTest { @@ -27,11 +27,12 @@ public void setUp() { } @Test - public void testBuilderWithTypeAndFormat() { + public void testRandomGeneratorBuilderWithTypeAndFormat() { String type = "type1"; String format = "format1"; - RandomGenerator generator = RandomGeneratorBuilder.builder(type, format).build(consumerMock); + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder(type, format) + .build(consumerMock); OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); assertNotNull(schema); assertEquals(schema.type, type); @@ -39,41 +40,46 @@ public void testBuilderWithTypeAndFormat() { } @Test - public void testBuilderWithType() { + public void testRandomGeneratorBuilderWithType() { String type = "type1"; - RandomGenerator generator = RandomGeneratorBuilder.builder().withType(type).build( - consumerMock); + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder() + .withType(type) + .build(consumerMock); OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); assertNotNull(schema); assertEquals(schema.type, type); } @Test - public void testBuilderWithFormat() { + public void testRandomGeneratorBuilderWithFormat() { String format = "format1"; - RandomGenerator generator = RandomGeneratorBuilder.builder().withFormat(format).build( - consumerMock); + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder() + .withFormat(format) + .build(consumerMock); OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); assertNotNull(schema); assertEquals(schema.format, format); } @Test - public void testBuilderWithPattern() { + public void testRandomGeneratorBuilderWithPattern() { String pattern = "pattern1"; - RandomGenerator generator = RandomGeneratorBuilder.builder().withPattern(pattern).build( - consumerMock); + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder() + .withPattern(pattern) + .build(consumerMock); OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); assertNotNull(schema); assertEquals(schema.pattern, pattern); } @Test - public void testBuilderWithEnum() { - RandomGenerator generator = RandomGeneratorBuilder.builder().withEnum().build(consumerMock); + public void testRandomGeneratorBuilderWithEnum() { + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder() + .withEnum() + .build(consumerMock); OasSchema schema = (OasSchema) ReflectionTestUtils.getField(generator, "schema"); assertNotNull(schema); assertNotNull(schema.enum_); @@ -82,11 +88,11 @@ public void testBuilderWithEnum() { @Test public void testBuildGenerator() { - RandomGenerator generator = RandomGeneratorBuilder.builder().build(consumerMock); + RandomGenerator generator = RandomGeneratorBuilder.randomGeneratorBuilder() + .build(consumerMock); generator.generate(contextMock, schemaMock); verify(consumerMock).accept(contextMock, schemaMock); } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java index c788fff730..6825b963b6 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomGeneratorTest.java @@ -1,17 +1,18 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.List; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.List; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomGeneratorTest { private RandomGenerator generator; @@ -145,7 +146,7 @@ void generate(RandomContext randomContext, OasSchema schema) { public void testNullGenerator() { RandomContext mockContext = mock(RandomContext.class); - RandomGenerator.NULL_GENERATOR.generate(mockContext, mockSchema); + RandomGenerator.NOOP_RANDOM_GENERATOR.generate(mockContext, mockSchema); verify(mockContext, never()).getRandomModelBuilder(); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java index ef4deb3abc..223e67cc52 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomModelBuilderTest.java @@ -16,14 +16,15 @@ package org.citrusframework.openapi.random; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.expectThrows; - -import java.util.ArrayDeque; import org.springframework.test.util.ReflectionTestUtils; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.ArrayDeque; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.expectThrows; + public class RandomModelBuilderTest { private RandomModelBuilder builder; @@ -63,7 +64,7 @@ public void testAppendSimpleQuoted() { @Test public void testAppendSimpleQuotedIfNotQuoting() { - ReflectionTestUtils.setField(builder,"quote", false); + ReflectionTestUtils.setField(builder, "quote", false); builder.appendSimpleQuoted("testValue"); String json = builder.write(); assertEquals(json, "testValue"); @@ -82,9 +83,9 @@ public void testObjectWithProperties() { @Test public void testNestedObject() { builder.object(() -> - builder.property("outerKey", () -> builder.object(() -> - builder.property("innerKey", () -> builder.appendSimple("\"innerValue\"")) - )) + builder.property("outerKey", () -> builder.object(() -> + builder.property("innerKey", () -> builder.appendSimple("\"innerValue\"")) + )) ); String json = builder.write(); assertEquals(json, "{\"outerKey\": {\"innerKey\": \"innerValue\"}}"); @@ -121,7 +122,7 @@ public void testMixedStructure() { builder.property("key1", () -> builder.array(() -> { builder.appendSimple("\"value1\""); builder.object(() -> - builder.property("nestedKey", () -> builder.appendSimple("\"nestedValue\"")) + builder.property("nestedKey", () -> builder.appendSimple("\"nestedValue\"")) ); })); builder.property("key2", () -> builder.appendSimple("\"value2\"")); @@ -132,21 +133,22 @@ public void testMixedStructure() { @Test public void testIllegalStateOnEmptyDeque() { - builder.deque.clear(); Exception exception = expectThrows(IllegalStateException.class, () -> - builder.property("key", () -> builder.appendSimple("value")) + builder.property("key", () -> builder.appendSimple("value")) ); assertEquals(exception.getMessage(), "Encountered empty stack!"); exception = expectThrows(IllegalStateException.class, () -> - builder.object(() -> {}) + builder.object(() -> { + }) ); assertEquals(exception.getMessage(), "Encountered empty stack!"); exception = expectThrows(IllegalStateException.class, () -> - builder.array(() -> {}) + builder.array(() -> { + }) ); assertEquals(exception.getMessage(), "Encountered empty stack!"); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java index fbcb4f0479..02d987b0a1 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomNumberGeneratorTest.java @@ -1,20 +1,21 @@ package org.citrusframework.openapi.random; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; - import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.math.BigDecimal; import org.citrusframework.openapi.OpenApiConstants; import org.testng.annotations.BeforeMethod; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.math.BigDecimal; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertTrue; + public class RandomNumberGeneratorTest { private RandomNumberGenerator generator; @@ -22,6 +23,18 @@ public class RandomNumberGeneratorTest { private RandomModelBuilder mockBuilder; private OasSchema schema; + @DataProvider(name = "findLeastSignificantDecimalPlace") + public static Object[][] findLeastSignificantDecimalPlace() { + return new Object[][]{ + {new BigDecimal("1234.5678"), 4}, + {new BigDecimal("123.567"), 3}, + {new BigDecimal("123.56"), 2}, + {new BigDecimal("123.5"), 1}, + {new BigDecimal("123.0"), 0}, + {new BigDecimal("123"), 0} + }; + } + @BeforeMethod public void setUp() { generator = new RandomNumberGenerator(); @@ -196,22 +209,8 @@ public void testHandlesWithNullSchema() { assertFalse(generator.handles(null)); } - @DataProvider(name = "findLeastSignificantDecimalPlace") - public static Object[][] findLeastSignificantDecimalPlace() { - return new Object[][]{ - {new BigDecimal("1234.5678"), 4}, - {new BigDecimal("123.567"), 3}, - {new BigDecimal("123.56"), 2}, - {new BigDecimal("123.5"), 1}, - {new BigDecimal("123.0"), 0}, - {new BigDecimal("123"), 0} - }; - } - @Test(dataProvider = "findLeastSignificantDecimalPlace") - void findLeastSignificantDecimalPlace(BigDecimal number, int expectedSignificance) { - assertEquals(generator.findLeastSignificantDecimalPlace(number), - expectedSignificance); + public void findLeastSignificantDecimalPlace(BigDecimal number, int expectedSignificance) { + assertEquals(generator.findLeastSignificantDecimalPlace(number), expectedSignificance); } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java index a32809f2f9..86849b3464 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java @@ -1,5 +1,18 @@ package org.citrusframework.openapi.random; +import io.apicurio.datamodels.openapi.models.OasSchema; +import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; +import org.citrusframework.openapi.OpenApiConstants; +import org.citrusframework.openapi.OpenApiSpecification; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; @@ -10,17 +23,6 @@ import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; -import io.apicurio.datamodels.openapi.models.OasSchema; -import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.List; -import org.citrusframework.openapi.OpenApiConstants; -import org.citrusframework.openapi.OpenApiSpecification; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - public class RandomObjectGeneratorTest { private RandomObjectGenerator generator; @@ -38,7 +40,6 @@ public void setUp() { when(contextMock.getRandomModelBuilder()).thenReturn(randomModelBuilderSpy); when(contextMock.getSpecification()).thenReturn(specificationMock); when(contextMock.get(eq("OBJECT_STACK"), any())).thenReturn(new ArrayDeque<>()); - } @Test @@ -91,7 +92,7 @@ public void testGenerateObjectWithRequiredProperties() { schema.properties = new HashMap<>(); OasSchema propertySchema = new Oas30Schema(); schema.properties.put("property1", propertySchema); - schema.required = List.of("property1"); + schema.required = singletonList("property1"); when(specificationMock.isGenerateOptionalFields()).thenReturn(false); @@ -109,7 +110,7 @@ public void testGenerateObjectWithOptionalProperties() { schema.properties = new HashMap<>(); OasSchema propertySchema = new Oas30Schema(); schema.properties.put("property1", propertySchema); - schema.required = List.of(); + schema.required = emptyList(); when(specificationMock.isGenerateOptionalFields()).thenReturn(false); generator.generate(contextMock, schema); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java index 445a318bd9..b45ae31f87 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomStringGeneratorTest.java @@ -1,14 +1,14 @@ package org.citrusframework.openapi.random; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - import io.apicurio.datamodels.openapi.models.OasSchema; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + public class RandomStringGeneratorTest { private RandomStringGenerator generator; diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessorTest.java similarity index 76% rename from connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java rename to connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessorTest.java index 34f82542a2..bcc3f4e503 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiMessageProcessorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiOperationToMessageHeadersProcessorTest.java @@ -1,24 +1,28 @@ package org.citrusframework.openapi.validation; -import java.util.Optional; import org.citrusframework.context.TestContext; import org.citrusframework.message.Message; import org.citrusframework.openapi.OpenApiMessageHeaders; import org.citrusframework.openapi.OpenApiMessageType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.mockito.Mockito; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import static org.mockito.Mockito.*; -import static org.testng.Assert.*; -public class OpenApiMessageProcessorTest { +import java.util.Optional; + +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class OpenApiOperationToMessageHeadersProcessorTest { private OpenApiSpecification openApiSpecification; private String operationId; private OpenApiMessageType type; - private OpenApiMessageProcessor processor; + private OpenApiOperationToMessageHeadersProcessor processor; private Message message; private TestContext context; @@ -27,7 +31,7 @@ public void setUp() { openApiSpecification = mock(OpenApiSpecification.class); operationId = "testOperationId"; type = mock(OpenApiMessageType.class); - processor = new OpenApiMessageProcessor(openApiSpecification, operationId, type); + processor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, type); message = mock(Message.class); context = mock(TestContext.class); @@ -37,7 +41,7 @@ public void setUp() { public void testProcess() { OperationPathAdapter operationPathAdapter = mock(OperationPathAdapter.class); when(openApiSpecification.getOperation(operationId, context)) - .thenReturn(Optional.of(operationPathAdapter)); + .thenReturn(Optional.of(operationPathAdapter)); when(operationPathAdapter.uniqueOperationId()).thenReturn("uniqueOperationId"); when(type.toHeaderName()).thenReturn("headerName"); @@ -50,7 +54,7 @@ public void testProcess() { @Test public void testProcessOperationNotPresent() { when(openApiSpecification.getOperation(operationId, context)) - .thenReturn(Optional.empty()); + .thenReturn(Optional.empty()); processor.process(message, context); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java index 478480e9ba..938c98cc57 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiRequestValidatorTest.java @@ -16,25 +16,10 @@ package org.citrusframework.openapi.validation; -import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_REQUEST_URI; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.report.ValidationReport; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.OpenApiSpecification; @@ -48,6 +33,24 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Collections.singletonList; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_REQUEST_URI; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + public class OpenApiRequestValidatorTest { @Mock @@ -93,7 +96,7 @@ public void shouldValidateRequestWithNoErrors() { when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) - .thenReturn(validationReportMock); + .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(false); // When @@ -110,7 +113,7 @@ public void shouldValidateRequestWithErrors() { when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); when(openApiInteractionValidatorMock.validateRequest(any(Request.class))) - .thenReturn(validationReportMock); + .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(true); // When @@ -134,7 +137,7 @@ public void shouldCreateRequestFromMessage() throws IOException { when(httpMessageMock.getHeaders()).thenReturn(headers); when(httpMessageMock.getHeader(HTTP_REQUEST_URI)).thenReturn("/api/test"); when(httpMessageMock.getRequestMethod()).thenReturn(RequestMethod.GET); - when(httpMessageMock.getAccept()).thenReturn("application/json"); + when(httpMessageMock.getAccept()).thenReturn(APPLICATION_JSON_VALUE); when(operationPathAdapterMock.contextPath()).thenReturn("/api"); // When @@ -145,7 +148,7 @@ public void shouldCreateRequestFromMessage() throws IOException { assertEquals(request.getPath(), "/test"); assertEquals(request.getMethod(), Method.GET); assertEquals(request.getHeaders().get("array"), List.of("e1", "e2")); - assertEquals(request.getHeaders().get("simple"), List.of("s1")); + assertEquals(request.getHeaders().get("simple"), singletonList("s1")); List nullList = new ArrayList<>(); nullList.add(null); assertEquals(request.getHeaders().get("nullarray"), nullList); @@ -171,7 +174,6 @@ public void shouldCreateFormRequestFromMessage() throws IOException { Request request = openApiRequestValidator.createRequestFromMessage(operationPathAdapterMock, httpMessageMock); // Then - assertEquals(request.getRequestBody().get().toString(StandardCharsets.UTF_8), "name=John+Doe&age=30&city=New+York"); + assertEquals(request.getRequestBody().orElseThrow(IllegalArgumentException::new).toString(StandardCharsets.UTF_8), "name=John+Doe&age=30&city=New+York"); } - } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java index 2246b0c00f..3bcb184b83 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/validation/OpenApiResponseValidatorTest.java @@ -16,23 +16,11 @@ package org.citrusframework.openapi.validation; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.anyString; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; - import com.atlassian.oai.validator.OpenApiInteractionValidator; import com.atlassian.oai.validator.model.Request.Method; import com.atlassian.oai.validator.model.Response; import com.atlassian.oai.validator.report.ValidationReport; import io.apicurio.datamodels.openapi.models.OasOperation; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.Map; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.OpenApiSpecification; @@ -45,6 +33,20 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.anyString; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + public class OpenApiResponseValidatorTest { @Mock @@ -88,12 +90,11 @@ public void afterMethod() throws Exception { mockCloseable.close(); } - @Test public void shouldValidateWithNoErrors() { // Given when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) - .thenReturn(validationReportMock); + .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(false); when(operationPathAdapterMock.operation()).thenReturn(operationMock); @@ -113,7 +114,7 @@ public void shouldValidateWithNoErrors() { public void shouldValidateWithErrors() { // Given when(openApiInteractionValidatorMock.validateResponse(anyString(), any(Method.class), any(Response.class))) - .thenReturn(validationReportMock); + .thenReturn(validationReportMock); when(validationReportMock.hasErrors()).thenReturn(true); when(operationPathAdapterMock.operation()).thenReturn(operationMock); @@ -133,7 +134,7 @@ public void shouldValidateWithErrors() { public void shouldCreateResponseMessage() throws IOException { // Given when(httpMessageMock.getPayload()).thenReturn("payload"); - when(httpMessageMock.getHeaders()).thenReturn(Map.of("Content-Type", "application/json")); + when(httpMessageMock.getHeaders()).thenReturn(Map.of("Content-Type", APPLICATION_JSON_VALUE)); when(httpMessageMock.getStatusCode()).thenReturn(HttpStatusCode.valueOf(200)); // When @@ -144,7 +145,7 @@ public void shouldCreateResponseMessage() throws IOException { assertTrue(response.getResponseBody().isPresent()); assertEquals(response.getResponseBody().get().toString(StandardCharsets.UTF_8), "payload"); assertTrue(response.getHeaderValue("Content-Type").isPresent()); - assertEquals(response.getHeaderValue("Content-Type").get(), "application/json"); + assertEquals(response.getHeaderValue("Content-Type").get(), APPLICATION_JSON_VALUE); assertEquals(response.getStatus(), Integer.valueOf(200)); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/AbstractXmlActionTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/AbstractXmlActionTest.java index 6d5fe30b8c..98f777dc40 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/AbstractXmlActionTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/AbstractXmlActionTest.java @@ -57,7 +57,7 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); - doAnswer(invocationOnMock-> { + doAnswer(invocationOnMock -> { context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); return null; }).when(citrusContext).addComponent(anyString(), any()); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index c18d7509dc..b63194d6d7 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -61,6 +61,7 @@ import java.util.concurrent.ArrayBlockingQueue; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; public class OpenApiClientTest extends AbstractXmlActionTest { @@ -75,13 +76,10 @@ public class OpenApiClientTest extends AbstractXmlActionTest { private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; - - private HttpServer httpServer; - private HttpClient httpClient; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); - private final Queue responses = new ArrayBlockingQueue<>(6); + private HttpServer httpServer; + private HttpClient httpClient; @BeforeClass public void setupEndpoints() { @@ -144,7 +142,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { ], "status": "available" } - """).status(HttpStatus.OK).contentType("application/json")); + """).status(HttpStatus.OK).contentType(APPLICATION_JSON_VALUE)); responses.add(new HttpMessage().status(HttpStatus.CREATED)); testLoader.load(); @@ -165,7 +163,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); Assert.assertFalse(sendMessageAction.isForkMode()); Assert.assertTrue(sendMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -190,7 +188,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -198,7 +196,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); @@ -206,7 +204,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); Assert.assertFalse(sendMessageAction.isForkMode()); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); @@ -217,7 +215,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); @@ -227,7 +225,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java index bcfee0463f..55c2568ff6 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiServerTest.java @@ -48,20 +48,19 @@ import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; public class OpenApiServerTest extends AbstractXmlActionTest { @BindToRegistry final TestActor testActor = Mockito.mock(TestActor.class); - - private HttpServer httpServer; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); private final EndpointAdapter endpointAdapter = new DirectEndpointAdapter(direct() .synchronous() .timeout(100L) .queue(inboundQueue) .build()); + private HttpServer httpServer; @BeforeClass public void setupEndpoints() { @@ -82,32 +81,32 @@ public void shouldLoadOpenApiServerActions() { context.getReferenceResolver().bind("httpServer", httpServer); endpointAdapter.handleMessage(new HttpMessage() - .method(HttpMethod.GET) - .path("/petstore/v3/pet/12345") - .version("HTTP/1.1") - .accept("application/json") - .contentType("application/json")); + .method(HttpMethod.GET) + .path("/petstore/v3/pet/12345") + .version("HTTP/1.1") + .accept(APPLICATION_JSON_VALUE) + .contentType(APPLICATION_JSON_VALUE)); endpointAdapter.handleMessage(new HttpMessage(""" - { - "id": 1000, - "name": "hasso", - "category": { - "id": 1000, - "name": "dog" - }, - "photoUrls": [ "http://localhost:8080/photos/1000" ], - "tags": [ - { - "id": 1000, - "name": "generated" - } - ], - "status": "available" - } - """) - .method(HttpMethod.POST) - .path("/petstore/v3/pet") - .contentType("application/json")); + { + "id": 1000, + "name": "hasso", + "category": { + "id": 1000, + "name": "dog" + }, + "photoUrls": [ "http://localhost:8080/photos/1000" ], + "tags": [ + { + "id": 1000, + "name": "generated" + } + ], + "status": "available" + } + """) + .method(HttpMethod.POST) + .path("/petstore/v3/pet") + .contentType(APPLICATION_JSON_VALUE)); testLoader.load(); @@ -133,7 +132,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -148,7 +147,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); @@ -157,7 +156,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); @@ -171,7 +170,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); @@ -188,7 +187,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpServer"); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/AbstractYamlActionTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/AbstractYamlActionTest.java index 6958c83ddc..aafbd77441 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/AbstractYamlActionTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/AbstractYamlActionTest.java @@ -57,7 +57,7 @@ protected TestContext createTestContext() { CitrusAnnotations.parseConfiguration(invocationOnMock.getArgument(0, Object.class), citrusContext); return null; }).when(citrusContext).parseConfiguration((Object) any()); - doAnswer(invocationOnMock-> { + doAnswer(invocationOnMock -> { context.getReferenceResolver().bind(invocationOnMock.getArgument(0), invocationOnMock.getArgument(1)); return null; }).when(citrusContext).addComponent(anyString(), any()); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index 24757fb060..c8441826c6 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -53,12 +53,12 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import java.io.IOException; import java.util.Map; import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; public class OpenApiClientTest extends AbstractYamlActionTest { @@ -73,13 +73,10 @@ public class OpenApiClientTest extends AbstractYamlActionTest { private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; - - private HttpServer httpServer; - private HttpClient httpClient; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); - private final Queue responses = new ArrayBlockingQueue<>(6); + private HttpServer httpServer; + private HttpClient httpClient; @BeforeClass public void setupEndpoints() { @@ -139,7 +136,7 @@ public void shouldLoadOpenApiClientActions() { ], "status": "available" } - """).status(HttpStatus.OK).contentType("application/json")); + """).status(HttpStatus.OK).contentType(APPLICATION_JSON_VALUE)); responses.add(new HttpMessage().status(HttpStatus.CREATED)); testLoader.load(); @@ -160,7 +157,7 @@ public void shouldLoadOpenApiClientActions() { SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); Assert.assertFalse(sendMessageAction.isForkMode()); Assert.assertTrue(sendMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -185,7 +182,7 @@ public void shouldLoadOpenApiClientActions() { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -193,7 +190,7 @@ public void shouldLoadOpenApiClientActions() { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); @@ -201,7 +198,7 @@ public void shouldLoadOpenApiClientActions() { sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); Assert.assertFalse(sendMessageAction.isForkMode()); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); @@ -212,7 +209,7 @@ public void shouldLoadOpenApiClientActions() { Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); @@ -222,7 +219,7 @@ public void shouldLoadOpenApiClientActions() { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(1) instanceof JsonMessageValidationContext); Assert.assertTrue(receiveMessageAction.getValidationContexts().get(2) instanceof HeaderValidationContext); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java index b0edf652dc..17ec33000e 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiServerTest.java @@ -48,20 +48,19 @@ import static org.citrusframework.endpoint.direct.DirectEndpoints.direct; import static org.citrusframework.http.endpoint.builder.HttpEndpoints.http; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; public class OpenApiServerTest extends AbstractYamlActionTest { @BindToRegistry final TestActor testActor = Mockito.mock(TestActor.class); - - private HttpServer httpServer; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); private final EndpointAdapter endpointAdapter = new DirectEndpointAdapter(direct() .synchronous() .timeout(100L) .queue(inboundQueue) .build()); + private HttpServer httpServer; @BeforeClass public void setupEndpoints() { @@ -82,32 +81,32 @@ public void shouldLoadOpenApiServerActions() { context.getReferenceResolver().bind("httpServer", httpServer); endpointAdapter.handleMessage(new HttpMessage() - .method(HttpMethod.GET) - .path("/petstore/v3/pet/12345") - .version("HTTP/1.1") - .accept("application/json") - .contentType("application/json")); + .method(HttpMethod.GET) + .path("/petstore/v3/pet/12345") + .version("HTTP/1.1") + .accept(APPLICATION_JSON_VALUE) + .contentType(APPLICATION_JSON_VALUE)); endpointAdapter.handleMessage(new HttpMessage(""" - { - "id": 1000, - "name": "hasso", - "category": { - "id": 1000, - "name": "dog" - }, - "photoUrls": [ "http://localhost:8080/photos/1000" ], - "tags": [ - { - "id": 1000, - "name": "generated" - } - ], - "status": "available" - } - """) - .method(HttpMethod.POST) - .path("/petstore/v3/pet") - .contentType("application/json")); + { + "id": 1000, + "name": "hasso", + "category": { + "id": 1000, + "name": "dog" + }, + "photoUrls": [ "http://localhost:8080/photos/1000" ], + "tags": [ + { + "id": 1000, + "name": "generated" + } + ], + "status": "available" + } + """) + .method(HttpMethod.POST) + .path("/petstore/v3/pet") + .contentType(APPLICATION_JSON_VALUE)); testLoader.load(); @@ -133,7 +132,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 0L); Assert.assertTrue(receiveMessageAction.getMessageBuilder() instanceof HttpMessageBuilder); - HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + HttpMessageBuilder httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), ""); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); @@ -148,7 +147,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getControlMessageProcessors().size(), 0); SendMessageAction sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex++); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertTrue(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()).toString().startsWith("{\"id\": ")); @@ -157,7 +156,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), "application/json"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpServer"); @@ -171,7 +170,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertTrue(receiveMessageAction.getValidationContexts().get(3) instanceof OpenApiMessageValidationContext); Assert.assertEquals(receiveMessageAction.getReceiveTimeout(), 2000L); - httpMessageBuilder = ((HttpMessageBuilder)receiveMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, receiveMessageAction.getMessageType()), "{\"id\": \"@isNumber()@\",\"category\": {\"id\": \"@isNumber()@\",\"name\": \"@notEmpty()@\"},\"name\": \"@notEmpty()@\",\"photoUrls\": \"@ignore@\",\"tags\": \"@ignore@\",\"status\": \"@matches(available|pending|sold)@\"}"); @@ -188,7 +187,7 @@ public void shouldLoadOpenApiServerActions() { Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpServer"); sendMessageAction = (SendMessageAction) result.getTestAction(actionIndex); - httpMessageBuilder = ((HttpMessageBuilder)sendMessageAction.getMessageBuilder()); + httpMessageBuilder = ((HttpMessageBuilder) sendMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); Assert.assertEquals(httpMessageBuilder.buildMessagePayload(context, sendMessageAction.getMessageType()), ""); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java index 5ba5731245..c4359a4bdf 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java @@ -25,10 +25,10 @@ */ public interface ApiActionBuilderCustomizer { - default > void customizeRequestBuilder(GeneratedApi generatedApi, T builder) { + default > void customizeRequestBuilder(GeneratedApi generatedApi, T builder) { } - default > void customizeResponseBuilder(GeneratedApi generatedApi, T builder) { + default > void customizeResponseBuilder(GeneratedApi generatedApi, T builder) { } } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java index 07c7bad723..27a34d5cf1 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java @@ -16,11 +16,11 @@ package org.citrusframework.openapi.testapi; +import org.citrusframework.endpoint.Endpoint; + import java.util.List; import java.util.Map; -import org.citrusframework.endpoint.Endpoint; - /** * Interface representing a generated API from an OpenAPI specification. * Provides methods to retrieve metadata about the API such as title, version, @@ -58,7 +58,7 @@ public interface GeneratedApi { *

      * * @return a map containing the specification extensions defined in the "info" section of the API, - * where keys are extension names and values are extension values + * where keys are extension names and values are extension values */ Map getApiInfoExtensions(); diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java index ea7bbe63cd..e344a670a7 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java @@ -16,12 +16,12 @@ package org.citrusframework.openapi.testapi; -import static java.util.Collections.emptyList; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import org.citrusframework.exceptions.CitrusRuntimeException; + import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; @@ -36,7 +36,8 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; -import org.citrusframework.exceptions.CitrusRuntimeException; + +import static java.util.Collections.emptyList; class OpenApiParameterFormatter { @@ -53,8 +54,8 @@ private OpenApiParameterFormatter() { /** * Formats a list of values as a single String based on the separator and other settings. */ - static String formatArray(String parameterName, Object parameterValue , ParameterStyle parameterStyle, - boolean explode, boolean isObject) { + static String formatArray(String parameterName, Object parameterValue, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { List values = toList(parameterValue, isObject); if (parameterStyle == ParameterStyle.DEEPOBJECT) { @@ -62,36 +63,36 @@ static String formatArray(String parameterName, Object parameterValue , Paramete } FormatParameters formatParameters = determineFormatParameters(parameterName, parameterStyle, explode, - isObject); + isObject); if (isObject && explode) { return formatParameters.prefix + explode(values, formatParameters.separator); } else { return formatParameters.prefix + values.stream() - .collect(Collectors.joining(formatParameters.separator)); + .collect(Collectors.joining(formatParameters.separator)); } } private static String formatDeepObject(String parameterName, List values) { StringBuilder builder = new StringBuilder(); - for (int i=0;i matrixFormatParameters(parameterName, explode, isObject); @@ -106,9 +107,9 @@ private static FormatParameters formFormatParameters(String parameterName, boole if (isObject) { return new FormatParameters("", "&"); } - return new FormatParameters(parameterName+"=", "&"+parameterName+"="); + return new FormatParameters(parameterName + "=", "&" + parameterName + "="); } else { - return new FormatParameters(parameterName+"=", ","); + return new FormatParameters(parameterName + "=", ","); } } @@ -136,8 +137,8 @@ private static FormatParameters matrixFormatParameters(String parameterName, boo private static String explode(List values, String delimiter) { return IntStream.range(0, values.size() / 2) - .mapToObj(i -> values.get(2 * i) + "=" + values.get(2 * i + 1)) - .collect(Collectors.joining(delimiter)); + .mapToObj(i -> values.get(2 * i) + "=" + values.get(2 * i + 1)) + .collect(Collectors.joining(delimiter)); } private static List toList(Object value, boolean isObject) { @@ -158,8 +159,8 @@ private static List toList(Object value, boolean isObject) { return list.stream().map(Object::toString).toList(); } else if (value instanceof Map map) { return map.entrySet().stream() - .flatMap(entry -> Stream.of(entry.getKey().toString(), entry.getValue().toString())) - .toList(); + .flatMap(entry -> Stream.of(entry.getKey().toString(), entry.getValue().toString())) + .toList(); } else if (isObject && value instanceof String jsonString) { return toList(convertJsonToMap(jsonString), true); } else if (isObject) { @@ -194,7 +195,7 @@ private static Map convertNodeToMap(ObjectNode objectNode) { if (valueNode.isObject() || valueNode.isArray()) { throw new IllegalArgumentException( - "Nested objects or arrays are not allowed in the JSON."); + "Nested objects or arrays are not allowed in the JSON."); } resultMap.put(field.getKey(), valueNode.asText()); } @@ -206,7 +207,7 @@ protected static Map convertBeanToMap(Object bean) { Map map = new TreeMap<>(); try { for (PropertyDescriptor propertyDescriptor : Introspector.getBeanInfo( - bean.getClass(), Object.class).getPropertyDescriptors()) { + bean.getClass(), Object.class).getPropertyDescriptors()) { String propertyName = propertyDescriptor.getName(); Object propertyValue = propertyDescriptor.getReadMethod().invoke(bean); if (propertyValue != null) { diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java index a87cdb3525..e531aa3d55 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java @@ -16,14 +16,15 @@ package org.citrusframework.openapi.testapi; -import java.util.List; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiSpecificationSource; import org.citrusframework.openapi.util.OpenApiUtils; +import java.util.List; + public class RestApiReceiveMessageActionBuilder extends - org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder { + org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder { private final GeneratedApi generatedApi; @@ -31,10 +32,10 @@ public class RestApiReceiveMessageActionBuilder extends public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, - String method, String path, String operationName, String statusCode) { + String method, String path, String operationName, String statusCode) { super(new OpenApiSpecificationSource(openApiSpec), - OpenApiUtils.createFullPathOperationIdentifier(method, path), statusCode); + OpenApiUtils.createFullPathOperationIdentifier(method, path), statusCode); this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); @@ -45,12 +46,12 @@ public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpec } public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, - OpenApiSpecification openApiSpec, - OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage httpMessage, String method, - String path, String operationName) { + OpenApiSpecification openApiSpec, + OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage httpMessage, String method, + String path, String operationName) { super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, - OpenApiUtils.createFullPathOperationIdentifier(method, path)); + OpenApiUtils.createFullPathOperationIdentifier(method, path)); this.generatedApi = generatedApi; diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java index 02b9ba53cd..24e5ab726c 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java @@ -16,17 +16,7 @@ package org.citrusframework.openapi.testapi; -import static java.lang.String.format; - import jakarta.servlet.http.Cookie; -import java.lang.reflect.Array; -import java.net.URLEncoder; -import java.util.Base64; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.BiConsumer; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -43,40 +33,51 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import java.lang.reflect.Array; +import java.net.URLEncoder; +import java.util.Base64; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +import static java.lang.String.format; + public class RestApiSendMessageActionBuilder extends - org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder { + org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder { private final GeneratedApi generatedApi; - private final List customizers; + private final List customizers; private final MultiValueMap formParameters = new LinkedMultiValueMap<>(); public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, - OpenApiSpecification openApiSpec, - String method, String path, String operationName) { + OpenApiSpecification openApiSpec, + String method, String path, String operationName) { this(generatedApi, openApiSpec, new HttpMessage(), method, path, operationName); } public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, - OpenApiSpecification openApiSpec, - HttpMessage httpMessage, String method, - String path, String operationName) { + OpenApiSpecification openApiSpec, + HttpMessage httpMessage, String method, + String path, String operationName) { this(generatedApi, openApiSpec, - new TestApiClientRequestMessageBuilder(httpMessage, - new OpenApiSpecificationSource(openApiSpec), - OpenApiUtils.createFullPathOperationIdentifier(method, path)), httpMessage, method, path, - operationName); + new TestApiClientRequestMessageBuilder(httpMessage, + new OpenApiSpecificationSource(openApiSpec), + OpenApiUtils.createFullPathOperationIdentifier(method, path)), httpMessage, method, path, + operationName); } public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, - OpenApiSpecification openApiSpec, - TestApiClientRequestMessageBuilder messageBuilder, HttpMessage httpMessage, String method, - String path, String operationName) { + OpenApiSpecification openApiSpec, + TestApiClientRequestMessageBuilder messageBuilder, HttpMessage httpMessage, String method, + String path, String operationName) { super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, - OpenApiUtils.createFullPathOperationIdentifier(method, path)); + OpenApiUtils.createFullPathOperationIdentifier(method, path)); this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); @@ -85,7 +86,7 @@ public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, httpMessage.path(path); name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - operationName)); + operationName)); getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); getMessageBuilderSupport().header("citrus_open_api_method", method); getMessageBuilderSupport().header("citrus_open_api_path", path); @@ -106,10 +107,10 @@ public final HttpClientRequestActionBuilder name(String name) { } protected void pathParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { + boolean explode, boolean isObject) { ((TestApiClientRequestMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).pathParameter( - name, value, parameterStyle, explode, isObject); + name, value, parameterStyle, explode, isObject); } @@ -133,11 +134,11 @@ protected void queryParameter(final String name, Object value) { } setParameter((paramName, paramValue) -> super.queryParam(paramName, - paramValue != null ? paramValue.toString() : null), name, value); + paramValue != null ? paramValue.toString() : null), name, value); } protected void queryParameter(final String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { + boolean explode, boolean isObject) { if (value == null || StringUtils.isEmpty(value.toString())) { return; @@ -158,12 +159,12 @@ protected void headerParameter(String name, Object value) { } setParameter( - (paramName, paramValue) -> getMessageBuilderSupport().header(paramName, paramValue), - name, value); + (paramName, paramValue) -> getMessageBuilderSupport().header(paramName, paramValue), + name, value); } protected void headerParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { + boolean explode, boolean isObject) { if (value == null || StringUtils.isEmpty(value.toString())) { return; @@ -179,12 +180,12 @@ protected void cookieParameter(String name, Object value) { } setParameter((paramName, paramValue) -> getMessageBuilderSupport().cookie( - (new Cookie(paramName, paramValue != null ? paramValue.toString() : null))), name, - value); + (new Cookie(paramName, paramValue != null ? paramValue.toString() : null))), name, + value); } protected void cookieParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { + boolean explode, boolean isObject) { if (value == null || StringUtils.isEmpty(value.toString())) { return; @@ -199,7 +200,7 @@ protected void cookieParameter(String name, Object value, ParameterStyle paramet } private void setParameter(BiConsumer parameterConsumer, - final String parameterName, Object parameterValue) { + final String parameterName, Object parameterValue) { if (parameterValue != null) { if (byte[].class.isAssignableFrom(parameterValue.getClass())) { // Pass through byte array @@ -212,7 +213,7 @@ private void setParameter(BiConsumer parameterConsumer, } } else if (parameterValue instanceof Collection collection) { collection.forEach( - singleValue -> parameterConsumer.accept(parameterName, singleValue)); + singleValue -> parameterConsumer.accept(parameterName, singleValue)); } else { parameterConsumer.accept(parameterName, parameterValue); } @@ -229,59 +230,6 @@ public SendMessageAction doBuild() { return super.doBuild(); } - public static final class TestApiClientRequestMessageBuilder extends - OpenApiClientRequestMessageBuilder { - - private final Map pathParameters = new HashMap<>(); - - public TestApiClientRequestMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { - super(httpMessage, openApiSpec, operationId); - } - - public void pathParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - - if (value == null) { - throw new CitrusRuntimeException( - "Mandatory path parameter '%s' must not be null".formatted(name)); - } - pathParameters.put(name, - new ParameterData(name, value, parameterStyle, explode, isObject)); - } - - @Override - protected String getDefinedPathParameter(TestContext context, String name) { - ParameterData parameterData = pathParameters.get(name); - String formatted = name; - if (parameterData != null) { - formatted = OpenApiParameterFormatter.formatArray(name, parameterData.value, parameterData.parameterStyle, - parameterData.explode, parameterData.isObject); - } - - return context.replaceDynamicContentInString(formatted); - } - - @Override - public Message build(TestContext context, String messageType) { - HttpMessage message = (HttpMessage) super.build(context, messageType); - encodeArrayStyleCookies(message); - return message; - } - - private static void encodeArrayStyleCookies(HttpMessage message) { - if (message.getCookies() != null && !message.getCookies().isEmpty()) { - for (Cookie cookie : message.getCookies()) { - if (cookie.getValue().contains(",")) { - cookie.setValue( - URLEncoder.encode(cookie.getValue(), FileUtils.getDefaultCharset())); - } - } - } - } - } - protected byte[] toBinary(Object object) { if (object instanceof byte[] bytes) { return bytes; @@ -303,8 +251,8 @@ protected byte[] toBinary(Object object) { } throw new IllegalArgumentException( - "Cannot convert object to byte array. Only byte[], Resource, and String are supported: " - + object.getClass()); + "Cannot convert object to byte array. Only byte[], Resource, and String are supported: " + + object.getClass()); } protected String getOrDefault(String value, String defaultValue, boolean base64Encode) { @@ -324,6 +272,59 @@ protected String getOrDefault(String value, String defaultValue, boolean base64E return value; } + public static final class TestApiClientRequestMessageBuilder extends + OpenApiClientRequestMessageBuilder { + + private final Map pathParameters = new HashMap<>(); + + public TestApiClientRequestMessageBuilder(HttpMessage httpMessage, + OpenApiSpecificationSource openApiSpec, + String operationId) { + super(httpMessage, openApiSpec, operationId); + } + + private static void encodeArrayStyleCookies(HttpMessage message) { + if (message.getCookies() != null && !message.getCookies().isEmpty()) { + for (Cookie cookie : message.getCookies()) { + if (cookie.getValue().contains(",")) { + cookie.setValue( + URLEncoder.encode(cookie.getValue(), FileUtils.getDefaultCharset())); + } + } + } + } + + public void pathParameter(String name, Object value, ParameterStyle parameterStyle, + boolean explode, boolean isObject) { + + if (value == null) { + throw new CitrusRuntimeException( + "Mandatory path parameter '%s' must not be null".formatted(name)); + } + pathParameters.put(name, + new ParameterData(name, value, parameterStyle, explode, isObject)); + } + + @Override + protected String getDefinedPathParameter(TestContext context, String name) { + ParameterData parameterData = pathParameters.get(name); + String formatted = name; + if (parameterData != null) { + formatted = OpenApiParameterFormatter.formatArray(name, parameterData.value, parameterData.parameterStyle, + parameterData.explode, parameterData.isObject); + } + + return context.replaceDynamicContentInString(formatted); + } + + @Override + public Message build(TestContext context, String messageType) { + HttpMessage message = (HttpMessage) super.build(context, messageType); + encodeArrayStyleCookies(message); + return message; + } + } + public record ParameterData(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java index cabbd162c7..f3024a09fc 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java @@ -16,14 +16,15 @@ package org.citrusframework.openapi.testapi; -import java.util.List; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; -public class SoapApiReceiveMessageActionBuilder extends ReceiveSoapMessageAction.Builder { +import java.util.List; + +public class SoapApiReceiveMessageActionBuilder extends ReceiveSoapMessageAction.Builder { private final GeneratedApi generatedApi; - private final List customizers; + private final List customizers; public SoapApiReceiveMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { @@ -34,7 +35,7 @@ public SoapApiReceiveMessageActionBuilder(GeneratedApi generatedApi, String soap endpoint(generatedApi.getEndpoint()); name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - soapAction)); + soapAction)); } public GeneratedApi getGeneratedApi() { diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java index cd69a5c7f7..97313fc0a4 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java @@ -16,14 +16,15 @@ package org.citrusframework.openapi.testapi; -import java.util.List; import org.citrusframework.ws.actions.SendSoapMessageAction.Builder; +import java.util.List; + public class SoapApiSendMessageActionBuilder extends Builder { private final GeneratedApi generatedApi; - private final List customizers; + private final List customizers; public SoapApiSendMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { @@ -34,7 +35,7 @@ public SoapApiSendMessageActionBuilder(GeneratedApi generatedApi, String soapAct endpoint(generatedApi.getEndpoint()); name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - soapAction)); + soapAction)); } public GeneratedApi getGeneratedApi() { diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java index a726e23cad..9f2170d1e5 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java @@ -28,7 +28,7 @@ private TestApiUtils() { public static void addBasicAuthHeader(String username, String password, HttpMessageBuilderSupport messageBuilderSupport) { if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) { messageBuilderSupport.header("Authorization", - "Basic citrus:encodeBase64(" + username + ":" + password + ")"); + "Basic citrus:encodeBase64(" + username + ":" + password + ")"); } } diff --git a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java index ab19fbf7a4..c8f08ff37f 100644 --- a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java +++ b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java @@ -1,15 +1,5 @@ package org.citrusframework.openapi.testapi; -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.openapi.testapi.OpenApiParameterFormatter.formatArray; -import static org.citrusframework.openapi.testapi.ParameterStyle.DEEPOBJECT; -import static org.citrusframework.openapi.testapi.ParameterStyle.FORM; -import static org.citrusframework.openapi.testapi.ParameterStyle.LABEL; -import static org.citrusframework.openapi.testapi.ParameterStyle.MATRIX; -import static org.citrusframework.openapi.testapi.ParameterStyle.SIMPLE; - -import java.util.List; -import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -19,39 +9,50 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.util.List; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.openapi.testapi.OpenApiParameterFormatter.formatArray; +import static org.citrusframework.openapi.testapi.ParameterStyle.DEEPOBJECT; +import static org.citrusframework.openapi.testapi.ParameterStyle.FORM; +import static org.citrusframework.openapi.testapi.ParameterStyle.LABEL; +import static org.citrusframework.openapi.testapi.ParameterStyle.MATRIX; +import static org.citrusframework.openapi.testapi.ParameterStyle.SIMPLE; + class OpenApiParameterFormatterTest { private static final User USER = User.user().role("admin").firstName("Alex").build(); - private static final List LIST = List.of(3,4,5); + private static final List LIST = List.of(3, 4, 5); private static final Integer SINGLE = 5; static Stream format() { return Stream.of( - Arguments.arguments("Simple/non exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, false, false), "5"), - Arguments.arguments("Simple/non exploded/non object/array", new ParameterData("id", LIST, SIMPLE, false, false), "3,4,5"), - Arguments.arguments("Simple/non exploded/Object/single", new ParameterData("id", USER, SIMPLE, false, true) , "firstName,Alex,role,admin"), - Arguments.arguments("Simple/exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, true, false), "5"), - Arguments.arguments("Simple/exploded/non object/array", new ParameterData("id", LIST, SIMPLE, true, false), "3,4,5"), - Arguments.arguments("Simple/exploded/Object/single", new ParameterData("id", USER, SIMPLE, true, true) , "firstName=Alex,role=admin"), - Arguments.arguments("Label/non exploded/non object/single", new ParameterData("id", SINGLE, LABEL, false, false), ".5"), - Arguments.arguments("Label/non exploded/non object/array", new ParameterData("id", LIST, LABEL, false, false), ".3,4,5"), - Arguments.arguments("Label/non exploded/Object/single", new ParameterData("id", USER, LABEL, false, true) , ".firstName,Alex,role,admin"), - Arguments.arguments("Label/exploded/non object/single", new ParameterData("id", SINGLE, LABEL, true, false), ".5"), - Arguments.arguments("Label/exploded/non object/array", new ParameterData("id", LIST, LABEL, true, false), ".3.4.5"), - Arguments.arguments("Label/exploded/Object/single", new ParameterData("id", USER, LABEL, true, true) , ".firstName=Alex.role=admin"), - Arguments.arguments("Matrix/non exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, false, false), ";id=5"), - Arguments.arguments("Matrix/non exploded/non object/array", new ParameterData("id", LIST, MATRIX, false, false), ";id=3,4,5"), - Arguments.arguments("Matrix/non exploded/Object/single", new ParameterData("id", USER, MATRIX, false, true) , ";id=firstName,Alex,role,admin"), - Arguments.arguments("Matrix/exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, true, false), ";id=5"), - Arguments.arguments("Matrix/exploded/non object/array", new ParameterData("id", LIST, MATRIX, true, false), ";id=3;id=4;id=5"), - Arguments.arguments("Matrix/exploded/Object/single", new ParameterData("id", USER, MATRIX, true, true) , ";firstName=Alex;role=admin"), - Arguments.arguments("Form/non exploded/non object/single", new ParameterData("id", SINGLE, FORM, false, false) , "id=5"), - Arguments.arguments("Form/non exploded/non object/array", new ParameterData("id", LIST, FORM, false, false) , "id=3,4,5"), - Arguments.arguments("Form/non exploded/object/single", new ParameterData("id", USER, FORM, false, true) , "id=firstName,Alex,role,admin"), - Arguments.arguments("Form/exploded/non object/single", new ParameterData("id", SINGLE, FORM, true, false) , "id=5"), - Arguments.arguments("Form/exploded/non object/array", new ParameterData("id", LIST, FORM, true, false) , "id=3&id=4&id=5"), - Arguments.arguments("Form/exploded/object/single", new ParameterData("id", USER, FORM, true, true) , "firstName=Alex&role=admin"), - Arguments.arguments("DeepObject/exploded/object/single", new ParameterData("id", USER, DEEPOBJECT, true, true) , "id[firstName]=Alex&id[role]=admin") + Arguments.arguments("Simple/non exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, false, false), "5"), + Arguments.arguments("Simple/non exploded/non object/array", new ParameterData("id", LIST, SIMPLE, false, false), "3,4,5"), + Arguments.arguments("Simple/non exploded/Object/single", new ParameterData("id", USER, SIMPLE, false, true), "firstName,Alex,role,admin"), + Arguments.arguments("Simple/exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, true, false), "5"), + Arguments.arguments("Simple/exploded/non object/array", new ParameterData("id", LIST, SIMPLE, true, false), "3,4,5"), + Arguments.arguments("Simple/exploded/Object/single", new ParameterData("id", USER, SIMPLE, true, true), "firstName=Alex,role=admin"), + Arguments.arguments("Label/non exploded/non object/single", new ParameterData("id", SINGLE, LABEL, false, false), ".5"), + Arguments.arguments("Label/non exploded/non object/array", new ParameterData("id", LIST, LABEL, false, false), ".3,4,5"), + Arguments.arguments("Label/non exploded/Object/single", new ParameterData("id", USER, LABEL, false, true), ".firstName,Alex,role,admin"), + Arguments.arguments("Label/exploded/non object/single", new ParameterData("id", SINGLE, LABEL, true, false), ".5"), + Arguments.arguments("Label/exploded/non object/array", new ParameterData("id", LIST, LABEL, true, false), ".3.4.5"), + Arguments.arguments("Label/exploded/Object/single", new ParameterData("id", USER, LABEL, true, true), ".firstName=Alex.role=admin"), + Arguments.arguments("Matrix/non exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, false, false), ";id=5"), + Arguments.arguments("Matrix/non exploded/non object/array", new ParameterData("id", LIST, MATRIX, false, false), ";id=3,4,5"), + Arguments.arguments("Matrix/non exploded/Object/single", new ParameterData("id", USER, MATRIX, false, true), ";id=firstName,Alex,role,admin"), + Arguments.arguments("Matrix/exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, true, false), ";id=5"), + Arguments.arguments("Matrix/exploded/non object/array", new ParameterData("id", LIST, MATRIX, true, false), ";id=3;id=4;id=5"), + Arguments.arguments("Matrix/exploded/Object/single", new ParameterData("id", USER, MATRIX, true, true), ";firstName=Alex;role=admin"), + Arguments.arguments("Form/non exploded/non object/single", new ParameterData("id", SINGLE, FORM, false, false), "id=5"), + Arguments.arguments("Form/non exploded/non object/array", new ParameterData("id", LIST, FORM, false, false), "id=3,4,5"), + Arguments.arguments("Form/non exploded/object/single", new ParameterData("id", USER, FORM, false, true), "id=firstName,Alex,role,admin"), + Arguments.arguments("Form/exploded/non object/single", new ParameterData("id", SINGLE, FORM, true, false), "id=5"), + Arguments.arguments("Form/exploded/non object/array", new ParameterData("id", LIST, FORM, true, false), "id=3&id=4&id=5"), + Arguments.arguments("Form/exploded/object/single", new ParameterData("id", USER, FORM, true, true), "firstName=Alex&role=admin"), + Arguments.arguments("DeepObject/exploded/object/single", new ParameterData("id", USER, DEEPOBJECT, true, true), "id[firstName]=Alex&id[role]=admin") ); } @@ -59,7 +60,7 @@ static Stream format() { @MethodSource void format(String name, ParameterData parameterData, String expected) { assertThat(formatArray(parameterData.name(), parameterData.value(), parameterData.parameterStyle(), parameterData.explode(), - parameterData.isObject())).isEqualTo(expected); + parameterData.isObject())).isEqualTo(expected); } @Getter diff --git a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java index 660130ba12..79d7ae2abe 100644 --- a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java +++ b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/TestApiUtilsTest.java @@ -1,13 +1,13 @@ package org.citrusframework.openapi.testapi; +import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; +import org.junit.jupiter.api.Test; + import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.junit.jupiter.api.Test; - class TestApiUtilsTest { @Test diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java index 50ae1d21b9..f3f685ca46 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java @@ -16,17 +16,6 @@ package org.citrusframework.openapi.generator; -import static java.lang.Boolean.TRUE; -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toMap; -import static org.citrusframework.util.ReflectionHelper.copyFields; -import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; -import static org.citrusframework.util.StringUtils.titleCase; -import static org.openapitools.codegen.CliOption.newString; -import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; -import static org.openapitools.codegen.utils.StringUtils.camelize; - import io.swagger.v3.core.util.Yaml; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -35,15 +24,6 @@ import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.servers.Server; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; import lombok.Getter; import lombok.Setter; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -63,17 +43,34 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; + +import static java.lang.Boolean.TRUE; +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toMap; +import static org.citrusframework.util.ReflectionHelper.copyFields; +import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; +import static org.citrusframework.util.StringUtils.titleCase; +import static org.openapitools.codegen.CliOption.newString; +import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; +import static org.openapitools.codegen.utils.StringUtils.camelize; + @Getter @Setter public class CitrusJavaCodegen extends AbstractJavaCodegen { - private static final Logger logger = LoggerFactory.getLogger(CitrusJavaCodegen.class); - public static final String CODEGEN_NAME = "java-citrus"; - public static final String API_TYPE_REST = "REST"; public static final String API_TYPE_SOAP = "SOAP"; - public static final String API_ENDPOINT = "apiEndpoint"; public static final String API_TYPE = "apiType"; public static final String GENERATED_SCHEMA_FOLDER = "generatedSchemaFolder"; @@ -85,13 +82,13 @@ public class CitrusJavaCodegen extends AbstractJavaCodegen { public static final String RESPONSE_BUILDER_CLASS = "responseBuilderClass"; public static final String REQUEST_BUILDER_CLASS_NAME = "requestBuilderClassName"; public static final String RESPONSE_BUILDER_CLASS_NAME = "responseBuilderClassName"; - + private static final Logger logger = LoggerFactory.getLogger(CitrusJavaCodegen.class); protected String apiPrefix = "Api"; protected String httpClient = API_ENDPOINT; protected String resourceFolder = - "src" + File.separator + "main" + File.separator + "resources"; + "src" + File.separator + "main" + File.separator + "resources"; protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; protected String targetXmlnsNamespace; @@ -111,6 +108,31 @@ public CitrusJavaCodegen() { configureTypeMappings(); } + private static void postProcessSecurityParameters( + CustomCodegenOperation customCodegenOperation) { + customCodegenOperation.hasApiKeyAuth = customCodegenOperation.authMethods.stream() + .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); + + customCodegenOperation.authWithParameters = customCodegenOperation.hasApiKeyAuth; + for (CodegenSecurity codegenSecurity : customCodegenOperation.authMethods) { + if (TRUE.equals(codegenSecurity.isBasicBasic)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthUsername"); + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthPassword"); + customCodegenOperation.authWithParameters = true; + } else if (TRUE.equals(codegenSecurity.isApiKey)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); + customCodegenOperation.authWithParameters = true; + } else if (TRUE.equals(codegenSecurity.isBasicBearer)) { + customCodegenOperation.optionalAndAuthParameterNames.add( + "basicAuthBearer"); + customCodegenOperation.authWithParameters = true; + } + } + } + private void configureAdditionalProperties() { additionalProperties.put("apiVersion", apiVersion); additionalProperties.put(API_TYPE, API_TYPE_REST); @@ -120,51 +142,51 @@ private void configureAdditionalProperties() { private void configureReservedWords() { Set reservedWordsTemp = reservedWords(); reservedWordsTemp.addAll( - asList( - "name", - "description", - "httpClient", - "message", - "endpoint", - "validate", - "validator", - "validators", - "process", - "selector", - "transform", - "build", - "actor", - "process") + asList( + "name", + "description", + "httpClient", + "message", + "endpoint", + "validate", + "validator", + "validators", + "process", + "selector", + "transform", + "build", + "actor", + "process") ); setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); } private void configureCliOptions() { cliOptions.add( - newString(API_ENDPOINT, - "Which http client should be used (default " + httpClient + ").")); + newString(API_ENDPOINT, + "Which http client should be used (default " + httpClient + ").")); cliOptions.add( - newString(API_TYPE, - "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" - ) + newString(API_TYPE, + "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" + ) ); cliOptions.add( - newString(GENERATED_SCHEMA_FOLDER, - "The schema output directory (default " + generatedSchemaFolder + ").") + newString(GENERATED_SCHEMA_FOLDER, + "The schema output directory (default " + generatedSchemaFolder + ").") ); cliOptions.add( - newString(PREFIX, - "Add a prefix before the name of the files. First character should be upper case (default " - + apiPrefix + ")." - ) + newString(PREFIX, + "Add a prefix before the name of the files. First character should be upper case (default " + + apiPrefix + ")." + ) ); cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); cliOptions.add( - newString(RESOURCE_FOLDER, - "Where the resource files are emitted (default " + resourceFolder + ").")); + newString(RESOURCE_FOLDER, + "Where the resource files are emitted (default " + resourceFolder + ").")); cliOptions.add( - newString(TARGET_XMLNS_NAMESPACE, - "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") + newString(TARGET_XMLNS_NAMESPACE, + "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") ); } @@ -232,8 +254,8 @@ private void setupApiPrefix() { additionalProperties.put(PREFIX + "LowerCase", apiPrefix.toLowerCase()); } else { logger.warn( - "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", - PREFIX); + "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", + PREFIX); apiPrefix = ""; } } @@ -241,11 +263,11 @@ private void setupApiPrefix() { private void setupNamespace() { if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { this.setTargetXmlnsNamespace( - additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); + additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); } else { this.targetXmlnsNamespace = format( - "http://www.citrusframework.org/citrus-test-schema/%s-api", - apiPrefix.toLowerCase()); + "http://www.citrusframework.org/citrus-test-schema/%s-api", + apiPrefix.toLowerCase()); } additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); } @@ -253,7 +275,7 @@ private void setupNamespace() { private void setupFolders() { if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { this.setGeneratedSchemaFolder( - additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); + additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); } additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); @@ -263,7 +285,7 @@ private void setupFolders() { additionalProperties.put(RESOURCE_FOLDER, resourceFolder); invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", - File.separator); + File.separator); springFolder = invokerFolder + File.separator + "spring"; schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; } @@ -281,13 +303,13 @@ private void setupApiType() { private void setupSoapApiType(String springFolder, String schemaFolder) { additionalProperties.put(REQUEST_BUILDER_CLASS, - SoapApiSendMessageActionBuilder.class.getName()); + SoapApiSendMessageActionBuilder.class.getName()); additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, - SoapApiSendMessageActionBuilder.class.getSimpleName()); + SoapApiSendMessageActionBuilder.class.getSimpleName()); additionalProperties.put(RESPONSE_BUILDER_CLASS, - SoapApiReceiveMessageActionBuilder.class.getName()); + SoapApiReceiveMessageActionBuilder.class.getName()); additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, - SoapApiReceiveMessageActionBuilder.class.getSimpleName()); + SoapApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", false); additionalProperties.put("isSoap", true); addSoapSupportingFiles(springFolder, schemaFolder); @@ -295,13 +317,13 @@ private void setupSoapApiType(String springFolder, String schemaFolder) { private void setupRestApiType(String springFolder, String schemaFolder) { additionalProperties.put(REQUEST_BUILDER_CLASS, - RestApiSendMessageActionBuilder.class.getName()); + RestApiSendMessageActionBuilder.class.getName()); additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, - RestApiSendMessageActionBuilder.class.getSimpleName()); + RestApiSendMessageActionBuilder.class.getSimpleName()); additionalProperties.put(RESPONSE_BUILDER_CLASS, - RestApiReceiveMessageActionBuilder.class.getName()); + RestApiReceiveMessageActionBuilder.class.getName()); additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, - RestApiReceiveMessageActionBuilder.class.getSimpleName()); + RestApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", true); additionalProperties.put("isSoap", false); @@ -315,7 +337,7 @@ private void writeApiToResourceFolder() { String directoryPath = appendSegmentToUrlPath(getOutputDir(), getResourceFolder()); directoryPath = appendSegmentToUrlPath(directoryPath, - invokerPackage.replace('.', File.separatorChar)); + invokerPackage.replace('.', File.separatorChar)); String filename = getApiPrefix() + "_openApi.yaml"; @@ -331,7 +353,7 @@ private void writeApiToResourceFolder() { writer.write(yamlContent); } catch (IOException e) { throw new CitrusRuntimeException( - "Unable to write OpenAPI to resource folder: " + file.getAbsolutePath()); + "Unable to write OpenAPI to resource folder: " + file.getAbsolutePath()); } } @@ -345,19 +367,19 @@ public void preprocessOpenAPI(OpenAPI openAPI) { additionalProperties.putAll(extensions); Map infoExtensions = extensions.entrySet().stream() - .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) - .collect(toMap(Entry::getKey, Entry::getValue)); + .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) + .collect(toMap(Entry::getKey, Entry::getValue)); additionalProperties.put("infoExtensions", infoExtensions); } } private void addRestSupportingFiles(String springFolder, - String schemaFolder) { + String schemaFolder) { supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder, - titleCase(apiPrefix) + "NamespaceHandler.java")); + titleCase(apiPrefix) + "NamespaceHandler.java")); supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); + apiPrefix.toLowerCase() + "-api.xsd")); } private void addSoapSupportingFiles(String springFolder, String schemaFolder) { @@ -366,28 +388,28 @@ private void addSoapSupportingFiles(String springFolder, String schemaFolder) { apiTemplateFiles().put("api_soap.mustache", ".java"); supportingFiles.add(new SupportingFile("namespace_handler_soap.mustache", springFolder, - titleCase(apiPrefix) + "NamespaceHandler.java")); + titleCase(apiPrefix) + "NamespaceHandler.java")); supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); + apiPrefix.toLowerCase() + "-api.xsd")); } private void addDefaultSupportingFiles() { supportingFiles.add(new SupportingFile("api_locator.mustache", invokerFolder, - titleCase(apiPrefix) + ".java")); + titleCase(apiPrefix) + ".java")); supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, - titleCase(apiPrefix) + "BeanConfiguration.java")); + titleCase(apiPrefix) + "BeanConfiguration.java")); } @Override public CodegenParameter fromRequestBody(RequestBody body, Set imports, - String bodyParameterName) { + String bodyParameterName) { CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); return convertToCustomCodegenParameter(codegenParameter); } @Override public CodegenParameter fromFormProperty(String name, Schema propertySchema, - Set imports) { + Set imports) { CodegenParameter codegenParameter = super.fromFormProperty(name, propertySchema, imports); return convertToCustomCodegenParameter(codegenParameter); } @@ -408,21 +430,21 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) * additional derived properties. */ private CustomCodegenParameter convertToCustomCodegenParameter( - CodegenParameter codegenParameter) { + CodegenParameter codegenParameter) { CustomCodegenParameter customCodegenParameter = new CustomCodegenParameter(); copyFields(CodegenParameter.class, codegenParameter, customCodegenParameter); customCodegenParameter.isBaseTypeString = codegenParameter.isString || "String".equals( - codegenParameter.baseType); + codegenParameter.baseType); return customCodegenParameter; } @Override public CodegenOperation fromOperation(String path, - String httpMethod, - Operation operation, - List servers) { + String httpMethod, + Operation operation, + List servers) { CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); return convertToCustomCodegenOperation(op); @@ -433,29 +455,29 @@ public CodegenOperation fromOperation(String path, * additional derived properties. */ private CustomCodegenOperation convertToCustomCodegenOperation( - CodegenOperation codegenOperation) { + CodegenOperation codegenOperation) { CustomCodegenOperation customOperation = new CustomCodegenOperation(); copyFields(CodegenOperation.class, codegenOperation, customOperation); customOperation.requiredNonBodyParams.addAll(customOperation.requiredParams - .stream() - .filter(param -> !param.isBodyParam).toList()); + .stream() + .filter(param -> !param.isBodyParam).toList()); customOperation.needsConstructorWithAllStringParameter = - !customOperation.requiredParams.isEmpty() && - customOperation.requiredParams - .stream() - .anyMatch( - param -> !param.isBodyParam && !"String".equals(param.dataType)); + !customOperation.requiredParams.isEmpty() && + customOperation.requiredParams + .stream() + .anyMatch( + param -> !param.isBodyParam && !"String".equals(param.dataType)); if (customOperation.optionalParams != null) { customOperation.optionalAndAuthParameterNames.addAll( - customOperation.optionalParams.stream() - .map(codegenParameter -> - toVarName(codegenParameter.nameInCamelCase)) - .toList()); + customOperation.optionalParams.stream() + .map(codegenParameter -> + toVarName(codegenParameter.nameInCamelCase)) + .toList()); } return customOperation; @@ -463,7 +485,7 @@ private CustomCodegenOperation convertToCustomCodegenOperation( @Override public OperationsMap postProcessOperationsWithModels(OperationsMap objs, - List allModels) { + List allModels) { OperationsMap operationsMap = super.postProcessOperationsWithModels(objs, allModels); OperationMap operations = objs.getOperations(); @@ -471,7 +493,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, if (operationList != null) { operationList.forEach(codegenOperation -> { if (codegenOperation instanceof CustomCodegenOperation customCodegenOperation - && customCodegenOperation.authMethods != null) { + && customCodegenOperation.authMethods != null) { postProcessSecurityParameters(customCodegenOperation); } }); @@ -480,31 +502,6 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, return operationsMap; } - private static void postProcessSecurityParameters( - CustomCodegenOperation customCodegenOperation) { - customCodegenOperation.hasApiKeyAuth = customCodegenOperation.authMethods.stream() - .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); - - customCodegenOperation.authWithParameters = customCodegenOperation.hasApiKeyAuth; - for (CodegenSecurity codegenSecurity : customCodegenOperation.authMethods) { - if (TRUE.equals(codegenSecurity.isBasicBasic)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthUsername"); - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthPassword"); - customCodegenOperation.authWithParameters = true; - } else if (TRUE.equals(codegenSecurity.isApiKey)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); - customCodegenOperation.authWithParameters = true; - } else if (TRUE.equals(codegenSecurity.isBasicBearer)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthBearer"); - customCodegenOperation.authWithParameters = true; - } - } - } - static class CustomCodegenOperation extends CodegenOperation { private final List requiredNonBodyParams; @@ -539,17 +536,17 @@ public boolean equals(Object o) { } CustomCodegenOperation that = (CustomCodegenOperation) o; return needsConstructorWithAllStringParameter - == that.needsConstructorWithAllStringParameter - && hasApiKeyAuth == that.hasApiKeyAuth && Objects.equals(requiredNonBodyParams, - that.requiredNonBodyParams) && Objects.equals(optionalAndAuthParameterNames, - that.optionalAndAuthParameterNames); + == that.needsConstructorWithAllStringParameter + && hasApiKeyAuth == that.hasApiKeyAuth && Objects.equals(requiredNonBodyParams, + that.requiredNonBodyParams) && Objects.equals(optionalAndAuthParameterNames, + that.optionalAndAuthParameterNames); } @Override public int hashCode() { return Objects.hash(super.hashCode(), requiredNonBodyParams, - optionalAndAuthParameterNames, - needsConstructorWithAllStringParameter, hasApiKeyAuth); + optionalAndAuthParameterNames, + needsConstructorWithAllStringParameter, hasApiKeyAuth); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java index db0be8bfe2..74dd5890a4 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java @@ -16,10 +16,6 @@ package org.citrusframework.openapi.generator; -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY; -import static java.lang.String.format; - import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; import io.swagger.v3.oas.models.OpenAPI; @@ -30,11 +26,11 @@ import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; -import java.net.URI; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; +import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; + import javax.wsdl.Binding; import javax.wsdl.BindingOperation; import javax.wsdl.Definition; @@ -43,10 +39,15 @@ import javax.wsdl.factory.WSDLFactory; import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; -import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; +import java.net.URI; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY; +import static java.lang.String.format; /** * Transforms a WSDL specification into a simple OpenAPI specification for usage with the OpenApiGenerator. @@ -94,16 +95,15 @@ * @see javax.wsdl.Definition * @see javax.wsdl.Binding * @see javax.wsdl.BindingOperation - * */ public class WsdlToOpenApiTransformer { private static final Logger logger = LoggerFactory.getLogger(WsdlToOpenApiTransformer.class); private static final YAMLMapper yamlMapper = (YAMLMapper) YAMLMapper.builder() - .enable(SORT_PROPERTIES_ALPHABETICALLY) - .build() - .setSerializationInclusion(NON_NULL); + .enable(SORT_PROPERTIES_ALPHABETICALLY) + .build() + .setSerializationInclusion(NON_NULL); private final URI wsdlUri; @@ -170,10 +170,10 @@ private Info createInfo() { info.setTitle("Generated api from wsdl"); info.setDescription( - format( - "This api has been generated from the following wsdl '%s'. It's purpose is solely to serve as input for SOAP API generation. Note that only operations are extracted from the WSDL. No schema information whatsoever is generated!", - java.nio.file.Paths.get(wsdlUri).getFileName() - ) + format( + "This api has been generated from the following wsdl '%s'. It's purpose is solely to serve as input for SOAP API generation. Note that only operations are extracted from the WSDL. No schema information whatsoever is generated!", + java.nio.file.Paths.get(wsdlUri).getFileName() + ) ); info.setVersion("1.0.0"); @@ -197,11 +197,11 @@ private void addOperations(OpenAPI openApi, QName qName, Binding binding) { for (Object operation : bindingOperations) { if (operation instanceof BindingOperation bindingOperation) { addOperation( - openApi.getPaths(), - bindingOperation.getName(), - retrieveOperationDescription(bindingOperation), - retrieveSoapAction(bindingOperation), - bindingApiName + openApi.getPaths(), + bindingOperation.getName(), + retrieveOperationDescription(bindingOperation), + retrieveSoapAction(bindingOperation), + bindingApiName ); } } @@ -236,18 +236,18 @@ private String retrieveOperationDescription(BindingOperation bindingOperation) { javax.wsdl.Operation soapOperation = bindingOperation.getOperation(); Element documentationElement = bindingOperation.getDocumentationElement(); if (documentationElement != null) { - String documentationText = documentationElement.getTextContent().trim(); - description.append(format("%s",documentationText)); + String documentationText = documentationElement.getTextContent().trim(); + description.append(format("%s", documentationText)); } if (soapOperation != null) { documentationElement = soapOperation.getDocumentationElement(); if (documentationElement != null) { - String documentationText = documentationElement.getTextContent().trim(); + String documentationText = documentationElement.getTextContent().trim(); if (!description.isEmpty()) { description.append(" "); } - description.append(format("%s",documentationText)); + description.append(format("%s", documentationText)); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java index 07eb532c9b..80a05bf60b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java @@ -1,20 +1,11 @@ package org.citrusframework.openapi.generator; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; - import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.servers.Server; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenOperation; import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenParameter; import org.junit.jupiter.api.BeforeEach; @@ -25,6 +16,16 @@ import org.openapitools.codegen.CodegenParameter; import org.openapitools.codegen.CodegenProperty; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; + /** * This test validates the code generation process. */ @@ -69,23 +70,23 @@ void testGetHelp() { @Test void testAdditionalPropertiesConfiguration() { assertThat(codegen.additionalProperties()) - .containsEntry("apiVersion", "1.0.0") - .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST) - .containsEntry("useJakartaEe", true); + .containsEntry("apiVersion", "1.0.0") + .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST) + .containsEntry("useJakartaEe", true); } @Test void testReservedWordsConfiguration() { assertThat(codegen.reservedWords()) - .contains("name", "description", "httpclient") - .doesNotContain("nonReservedWord"); + .contains("name", "description", "httpclient") + .doesNotContain("nonReservedWord"); } @Test void testTypeMappings() { assertThat(codegen.typeMapping()) - .containsEntry("binary", "Resource") - .containsEntry("file", "Resource"); + .containsEntry("binary", "Resource") + .containsEntry("file", "Resource"); } @Test @@ -93,8 +94,8 @@ void testProcessOptsWithApiType() { codegen.additionalProperties().put(CitrusJavaCodegen.API_TYPE, "XXX"); assertThatThrownBy(() -> codegen.processOpts()) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("Unknown API_TYPE: 'XXX'"); + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Unknown API_TYPE: 'XXX'"); } @Test @@ -103,7 +104,7 @@ void testProcessOptsValidApiType() { codegen.processOpts(); assertThat(codegen.additionalProperties()) - .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST); + .containsEntry(CitrusJavaCodegen.API_TYPE, CitrusJavaCodegen.API_TYPE_REST); } @Test @@ -119,9 +120,9 @@ void testPreprocessOpenAPI() { codegen.preprocessOpenAPI(openAPI); assertThat(codegen.additionalProperties()) - .containsEntry("x-api-owner", "citrus-framework") - .containsEntry("x-api-version", "2.0.0") - .containsEntry("infoExtensions", extensions); + .containsEntry("x-api-owner", "citrus-framework") + .containsEntry("x-api-version", "2.0.0") + .containsEntry("infoExtensions", extensions); } @Test @@ -132,9 +133,9 @@ void testFromProperty() { // Call fromProperty and verify conversion CodegenProperty codegenProperty = codegen.fromProperty("name", schema, true); assertThat(codegenProperty) - .isInstanceOf(CodegenProperty.class) - .hasFieldOrPropertyWithValue("name", "_name") - .hasFieldOrPropertyWithValue("required", true); + .isInstanceOf(CodegenProperty.class) + .hasFieldOrPropertyWithValue("name", "_name") + .hasFieldOrPropertyWithValue("required", true); } @Test @@ -146,8 +147,8 @@ void testFromFormProperty() { CodegenParameter codegenParameter = codegen.fromFormProperty("formParam", schema, imports); assertThat(codegenParameter) - .isInstanceOf(CustomCodegenParameter.class) - .hasFieldOrPropertyWithValue("paramName", "formParam"); + .isInstanceOf(CustomCodegenParameter.class) + .hasFieldOrPropertyWithValue("paramName", "formParam"); } @Test @@ -159,7 +160,7 @@ void testFromParameter() { CodegenParameter codegenParameter = codegen.fromParameter(parameter, imports); assertThat(codegenParameter) - .isInstanceOf(CustomCodegenParameter.class); + .isInstanceOf(CustomCodegenParameter.class); } @Test @@ -169,9 +170,9 @@ void testFromOperation() { CodegenOperation codegenOperation = codegen.fromOperation("/path", "GET", operation, servers); assertThat(codegenOperation) - .isInstanceOf(CustomCodegenOperation.class) - .hasFieldOrPropertyWithValue("httpMethod", "GET") - .hasFieldOrPropertyWithValue("path", "/path"); + .isInstanceOf(CustomCodegenOperation.class) + .hasFieldOrPropertyWithValue("httpMethod", "GET") + .hasFieldOrPropertyWithValue("path", "/path"); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java index 1af4ffa9f6..4283d057b2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java @@ -1,16 +1,5 @@ package org.citrusframework.openapi.generator; -import static java.nio.file.Files.readString; -import static java.nio.file.Files.walk; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.stream.Stream; import org.apache.commons.lang3.stream.Streams; import org.citrusframework.exceptions.CitrusRuntimeException; import org.junit.jupiter.api.Test; @@ -21,6 +10,18 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; + +import static java.nio.file.Files.readString; +import static java.nio.file.Files.walk; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * This test case is designed to validate the consistency of the code generation process and detect * any discrepancies between the generated API files and the reference files stored in @@ -38,21 +39,65 @@ class ExpectedCodeGenIT { public static final String BASE_PACKAGE = "org/citrusframework/openapi/generator"; + static Stream getResourcesForRest() throws IOException { + return geClassResourcesIgnoringInnerClasses(BASE_PACKAGE + "/rest"); + } + + static Stream getResourcesForSoap() throws IOException { + return geClassResourcesIgnoringInnerClasses( + BASE_PACKAGE + "/soap/bookservice"); + } + + private static Stream geClassResourcesIgnoringInnerClasses(String path) + throws IOException { + return Streams.of( + new PathMatchingResourcePatternResolver().getResources(path + "/**/*.class")) + .filter(resource -> { + try { + return !resource.getURI().toString().contains("$"); + } catch (Exception e) { + throw new CitrusRuntimeException("Unable to retrieve URL from resource!"); + } + } + ).map(Arguments::arguments); + } + + private static long countFilesRecursively(Path dir) throws IOException { + try (Stream walk = walk(dir)) { + return walk.filter(Files::isRegularFile).count(); + } + } + + /** + * Get the absolute path to the test resources directory. + */ + static String getAbsoluteTestResourcePath(String pathToFileInTestResources) { + URL resourceUrl = CitrusJavaCodegenTest.class.getClassLoader().getResource(pathToFileInTestResources); + assert resourceUrl != null; + File inputSpecFile = new File(resourceUrl.getFile()); + return inputSpecFile.getAbsolutePath(); + } + + /** + * Get the absolute path to the project's target directory. + */ + static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { + String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project + File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); + return outputDirFile.getAbsolutePath(); + } + @Test void noAdditionalFiles() throws IOException { long expectedFileCount = countFilesRecursively( - Path.of(getAbsoluteTestResourcePath( - BASE_PACKAGE + "/ExpectedCodeGenIT/expectedgen/rest"))); + Path.of(getAbsoluteTestResourcePath( + BASE_PACKAGE + "/ExpectedCodeGenIT/expectedgen/rest"))); long actualFileCount = countFilesRecursively( - Path.of(getAbsoluteTargetDirectoryPath( - "generated-test-sources/" + BASE_PACKAGE + "/rest"))); + Path.of(getAbsoluteTargetDirectoryPath( + "generated-test-sources/" + BASE_PACKAGE + "/rest"))); assertEquals(expectedFileCount, actualFileCount, - "Directories do not have the same number of files."); - } - - static Stream getResourcesForRest() throws IOException { - return geClassResourcesIgnoringInnerClasses(BASE_PACKAGE + "/rest"); + "Directories do not have the same number of files."); } @ParameterizedTest @@ -61,17 +106,12 @@ void testGeneratedFiles(Resource resource) throws IOException { File classFile = resource.getFile(); String absolutePath = classFile.getAbsolutePath(); String javaFilePath = absolutePath - .replace("test-classes", "generated-test-sources") - .replace(".class", ".java"); + .replace("test-classes", "generated-test-sources") + .replace(".class", ".java"); assertFileContent(new File(javaFilePath), "rest"); } - static Stream getResourcesForSoap() throws IOException { - return geClassResourcesIgnoringInnerClasses( - BASE_PACKAGE + "/soap/bookservice"); - } - @ParameterizedTest @MethodSource("getResourcesForSoap") void testGeneratedSoapFiles(Resource resource) throws IOException { @@ -79,26 +119,12 @@ void testGeneratedSoapFiles(Resource resource) throws IOException { String absolutePath = classFile.getAbsolutePath(); String javaFilePath = absolutePath - .replace("test-classes", "generated-test-sources") - .replace(".class", ".java"); + .replace("test-classes", "generated-test-sources") + .replace(".class", ".java"); assertFileContent(new File(javaFilePath), "soap"); } - private static Stream geClassResourcesIgnoringInnerClasses(String path) - throws IOException { - return Streams.of( - new PathMatchingResourcePatternResolver().getResources(path + "/**/*.class")) - .filter(resource -> { - try { - return !resource.getURI().toString().contains("$"); - } catch (Exception e) { - throw new CitrusRuntimeException("Unable to retrieve URL from resource!"); - } - } - ).map(Arguments::arguments); - } - /* * NOTE: when changes have been performed to mustache templates, the expected files need to be updated. * Be aware that file content may change according to IDE formatting rules if the files are copied via IDE. @@ -122,29 +148,4 @@ private void assertFileContent(File file, String apiDir) throws IOException { assertThat(actualContent).isEqualTo(expectedContent); } - - private static long countFilesRecursively(Path dir) throws IOException { - try (Stream walk = walk(dir)) { - return walk.filter(Files::isRegularFile).count(); - } - } - - /** - * Get the absolute path to the test resources directory. - */ - static String getAbsoluteTestResourcePath(String pathToFileInTestResources) { - URL resourceUrl = CitrusJavaCodegenTest.class.getClassLoader().getResource(pathToFileInTestResources); - assert resourceUrl != null; - File inputSpecFile = new File(resourceUrl.getFile()); - return inputSpecFile.getAbsolutePath(); - } - - /** - * Get the absolute path to the project's target directory. - */ - static String getAbsoluteTargetDirectoryPath(String pathToFileInTargetDirectory) { - String projectBaseDir = System.getProperty("user.dir"); // Base directory of the project - File outputDirFile = new File(projectBaseDir, "target/" + pathToFileInTargetDirectory); - return outputDirFile.getAbsolutePath(); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java index 7124bb9536..fc762dca65 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -1,20 +1,6 @@ package org.citrusframework.openapi.generator; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.http.actions.HttpActionBuilder.http; -import static org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMap; -import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; -import static org.springframework.http.HttpStatus.OK; - import jakarta.servlet.http.Cookie; -import java.io.IOException; -import java.math.BigDecimal; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; -import java.util.List; -import java.util.Map; import org.assertj.core.api.Assertions; import org.citrusframework.TestActor; import org.citrusframework.TestCaseRunner; @@ -62,6 +48,21 @@ import org.springframework.context.annotation.Bean; import org.springframework.http.HttpStatus; +import java.io.IOException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMap; +import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; +import static org.springframework.http.HttpStatus.OK; + /** * This integration test class for the generated TestAPI aims to comprehensively test all aspects of * accessing the API using both Java and XML. In addition to serving as a test suite, it also acts @@ -74,14 +75,14 @@ @ExtendWith(CitrusSpringExtension.class) @SpringBootTest(classes = {PetStoreBeanConfiguration.class, ExtPetStoreBeanConfiguration.class, - CitrusSpringConfig.class, Config.class}, properties = { - "extpetstore.basic.username=extUser", - "extpetstore.basic.password=extPassword", - "extpetstore.bearer.token=defaultBearerToken", - "extpetstore.api-key-query=defaultTopSecretQueryApiKey", - "extpetstore.api-key-header=defaultTopSecretHeaderApiKey", - "extpetstore.api-key-cookie=defaultTopSecretCookieApiKey", - "extpetstore.base64-encode-api-key=true" + CitrusSpringConfig.class, Config.class}, properties = { + "extpetstore.basic.username=extUser", + "extpetstore.basic.password=extPassword", + "extpetstore.bearer.token=defaultBearerToken", + "extpetstore.api-key-query=defaultTopSecretQueryApiKey", + "extpetstore.api-key-header=defaultTopSecretHeaderApiKey", + "extpetstore.api-key-cookie=defaultTopSecretCookieApiKey", + "extpetstore.base64-encode-api-key=true" } ) class GeneratedRestApiIT { @@ -89,12 +90,12 @@ class GeneratedRestApiIT { public static final List PET_ID_LIST = List.of(1, 2); public static final List PET_ID_AS_STRING_LIST = List.of("1", "2"); public static final List PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST = List.of("${one}", - "${two}"); + "${two}"); public static final PetIdentifier PET_IDENTIFIER = new PetIdentifier()._name("Louis") - .alias("Alexander"); + .alias("Alexander"); public static final String PET_IDENTIFIER_AS_STRING = """ - {"alias":"Alexander","name":"Louis"}"""; + {"alias":"Alexander","name":"Louis"}"""; @Autowired private HttpServer httpServer; @@ -114,6 +115,117 @@ class GeneratedRestApiIT { @Autowired private HttpClient otherApplicationServiceClient; + @TestConfiguration + public static class Config { + + private final int port = SocketUtils.findAvailableTcpPort(8080); + + private final int otherPort = SocketUtils.findAvailableTcpPort(8081); + + private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + + /** + * Main http client for accessing the main http server. + */ + @Bean(name = {"petstore.endpoint", "extpetstore.endpoint"}) + public HttpClient applicationServiceClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .handleCookies(true) + .build(); + } + + /** + * Http client accessing "other" server, see configuration of other server bean below. + */ + @Bean + public HttpClient otherApplicationServiceClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(otherPort)) + .build(); + } + + /** + * A sample actor used to test actor configuration and functionality. + */ + @Bean + public TestActor petStoreActor() { + TestActor petStoreActor = new TestActor(); + petStoreActor.setName("PetStoreActor"); + petStoreActor.setDisabled(true); + return petStoreActor; + } + + /** + * Http server for mocking server side messaging and asserting data being send from test api + * requests. + */ + @Bean + public HttpServer httpServer() { + return new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .handleCookies(true) + .handleHandleSemicolonPathContent(true) + .build(); + } + + @Bean + public WebServiceServer soapServer() { + return WebServiceEndpoints.soap().server() + .port(wsPort) + .timeout(5000) + .autoStart(true) + .build(); + } + + /** + * A second http server. Mainly for tests that assert, that the default endpoint + * configuration can be overridden by an explicit endpoint. + */ + @Bean + public HttpServer otherHttpServer() { + return new HttpServerBuilder() + .port(otherPort) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + } + + /* + * Global variables, that make the ports available within the test context. Mainly + * used to access to port for explicit endpoint configuration tests. + */ + @Bean + public GlobalVariables globalVariables() { + return new GlobalVariables.Builder() + .variable("petstoreApplicationPort", port) + .variable("otherPetstoreApplicationPort", otherPort).build(); + } + +// @Bean +// public ApiActionBuilderCustomizer petApiCustomizer() { +// return new ApiActionBuilderCustomizer() { +// @Override +// public T customizeRequestBuilder( +// GeneratedApi generatedApi, T builder) { +// return ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApi, +// builder); +// } +// +// @Override +// public T customizeResponseBuilder( +// GeneratedApi generatedApi, T builder) { +// return ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApi, +// builder); +// } +// }; +// } + } + /** * Demonstrates usage of parameter serialization according to * ... @@ -134,19 +246,19 @@ class Array { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleArray(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/1") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); @@ -156,19 +268,19 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleArray(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); @@ -178,19 +290,19 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleArray$(PET_ID_AS_STRING_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); @@ -198,26 +310,26 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithSimpleStyleArray$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + extPetApi.sendGetPetWithSimpleStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); @@ -229,21 +341,21 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObject( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); } @@ -254,20 +366,20 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObject$(PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/object/alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); } @@ -282,18 +394,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(extPetApi.sendGetPetWithSimpleStyleArrayExploded(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/exploded/1") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/exploded/1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); @@ -304,18 +416,18 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(extPetApi.sendGetPetWithSimpleStyleArrayExploded(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/exploded/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); @@ -325,20 +437,20 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when( - extPetApi.sendGetPetWithSimpleStyleArrayExploded$(PET_ID_AS_STRING_LIST) - .fork(true)); + extPetApi.sendGetPetWithSimpleStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/exploded/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); @@ -346,26 +458,26 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithSimpleStyleArrayExploded$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + extPetApi.sendGetPetWithSimpleStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/simple/exploded/1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/simple/exploded/1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); @@ -377,22 +489,22 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); } @@ -403,22 +515,22 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/simple/exploded/object/alias=Alexander,name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); } @@ -439,17 +551,17 @@ class Array { */ @Test void throws_request_validation_exception( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { HttpClientRequestActionBuilder builder = extPetApi.sendGetPetWithLabelStyleArray( - PET_ID_LIST) - .fork(false); + PET_ID_LIST) + .fork(false); assertThatThrownBy(() -> runner.when(builder)) - .isInstanceOf(TestCaseFailedException.class) - .hasCauseInstanceOf(ValidationException.class) - .hasMessageContaining( - "ERROR - Instance type (string) does not match any allowed primitive type (allowed: [\"integer\"]): []"); + .isInstanceOf(TestCaseFailedException.class) + .hasCauseInstanceOf(ValidationException.class) + .hasMessageContaining( + "ERROR - Instance type (string) does not match any allowed primitive type (allowed: [\"integer\"]): []"); } @Test @@ -458,20 +570,20 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray(List.of(1)) - .schemaValidation(true) - .fork(true)); + .schemaValidation(true) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/.1") - .message()); + .receive() + .get("/api/v3/ext/pet/label/.1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); @@ -483,20 +595,20 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray(PET_ID_LIST) - .schemaValidation(false) - .fork(true)); + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/.1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); @@ -508,20 +620,20 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray$(PET_ID_AS_STRING_LIST) - .schemaValidation(false) - .fork(true)); + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/.1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); @@ -529,29 +641,29 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when( - extPetApi.sendGetPetWithLabelStyleArray$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .schemaValidation(false) - .fork(true)); + extPetApi.sendGetPetWithLabelStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/.1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/.1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); @@ -563,21 +675,21 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObject( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); } @@ -588,22 +700,22 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObject$(""" - {"name":"Louis","alias":"Alexander"} - """) - .schemaValidation(false) - .fork(true)); + {"name":"Louis","alias":"Alexander"} + """) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/label/object/.alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); } @@ -617,18 +729,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(extPetApi.sendGetPetWithLabelStyleArrayExploded(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/exploded/.1") - .message()); + .receive() + .get("/api/v3/ext/pet/label/exploded/.1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); @@ -639,18 +751,18 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(extPetApi.sendGetPetWithLabelStyleArrayExploded(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/exploded/.1.2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); @@ -660,20 +772,20 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when( - extPetApi.sendGetPetWithLabelStyleArrayExploded$(PET_ID_AS_STRING_LIST) - .fork(true)); + extPetApi.sendGetPetWithLabelStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/exploded/.1.2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); @@ -681,26 +793,26 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithLabelStyleArrayExploded$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + extPetApi.sendGetPetWithLabelStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/label/exploded/.1.2") - .message()); + .receive() + .get("/api/v3/ext/pet/label/exploded/.1.2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); @@ -712,23 +824,23 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded$(""" - {"name":"Louis","alias":"Alexander"} - """) - .schemaValidation(false) - .fork(true)); + {"name":"Louis","alias":"Alexander"} + """) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); } @@ -739,22 +851,22 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/label/exploded/object/.alias=Alexander.name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); } @@ -772,19 +884,19 @@ class Array { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithMatrixStyleArray(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/;petId=1") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); @@ -794,19 +906,19 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithMatrixStyleArray(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/;petId=1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); @@ -816,19 +928,19 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithMatrixStyleArray$(PET_ID_AS_STRING_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/;petId=1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); @@ -836,26 +948,26 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithMatrixStyleArray$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + extPetApi.sendGetPetWithMatrixStyleArray$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/;petId=1,2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/;petId=1,2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); @@ -867,21 +979,21 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObject( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } @@ -892,21 +1004,21 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObject$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/object/;petId=alias,Alexander,name,Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } @@ -920,18 +1032,18 @@ class ExplodedArray { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/exploded/;petId=1") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); @@ -941,18 +1053,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); @@ -962,20 +1074,20 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when( - extPetApi.sendGetPetWithMatrixStyleArrayExploded$(PET_ID_AS_STRING_LIST) - .fork(true)); + extPetApi.sendGetPetWithMatrixStyleArrayExploded$(PET_ID_AS_STRING_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); @@ -983,27 +1095,27 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithMatrixStyleArrayExploded$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + extPetApi.sendGetPetWithMatrixStyleArrayExploded$( + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") - .message()); + .receive() + .get("/api/v3/ext/pet/matrix/exploded/;petId=1;petId=2") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); @@ -1015,22 +1127,22 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } @@ -1041,22 +1153,22 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get( - "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") - .message()); + .receive() + .get( + "/api/v3/ext/pet/matrix/exploded/object/;alias=Alexander;name=Louis") + .message()); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK) + .message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } @@ -1079,18 +1191,18 @@ class Array { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple") - .message().header("petId", "1")); + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); @@ -1100,18 +1212,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); @@ -1121,19 +1233,19 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$( - PET_ID_AS_STRING_LIST) - .fork(true)); + PET_ID_AS_STRING_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); @@ -1141,25 +1253,25 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); @@ -1171,20 +1283,20 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithSimpleStyleObjectHeader( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithSimpleStyleObjectHeader( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/object") - .message().header("petId", "alias,Alexander,name,Louis")); + .receive() + .get("/api/v3/ext/pet/header/simple/object") + .message().header("petId", "alias,Alexander,name,Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); } @@ -1195,20 +1307,20 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithSimpleStyleObjectHeader$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithSimpleStyleObjectHeader$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/object") - .message().header("petId", "alias,Alexander,name,Louis")); + .receive() + .get("/api/v3/ext/pet/header/simple/object") + .message().header("petId", "alias,Alexander,name,Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); } @@ -1222,18 +1334,18 @@ class ArrayExploded { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded") - .message().header("petId", "1")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); @@ -1243,18 +1355,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); @@ -1264,19 +1376,19 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( - PET_ID_AS_STRING_LIST) - .fork(true)); + PET_ID_AS_STRING_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); @@ -1284,25 +1396,25 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded") - .message().header("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded") + .message().header("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); @@ -1314,23 +1426,23 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithSimpleStyleExplodedObjectHeader( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithSimpleStyleExplodedObjectHeader( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded/object") - .message().header("petId", "alias=Alexander,name=Louis")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded/object") + .message().header("petId", "alias=Alexander,name=Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when( - extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); + extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); } @Test @@ -1339,23 +1451,23 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithSimpleStyleExplodedObjectHeader$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithSimpleStyleExplodedObjectHeader$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/header/simple/exploded/object") - .message().header("petId", "alias=Alexander,name=Louis")); + .receive() + .get("/api/v3/ext/pet/header/simple/exploded/object") + .message().header("petId", "alias=Alexander,name=Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when( - extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); + extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); } } @@ -1376,18 +1488,18 @@ class Array { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleQuery(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form") - .message().queryParam("petId", "1")); + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1397,18 +1509,18 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_arrya_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleQuery(PET_ID_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form") - .message().queryParam("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @@ -1417,43 +1529,43 @@ void java_arrya_value(@CitrusResource TestCaseRunner runner) { void java_arrya_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleQuery$(PET_ID_AS_STRING_LIST) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form") - .message().queryParam("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @Test void java_arrya_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when(extPetApi.sendGetPetWithFormStyleQuery$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form") - .message().queryParam("petId", "1,2")); + .receive() + .get("/api/v3/ext/pet/query/form") + .message().queryParam("petId", "1,2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @@ -1464,20 +1576,20 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithFormStyleObjectQuery( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithFormStyleObjectQuery( + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/object") - .message().queryParam("petId", "alias,Alexander,name,Louis")); + .receive() + .get("/api/v3/ext/pet/query/form/object") + .message().queryParam("petId", "alias,Alexander,name,Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); } @@ -1488,20 +1600,20 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi - .sendGetPetWithFormStyleObjectQuery$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + .sendGetPetWithFormStyleObjectQuery$( + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/object") - .message().queryParam("petId", "alias,Alexander,name,Louis")); + .receive() + .get("/api/v3/ext/pet/query/form/object") + .message().queryParam("petId", "alias,Alexander,name,Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); } @@ -1514,18 +1626,18 @@ class ArrayExploded { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded") - .message().queryParam("petId", "1")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message().queryParam("petId", "1")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1535,22 +1647,22 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(PET_ID_LIST) - .fork(true)); + .fork(true)); // Note that citrus currently fails to validate a query parameter array. Thus, we // assert against the query_params header. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded") - .message() - .queryParam("petId", "1") - .queryParam("petId", "2")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @@ -1559,52 +1671,52 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when( - extPetApi.sendGetPetWithFormStyleExplodedQuery$(PET_ID_AS_STRING_LIST) - .fork(true)); + extPetApi.sendGetPetWithFormStyleExplodedQuery$(PET_ID_AS_STRING_LIST) + .fork(true)); // Note that citrus currently fails to validate a query parameter array. Thus, we // assert against the query_params header. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded") - .message() - .queryParam("petId", "1") - .queryParam("petId", "2")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); // Note that citrus currently fails to validate a query parameter array. Thus, we // assert against the query_params header. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded") - .message() - .queryParam("petId", "1") - .queryParam("petId", "2")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded") + .message() + .queryParam("petId", "1") + .queryParam("petId", "2")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @@ -1613,21 +1725,21 @@ void java_array_value_non_type_safe_with_variables( void java_object_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi - .sendGetPetWithFormStyleExplodedObjectQuery( - PET_IDENTIFIER) - .fork(true)); + .sendGetPetWithFormStyleExplodedObjectQuery( + PET_IDENTIFIER) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded/object") - .message() - .queryParam("alias", "Alexander") - .queryParam("name", "Louis")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded/object") + .message() + .queryParam("alias", "Alexander") + .queryParam("name", "Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); } @@ -1636,21 +1748,21 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi - .sendGetPetWithFormStyleExplodedObjectQuery$( - PET_IDENTIFIER_AS_STRING) - .fork(true)); + .sendGetPetWithFormStyleExplodedObjectQuery$( + PET_IDENTIFIER_AS_STRING) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/form/exploded/object") - .message() - .queryParam("alias", "Alexander") - .queryParam("name", "Louis")); + .receive() + .get("/api/v3/ext/pet/query/form/exploded/object") + .message() + .queryParam("alias", "Alexander") + .queryParam("name", "Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); } @@ -1667,21 +1779,21 @@ class ArrayExploded { void java_object_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi - .sendGetPetWithDeepObjectTypeQuery( - PET_IDENTIFIER) - .fork(true)); + .sendGetPetWithDeepObjectTypeQuery( + PET_IDENTIFIER) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/deep/object") - .message() - .queryParam("petId[alias]", "Alexander") - .queryParam("petId[name]", "Louis")); + .receive() + .get("/api/v3/ext/pet/query/deep/object") + .message() + .queryParam("petId[alias]", "Alexander") + .queryParam("petId[name]", "Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); } @@ -1690,21 +1802,21 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi - .sendGetPetWithDeepObjectTypeQuery$( - PET_IDENTIFIER_AS_STRING) - .fork(true)); + .sendGetPetWithDeepObjectTypeQuery$( + PET_IDENTIFIER_AS_STRING) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/query/deep/object") - .message() - .queryParam("petId[alias]", "Alexander") - .queryParam("petId[name]", "Louis")); + .receive() + .get("/api/v3/ext/pet/query/deep/object") + .message() + .queryParam("petId[alias]", "Alexander") + .queryParam("petId[name]", "Louis")); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); } @@ -1725,18 +1837,18 @@ class Array { void java_single_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleCookie(List.of(1)) - .fork(true)); + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form") - .message().cookie(new Cookie("petId", "1"))); + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1746,20 +1858,20 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { void java_array_value(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleCookie(PET_ID_LIST) - .fork(true)); + .fork(true)); // Cookies may not contain "," which is used to separate array values. // Therefore, cookies are URL encoded and reach the server accordingly. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form") - .message().cookie(new Cookie("petId", "1%2C2"))); + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1769,20 +1881,20 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi.sendGetPetWithFormStyleCookie$(PET_ID_AS_STRING_LIST) - .fork(true)); + .fork(true)); // Cookies may not contain "," which is used to separate array values. // Therefore, cookies are URL encoded and reach the server accordingly. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form") - .message().cookie(new Cookie("petId", "1%2C2"))); + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1790,27 +1902,27 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when(extPetApi.sendGetPetWithFormStyleCookie$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) - .fork(true)); + PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + .fork(true)); // Cookies may not contain "," which is used to separate array values. // Therefore, cookies are URL encoded and reach the server accordingly. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form") - .message().cookie(new Cookie("petId", "1%2C2"))); + .receive() + .get("/api/v3/ext/pet/cookie/form") + .message().cookie(new Cookie("petId", "1%2C2"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1822,23 +1934,23 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie( - PET_IDENTIFIER) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER) + .schemaValidation(false) + .fork(true)); // Cookies may not contain "," which is used to separate array values. // Therefore, cookies are URL encoded and reach the server accordingly. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form/object") - .message() - .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); + .receive() + .get("/api/v3/ext/pet/cookie/form/object") + .message() + .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1850,23 +1962,23 @@ void java_object_value_none_type(@CitrusResource TestCaseRunner runner) { // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie$( - PET_IDENTIFIER_AS_STRING) - .schemaValidation(false) - .fork(true)); + PET_IDENTIFIER_AS_STRING) + .schemaValidation(false) + .fork(true)); // Cookies may not contain "," which is used to separate array values. // Therefore, cookies are URL encoded and reach the server accordingly. runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/cookie/form/object") - .message() - .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); + .receive() + .get("/api/v3/ext/pet/cookie/form/object") + .message() + .cookie(new Cookie("petId", "alias%2CAlexander%2Cname%2CLouis"))); runner.then(http().server(httpServer) - .send() - .response(OK).message() - .contentType("application/json") - .body("[]")); + .send() + .response(OK).message() + .contentType("application/json") + .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); @@ -1894,44 +2006,44 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("tag2", "tag2Value"); runner.when(extPetApi - .sendUpdatePetWithArrayQueryData$("${petId}", "Thunder", "sold", - List.of("tag1", "${tag2}"), - List.of("${nick1}", "${nick2}"), "header1") - .fork(true)); + .sendUpdatePetWithArrayQueryData$("${petId}", "Thunder", "sold", + List.of("tag1", "${tag2}"), + List.of("${nick1}", "${nick2}"), "header1") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/ext/pet/1234") - .message() - .validate(ScriptValidationContext.Builder.groovy().script(""" - assert receivedMessage.getHeader("sampleStringHeader") == header1 - org.assertj.core.api.Assertions.assertThat(((org.citrusframework.http.message.HttpMessage)receivedMessage).getQueryParams()).containsExactlyInAnyOrderEntriesOf( - java.util.Map.of( - "tags", java.util.List.of("tag1", "tag2Value"), - "name", java.util.List.of("Thunder"), - "nicknames", java.util.List.of("Wind", "Storm"), - "status", java.util.List.of("sold") - """)) - .validate((message, context) -> { - assertThat(message.getHeader("sampleStringHeader")).isEqualTo("header1"); - assertThat( - ((HttpMessage) message).getQueryParams()).containsExactlyInAnyOrderEntriesOf( - Map.of( - "tags", List.of("tag1", "tag2Value"), - "name", List.of("Thunder"), - "nicknames", List.of("Wind", "Storm"), - "status", List.of("sold") - ) - ); - })); + .receive() + .put("/api/v3/ext/pet/1234") + .message() + .validate(ScriptValidationContext.Builder.groovy().script(""" + assert receivedMessage.getHeader("sampleStringHeader") == header1 + org.assertj.core.api.Assertions.assertThat(((org.citrusframework.http.message.HttpMessage)receivedMessage).getQueryParams()).containsExactlyInAnyOrderEntriesOf( + java.util.Map.of( + "tags", java.util.List.of("tag1", "tag2Value"), + "name", java.util.List.of("Thunder"), + "nicknames", java.util.List.of("Wind", "Storm"), + "status", java.util.List.of("sold") + """)) + .validate((message, context) -> { + assertThat(message.getHeader("sampleStringHeader")).isEqualTo("header1"); + assertThat( + ((HttpMessage) message).getQueryParams()).containsExactlyInAnyOrderEntriesOf( + Map.of( + "tags", List.of("tag1", "tag2Value"), + "name", List.of("Thunder"), + "nicknames", List.of("Wind", "Storm"), + "status", List.of("sold") + ) + ); + })); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(extPetApi - .receiveUpdatePetWithArrayQueryData(OK) - .message()); + .receiveUpdatePetWithArrayQueryData(OK) + .message()); } } @@ -1953,20 +2065,20 @@ void updatePetWithForm_java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(petApi.sendUpdatePetWithForm$("${petId}") - ._name("Tom") - .status("sold") - .fork(true)); + ._name("Tom") + .status("sold") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .post("/api/v3/pet/${petId}") - .message() - .queryParam("name", "Tom") - .queryParam("status", "sold")); + .receive() + .post("/api/v3/pet/${petId}") + .message() + .queryParam("name", "Tom") + .queryParam("status", "sold")); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); @@ -1993,31 +2105,31 @@ void xml() { @Test void java( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); runner.when(petApi - .receiveGetPetById(OK) - .schemaValidation(false)); + .receiveGetPetById(OK) + .schemaValidation(false)); } } @@ -2046,30 +2158,30 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi - .receiveGetPetById(OK).message().reasonPhrase("Almost OK"); + .receiveGetPetById(OK).message().reasonPhrase("Almost OK"); assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining( - "Values not equal for header element 'citrus_http_reason_phrase', expected 'Almost OK' but was 'OK'") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_reason_phrase', expected 'Almost OK' but was 'OK'") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2090,30 +2202,30 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi - .receiveGetPetById("201"); + .receiveGetPetById("201"); assertThatThrownBy(() -> runner.when(getPetByIdResponseActionBuilder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining( - "Values not equal for header element 'citrus_http_reason_phrase', expected 'CREATED' but was 'OK'") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_reason_phrase', expected 'CREATED' but was 'OK'") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2134,30 +2246,30 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi - .receiveGetPetById(OK).message().version("HTTP/1.0"); + .receiveGetPetById(OK).message().version("HTTP/1.0"); assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining( - "Values not equal for header element 'citrus_http_version', expected 'HTTP/1.0' but was 'HTTP/1.1'") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for header element 'citrus_http_version', expected 'HTTP/1.0' but was 'HTTP/1.1'") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2178,29 +2290,29 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi.receiveGetPetById( - OK); + OK); assertThatThrownBy(() -> runner.when(getPetByIdResponseActionBuilder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining("Object has missing required properties ([\"name\"]): []") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining("Object has missing required properties ([\"name\"]): []") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2222,31 +2334,31 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi - .receiveGetPetById(OK).message().body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json")); + .receiveGetPetById(OK).message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/thisAintNoPed.json")); assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining( - "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining( + "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2268,31 +2380,31 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi - .receiveGetPetById(OK).message().body(""" - {"description": "no pet"}"""); + .receiveGetPetById(OK).message().body(""" + {"description": "no pet"}"""); assertThatThrownBy(() -> runner.when(builder)).isInstanceOf( - TestCaseFailedException.class) - .hasMessageContaining( - "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") - .hasCauseInstanceOf(ValidationException.class); + TestCaseFailedException.class) + .hasMessageContaining( + "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2314,31 +2426,31 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi - .receiveGetPetById(OK).message() - .validate(jsonPath().expression("$.name", "unknown")); + .receiveGetPetById(OK).message() + .validate(jsonPath().expression("$.name", "unknown")); assertThatThrownBy(() -> runner.when(builder)) - .isInstanceOf(TestCaseFailedException.class) - .hasMessageContaining( - "Values not equal for element '$.name', expected 'unknown' but was") - .hasCauseInstanceOf(ValidationException.class); + .isInstanceOf(TestCaseFailedException.class) + .hasMessageContaining( + "Values not equal for element '$.name', expected 'unknown' but was") + .hasCauseInstanceOf(ValidationException.class); } } @@ -2360,21 +2472,21 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .actor(petStoreActor) - .fork(true)); + .sendGetPetById$("${petId}") + .actor(petStoreActor) + .fork(true)); HttpMessageBuilderSupport builder = http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@"); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@"); assertThatThrownBy(() -> runner.$(builder)) - .isInstanceOf(TestCaseFailedException.class) - .hasCauseInstanceOf(MessageTimeoutException.class) - .hasMessageContaining( - "Action timeout after 5000 milliseconds. Failed to receive message on endpoint: 'httpServer.inbound'"); + .isInstanceOf(TestCaseFailedException.class) + .hasCauseInstanceOf(MessageTimeoutException.class) + .hasMessageContaining( + "Action timeout after 5000 milliseconds. Failed to receive message on endpoint: 'httpServer.inbound'"); } } @@ -2394,27 +2506,27 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .uri("http://localhost:${petstoreApplicationPort}") - .fork(true)); + .sendGetPetById$("${petId}") + .uri("http://localhost:${petstoreApplicationPort}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK) - .message() - .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) ); } } @@ -2435,26 +2547,26 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}").endpoint(otherApplicationServiceClient) - .fork(true)); + .sendGetPetById$("${petId}").endpoint(otherApplicationServiceClient) + .fork(true)); runner.then(http().server(otherHttpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(otherHttpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK).endpoint(otherApplicationServiceClient) - .message() - .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) ); } } @@ -2498,26 +2610,26 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") - .fork(true)); + .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-basic/pet/${petId}") - .message() - .header("Authorization", "Basic ZXh0VXNlcjpleHRQYXNzd29yZA==")); + .receive() + .get("/api/v3/ext/secure-basic/pet/${petId}") + .message() + .header("Authorization", "Basic ZXh0VXNlcjpleHRQYXNzd29yZA==")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithBasicAuthentication(OK) - .message()); + .receiveGetPetByIdWithBasicAuthentication(OK) + .message()); } @@ -2536,31 +2648,31 @@ void xml() { @Test void java( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") - .basicAuthUsername("admin") - .basicAuthPassword("topSecret") - .fork(true)); + .sendGetPetByIdWithBasicAuthentication$("${petId}", "true") + .basicAuthUsername("admin") + .basicAuthPassword("topSecret") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-basic/pet/${petId}") - .message().header("Authorization", "Basic YWRtaW46dG9wU2VjcmV0")); + .receive() + .get("/api/v3/ext/secure-basic/pet/${petId}") + .message().header("Authorization", "Basic YWRtaW46dG9wU2VjcmV0")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithBasicAuthentication(OK) - .message()); + .receiveGetPetByIdWithBasicAuthentication(OK) + .message()); } @@ -2583,30 +2695,30 @@ void xml() { @Test void java( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") - .fork(true)); + .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-bearer/pet/${petId}") - .message() - .header("Authorization", "Bearer ZGVmYXVsdEJlYXJlclRva2Vu")); + .receive() + .get("/api/v3/ext/secure-bearer/pet/${petId}") + .message() + .header("Authorization", "Bearer ZGVmYXVsdEJlYXJlclRva2Vu")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithBearerAuthentication(OK) - .message()); + .receiveGetPetByIdWithBearerAuthentication(OK) + .message()); } } @@ -2627,26 +2739,26 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") - .basicAuthBearer("bearerToken") - .fork(true)); + .sendGetPetByIdWithBearerAuthentication$("${petId}", "true") + .basicAuthBearer("bearerToken") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-bearer/pet/${petId}") - .message().header("Authorization", "Bearer YmVhcmVyVG9rZW4=")); + .receive() + .get("/api/v3/ext/secure-bearer/pet/${petId}") + .message().header("Authorization", "Bearer YmVhcmVyVG9rZW4=")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithBearerAuthentication(OK) - .message()); + .receiveGetPetByIdWithBearerAuthentication(OK) + .message()); } @@ -2676,32 +2788,32 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") - .fork(true)); + .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-api-key/pet/${petId}") - .message() - .header("api_key_header", - "citrus:encodeBase64('defaultTopSecretHeaderApiKey')") - .cookie(new Cookie("api_key_cookie", - "citrus:encodeBase64('defaultTopSecretCookieApiKey')")) - .queryParam("api_key_query", - "citrus:encodeBase64('defaultTopSecretQueryApiKey')") - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/ext/secure-api-key/pet/${petId}") + .message() + .header("api_key_header", + "citrus:encodeBase64('defaultTopSecretHeaderApiKey')") + .cookie(new Cookie("api_key_cookie", + "citrus:encodeBase64('defaultTopSecretCookieApiKey')")) + .queryParam("api_key_query", + "citrus:encodeBase64('defaultTopSecretQueryApiKey')") + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithApiKeyAuthentication(OK) - .schemaValidation(false)); + .receiveGetPetByIdWithApiKeyAuthentication(OK) + .schemaValidation(false)); } } @@ -2719,7 +2831,7 @@ void xml() { @Test void java( - @CitrusResource TestCaseRunner runner) { + @CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.variable("apiKeyHeader", "TopSecretHeader"); @@ -2727,33 +2839,33 @@ void java( runner.variable("apiKeyQuery", "TopSecretQuery"); runner.when(extPetApi - .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") - .apiKeyHeader("${apiKeyHeader}") - .apiKeyCookie("${apiKeyCookie}") - .apiKeyQuery("${apiKeyQuery}") - .fork(true)); + .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false") + .apiKeyHeader("${apiKeyHeader}") + .apiKeyCookie("${apiKeyCookie}") + .apiKeyQuery("${apiKeyQuery}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/secure-api-key/pet/${petId}") - .message() - .header("api_key_header", "citrus:encodeBase64('TopSecretHeader')") - .cookie( - new Cookie("api_key_cookie", "citrus:encodeBase64('TopSecretCookie')")) - .queryParam("api_key_query", "citrus:encodeBase64('TopSecretQuery')") - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/ext/secure-api-key/pet/${petId}") + .message() + .header("api_key_header", "citrus:encodeBase64('TopSecretHeader')") + .cookie( + new Cookie("api_key_cookie", "citrus:encodeBase64('TopSecretCookie')")) + .queryParam("api_key_query", "citrus:encodeBase64('TopSecretQuery')") + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetByIdWithApiKeyAuthentication(OK) - .schemaValidation(false)); + .receiveGetPetByIdWithApiKeyAuthentication(OK) + .schemaValidation(false)); } } } @@ -2774,46 +2886,46 @@ void xml() { void java(@CitrusResource TestCaseRunner runner) throws IOException { byte[] templateData = FileUtils.copyToByteArray( - Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin")); + Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin")); String additionalData = FileUtils.readToString(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json")); + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json")); runner.when(extPetApi.sendGenerateVaccinationReport$( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin", - "1") - .additionalData(additionalData) - .optIntVal(100) - .optBoolVal(true) - .optStringVal("a") - .optNumberVal(BigDecimal.valueOf(1L)) - .optDateVal(LocalDate.of(2024, 12, 1)) - .fork(true)); + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin", + "1") + .additionalData(additionalData) + .optIntVal(100) + .optBoolVal(true) + .optStringVal("a") + .optNumberVal(BigDecimal.valueOf(1L)) + .optDateVal(LocalDate.of(2024, 12, 1)) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .post("/api/v3/ext/pet/vaccination/status-report") - .message() - .validate((message, context) -> - Assertions.assertThat(multipartMessageToMap((HttpMessage) message)) - .containsExactlyInAnyOrderEntriesOf(Map.of( - "additionalData", additionalData, - "reqIntVal", "1", - "template", templateData, - "optIntVal", "100", - "optBoolVal", "true", - "optDateVal", "[2024,12,1]", - "optNumberVal", "1", - "optStringVal", "a")) - ) + .receive() + .post("/api/v3/ext/pet/vaccination/status-report") + .message() + .validate((message, context) -> + Assertions.assertThat(multipartMessageToMap((HttpMessage) message)) + .containsExactlyInAnyOrderEntriesOf(Map.of( + "additionalData", additionalData, + "reqIntVal", "1", + "template", templateData, + "optIntVal", "100", + "optBoolVal", "true", + "optDateVal", "[2024,12,1]", + "optNumberVal", "1", + "optStringVal", "a")) + ) ); runner.then(http().server(httpServer) - .send() - .response(OK) - .message().contentType("application/pdf") - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf"))); + .send() + .response(OK) + .message().contentType("application/pdf") + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf"))); runner.then(extPetApi.receiveGenerateVaccinationReport(OK)); } @@ -2836,26 +2948,26 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(petApi.sendUpdatePet() - .message().body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .queryParam("nonApiQueryParam", "nonApiQueryParamValue") - .header("nonApiHeader", "nonApiHeaderValue") - .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) - .fork(true)); + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .queryParam("nonApiQueryParam", "nonApiQueryParamValue") + .header("nonApiHeader", "nonApiHeaderValue") + .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/pet") - .message() - .queryParam("nonApiQueryParam", "nonApiQueryParamValue") - .header("nonApiHeader", "nonApiHeaderValue") - .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + .receive() + .put("/api/v3/pet") + .message() + .queryParam("nonApiQueryParam", "nonApiQueryParamValue") + .header("nonApiHeader", "nonApiHeaderValue") + .cookie(new Cookie("nonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); @@ -2882,42 +2994,42 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("tag2", "tag2Value"); runner.when(extPetApi - .sendUpdatePetWithFormUrlEncoded$("${petId}", "Thunder", "sold", "5", - List.of("tag1", "${tag2}")) - .nicknames( - "${nick1}", - "${nick2}", - URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", - StandardCharsets.UTF_8) - ) - .owners("2") - .fork(true)); + .sendUpdatePetWithFormUrlEncoded$("${petId}", "Thunder", "sold", "5", + List.of("tag1", "${tag2}")) + .nicknames( + "${nick1}", + "${nick2}", + URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", + StandardCharsets.UTF_8) + ) + .owners("2") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/ext/pet/form/1234") - .message() - .contentType("application/x-www-form-urlencoded") - .validate((Message message, TestContext context) -> - assertThat(message.getPayload(String.class)) - .contains("name=Thunder") - .contains("status=sold") - .contains("nicknames=Wind") - .contains("nicknames=Storm") - .contains("tags=tag2") - .contains("tags=tag2Value") - .contains("age=5") - .contains( - "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") - )); + .receive() + .put("/api/v3/ext/pet/form/1234") + .message() + .contentType("application/x-www-form-urlencoded") + .validate((Message message, TestContext context) -> + assertThat(message.getPayload(String.class)) + .contains("name=Thunder") + .contains("status=sold") + .contains("nicknames=Wind") + .contains("nicknames=Storm") + .contains("tags=tag2") + .contains("tags=tag2Value") + .contains("age=5") + .contains( + "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + )); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(extPetApi - .receiveUpdatePetWithFormUrlEncoded(OK) - .message()); + .receiveUpdatePetWithFormUrlEncoded(OK) + .message()); } } @@ -2936,41 +3048,41 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("tag2", "tag2Value"); runner.when(extPetApi - .sendUpdatePetWithFormUrlEncoded(1234L, "Thunder", "sold", 5, - List.of("tag1", "${tag2}")) - .nicknames( - "${nick1}", - "${nick2}", - URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", - StandardCharsets.UTF_8) - ) - .owners("2") - .fork(true)); + .sendUpdatePetWithFormUrlEncoded(1234L, "Thunder", "sold", 5, + List.of("tag1", "${tag2}")) + .nicknames( + "${nick1}", + "${nick2}", + URLEncoder.encode("Wei{:/?#[]@!$&'()*+,;=%\"<>^`{|}~ }rd", + StandardCharsets.UTF_8) + ) + .owners("2") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/ext/pet/form/1234") - .message() - .contentType("application/x-www-form-urlencoded") - .validate((Message message, TestContext context) -> - assertThat(message.getPayload(String.class)) - .contains("name=Thunder") - .contains("status=sold") - .contains("nicknames=Wind") - .contains("nicknames=Storm") - .contains("tags=tag2") - .contains("tags=tag2Value") - .contains("age=5") - .contains( - "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") - )); + .receive() + .put("/api/v3/ext/pet/form/1234") + .message() + .contentType("application/x-www-form-urlencoded") + .validate((Message message, TestContext context) -> + assertThat(message.getPayload(String.class)) + .contains("name=Thunder") + .contains("status=sold") + .contains("nicknames=Wind") + .contains("nicknames=Storm") + .contains("tags=tag2") + .contains("tags=tag2Value") + .contains("age=5") + .contains( + "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + )); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(extPetApi - .receiveUpdatePetWithFormUrlEncoded(OK) - .message()); + .receiveUpdatePetWithFormUrlEncoded(OK) + .message()); } } @@ -2991,37 +3103,37 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(petApi.sendUpdatePet() - .message().body(""" - { - "id": ${petId}, - "name": "citrus:randomEnumValue('hasso','cutie','fluffy')", - "category": { - "id": ${petId}, - "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" - }, - "photoUrls": [ - "http://localhost:8080/photos/${petId}" - ], - "tags": [ - { - "id": ${petId}, - "name": "generated" - } - ], - "status": "citrus:randomEnumValue('available', 'pending', 'sold')" - } - """) - .fork(true)); + .message().body(""" + { + "id": ${petId}, + "name": "citrus:randomEnumValue('hasso','cutie','fluffy')", + "category": { + "id": ${petId}, + "name": "citrus:randomEnumValue('dog', 'cat', 'fish')" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "citrus:randomEnumValue('available', 'pending', 'sold')" + } + """) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/pet") - .message().body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + .receive() + .put("/api/v3/pet") + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); @@ -3044,19 +3156,19 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "citrus:randomNumber(10)"); runner.when(petApi.sendUpdatePet() - .message().body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .fork(true)); + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .put("/api/v3/pet") - .message().body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); + .receive() + .put("/api/v3/pet") + .message().body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json"))); runner.then(http().server(httpServer) - .send() - .response(OK)); + .send() + .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); @@ -3079,46 +3191,46 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK) - .message() - .body(""" - { - "id": ${petId}, - "name": "@matches('hasso|cutie|fluffy')@", - "category": { - "id": ${petId}, - "name": "@matches('dog|cat|fish')@" - }, - "photoUrls": [ - "http://localhost:8080/photos/${petId}" - ], - "tags": [ - { - "id": ${petId}, - "name": "generated" - } - ], - "status": "@matches('available|pending|sold')@" - } - """) + .message() + .body(""" + { + "id": ${petId}, + "name": "@matches('hasso|cutie|fluffy')@", + "category": { + "id": ${petId}, + "name": "@matches('dog|cat|fish')@" + }, + "photoUrls": [ + "http://localhost:8080/photos/${petId}" + ], + "tags": [ + { + "id": ${petId}, + "name": "generated" + } + ], + "status": "@matches('available|pending|sold')@" + } + """) ); } } @@ -3139,28 +3251,28 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json")) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response_validation.json")) ); } } @@ -3181,27 +3293,27 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK) - .message() - .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) + .message() + .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) ); } } @@ -3224,26 +3336,26 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.then(petApi.receiveGetPetById(OK) - .message() - .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) + .message() + .validate(jsonPath().expression("$.name", "@matches('hasso|cutie|fluffy')@")) ); } } @@ -3261,35 +3373,35 @@ void xml() { @Test void java( - @CitrusResource TestCaseRunner runner, @CitrusResource TestContext context) { + @CitrusResource TestCaseRunner runner, @CitrusResource TestContext context) { runner.variable("petId", "1234"); runner.when(petApi - .sendGetPetById$("${petId}") - .fork(true)); + .sendGetPetById$("${petId}") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/pet/${petId}") - .message() - .accept("@contains('application/json')@")); + .receive() + .get("/api/v3/pet/${petId}") + .message() + .accept("@contains('application/json')@")); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(petApi - .receiveGetPetById(OK) - .message() - .extract(MessageHeaderVariableExtractor.Builder.fromHeaders() - .expression("Content-Type", "varContentType")) - .extract(JsonPathVariableExtractor.Builder.fromJsonPath() - .expression("$.name", "varName"))) + .receiveGetPetById(OK) + .message() + .extract(MessageHeaderVariableExtractor.Builder.fromHeaders() + .expression("Content-Type", "varContentType")) + .extract(JsonPathVariableExtractor.Builder.fromJsonPath() + .expression("$.name", "varName"))) ; assertThat(context.getVariable("varContentType")).isEqualTo("application/json"); @@ -3313,29 +3425,29 @@ void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi - .sendGetPetWithCookie$("${petId}", "cookieValue") - .optTrxId("trxId") - .fork(true)); + .sendGetPetWithCookie$("${petId}", "cookieValue") + .optTrxId("trxId") + .fork(true)); runner.then(http().server(httpServer) - .receive() - .get("/api/v3/ext/pet/${petId}") - .message() - .cookie(new Cookie("session_id", "cookieValue")) - .cookie(new Cookie("opt_trx_id", "trxId")) + .receive() + .get("/api/v3/ext/pet/${petId}") + .message() + .cookie(new Cookie("session_id", "cookieValue")) + .cookie(new Cookie("opt_trx_id", "trxId")) ); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(Resources.create( - "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(Resources.create( + "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) + .contentType("application/json")); runner.when(extPetApi - .receiveGetPetWithCookie(OK) - .message()); + .receiveGetPetWithCookie(OK) + .message()); } } @@ -3360,151 +3472,40 @@ void uploadFile_java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi.sendUploadFile$("${petId}") - .additionalMetadata(additionalMetadata) - .message() - .body(file) - .fork(true)); + .additionalMetadata(additionalMetadata) + .message() + .body(file) + .fork(true)); runner.then(http().server(httpServer) - .receive() - .post("/api/v3/pet/${petId}/uploadImage") - .message() - .contentType("application/octet-stream") - .queryParam("additionalMetadata", "myMeta") - .validate((message, context) -> { - Object payload = message.getPayload(); - assertThat(payload).isInstanceOf(byte[].class); - assertThat(new String((byte[]) payload, StandardCharsets.UTF_8)).isEqualTo( - "filedata"); - }) + .receive() + .post("/api/v3/pet/${petId}/uploadImage") + .message() + .contentType("application/octet-stream") + .queryParam("additionalMetadata", "myMeta") + .validate((message, context) -> { + Object payload = message.getPayload(); + assertThat(payload).isInstanceOf(byte[].class); + assertThat(new String((byte[]) payload, StandardCharsets.UTF_8)).isEqualTo( + "filedata"); + }) ); runner.then(http().server(httpServer) - .send() - .response(OK) - .message() - .body(""" - {"code": 12, "type":"post-image-ok", "message":"image successfully uploaded"} - """) - .contentType("application/json")); + .send() + .response(OK) + .message() + .body(""" + {"code": 12, "type":"post-image-ok", "message":"image successfully uploaded"} + """) + .contentType("application/json")); runner.then(petApi - .receiveUploadFile(OK) - .message() - .validate(jsonPath().expression("$.code", "12")) - .validate(jsonPath().expression("$.message", "image successfully uploaded"))); - } - } - - @TestConfiguration - public static class Config { - - private final int port = SocketUtils.findAvailableTcpPort(8080); - - private final int otherPort = SocketUtils.findAvailableTcpPort(8081); - - private final int wsPort = SocketUtils.findAvailableTcpPort(8090); - - /** - * Main http client for accessing the main http server. - */ - @Bean(name = {"petstore.endpoint", "extpetstore.endpoint"}) - public HttpClient applicationServiceClient() { - return new HttpClientBuilder() - .requestUrl("http://localhost:%d".formatted(port)) - .handleCookies(true) - .build(); - } - - /** - * Http client accessing "other" server, see configuration of other server bean below. - */ - @Bean - public HttpClient otherApplicationServiceClient() { - return new HttpClientBuilder() - .requestUrl("http://localhost:%d".formatted(otherPort)) - .build(); - } - - /** - * A sample actor used to test actor configuration and functionality. - */ - @Bean - public TestActor petStoreActor() { - TestActor petStoreActor = new TestActor(); - petStoreActor.setName("PetStoreActor"); - petStoreActor.setDisabled(true); - return petStoreActor; - } - - /** - * Http server for mocking server side messaging and asserting data being send from test api - * requests. - */ - @Bean - public HttpServer httpServer() { - return new HttpServerBuilder() - .port(port) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .handleCookies(true) - .handleHandleSemicolonPathContent(true) - .build(); - } - - @Bean - public WebServiceServer soapServer() { - return WebServiceEndpoints.soap().server() - .port(wsPort) - .timeout(5000) - .autoStart(true) - .build(); - } - - /** - * A second http server. Mainly for tests that assert, that the default endpoint - * configuration can be overridden by an explicit endpoint. - */ - @Bean - public HttpServer otherHttpServer() { - return new HttpServerBuilder() - .port(otherPort) - .timeout(5000L) - .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) - .build(); - } - - /* - * Global variables, that make the ports available within the test context. Mainly - * used to access to port for explicit endpoint configuration tests. - */ - @Bean - public GlobalVariables globalVariables() { - return new GlobalVariables.Builder() - .variable("petstoreApplicationPort", port) - .variable("otherPetstoreApplicationPort", otherPort).build(); + .receiveUploadFile(OK) + .message() + .validate(jsonPath().expression("$.code", "12")) + .validate(jsonPath().expression("$.message", "image successfully uploaded"))); } - -// @Bean -// public ApiActionBuilderCustomizer petApiCustomizer() { -// return new ApiActionBuilderCustomizer() { -// @Override -// public T customizeRequestBuilder( -// GeneratedApi generatedApi, T builder) { -// return ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApi, -// builder); -// } -// -// @Override -// public T customizeResponseBuilder( -// GeneratedApi generatedApi, T builder) { -// return ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApi, -// builder); -// } -// }; -// } } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java index ac8289eb9e..c72a6ae179 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java @@ -1,7 +1,5 @@ package org.citrusframework.openapi.generator; -import static org.citrusframework.ws.actions.SoapActionBuilder.soap; - import org.citrusframework.TestCaseRunner; import org.citrusframework.annotations.CitrusResource; import org.citrusframework.annotations.CitrusTestSource; @@ -24,6 +22,8 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; +import static org.citrusframework.ws.actions.SoapActionBuilder.soap; + /** * This integration test class for the generated TestAPI aims to comprehensively test all aspects of * accessing the API using both Java and XML. In addition to serving as a test suite, it also acts @@ -46,6 +46,29 @@ class GeneratedSoapApiIT { @Autowired private BookServiceSoapApi bookServiceSoapApi; + @TestConfiguration + public static class Config { + + private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + + @Bean(name = {"bookstore.endpoint"}) + public WebServiceClient soapClient() { + return new WebServiceClientBuilder() + .defaultUri("http://localhost:%d".formatted(wsPort)) + .build(); + } + + @Bean + public WebServiceServer soapServer() { + return WebServiceEndpoints.soap().server() + .port(wsPort) + .timeout(5000) + .autoStart(true) + .build(); + } + + } + @Nested class SoapApi { @@ -57,61 +80,38 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { String request = """ - - - Lord of the Rings - J.R.R. Tolkien - - - """; + + + Lord of the Rings + J.R.R. Tolkien + + + """; runner.when(bookServiceSoapApi.sendAddBook().fork(true).message().body(request)); runner.then(soap().server(soapServer) - .receive() - .message() - .body(request)); + .receive() + .message() + .body(request)); String response = """ - - - Lord of the Rings - J.R.R. Tolkien - - - """; + + + Lord of the Rings + J.R.R. Tolkien + + + """; runner.then(soap().server(soapServer) - .send() - .message() - .body(response)); + .send() + .message() + .body(response)); runner.then(bookServiceSoapApi.receiveAddBook() - .message() - .body(response)); + .message() + .body(response)); } } - - @TestConfiguration - public static class Config { - - private final int wsPort = SocketUtils.findAvailableTcpPort(8090); - - @Bean(name = {"bookstore.endpoint"}) - public WebServiceClient soapClient() { - return new WebServiceClientBuilder() - .defaultUri("http://localhost:%d".formatted(wsPort)) - .build(); - } - - @Bean - public WebServiceServer soapServer() { - return WebServiceEndpoints.soap().server() - .port(wsPort) - .timeout(5000) - .autoStart(true) - .build(); - } - - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java index db2664db43..e3244b1efc 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java @@ -1,7 +1,5 @@ package org.citrusframework.openapi.generator; -import static org.assertj.core.api.Assertions.assertThat; - import org.citrusframework.annotations.CitrusResource; import org.citrusframework.annotations.CitrusTest; import org.citrusframework.config.CitrusSpringConfig; @@ -19,45 +17,47 @@ import org.springframework.context.annotation.Bean; import org.springframework.test.context.ContextConfiguration; +import static org.assertj.core.api.Assertions.assertThat; + @CitrusSpringSupport @ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, - PetStoreBeanConfiguration.class}) + PetStoreBeanConfiguration.class}) class GeneratedSpringBeanConfigurationIT { @Test @CitrusTest void petStoreOpenApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { var petStoreOpenApiRepository = testContext.getReferenceResolver() - .resolve("petStoreOpenApiRepository"); + .resolve("petStoreOpenApiRepository"); assertThat(petStoreOpenApiRepository) - .isNotNull(); + .isNotNull(); } @Test @CitrusTest void petApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { var petApi = testContext.getReferenceResolver() - .resolve(PetApi.class); + .resolve(PetApi.class); assertThat(petApi) - .isNotNull(); + .isNotNull(); } @Test @CitrusTest void storeApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { var storeApi = testContext.getReferenceResolver() - .resolve(StoreApi.class); + .resolve(StoreApi.class); assertThat(storeApi) - .isNotNull(); + .isNotNull(); } @Test @CitrusTest void userApiRepositoryIsAvailable(@CitrusResource TestContext testContext) { var userApi = testContext.getReferenceResolver() - .resolve(UserApi.class); + .resolve(UserApi.class); assertThat(userApi) - .isNotNull(); + .isNotNull(); } @TestConfiguration diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java index 581a3f065a..e8f6544109 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformerTest.java @@ -1,27 +1,28 @@ package org.citrusframework.openapi.generator; -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.util.FileUtils.readToString; - -import java.io.IOException; import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources.ClasspathResource; import org.junit.jupiter.api.Test; import org.springframework.core.io.ClassPathResource; +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.util.FileUtils.readToString; + class WsdlToOpenApiTransformerTest { @Test void testTransform() throws WsdlToOpenApiTransformationException, IOException { ClassPathResource wsdlResource = new ClassPathResource( - "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl"); + "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl"); WsdlToOpenApiTransformer simpleWsdlToOpenApiTransformer = new WsdlToOpenApiTransformer(wsdlResource.getURI()); String generatedYaml = simpleWsdlToOpenApiTransformer.transformToOpenApi(); Resource expectedYamlResource = new ClasspathResource( - "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml"); + "/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml"); String expectedYaml = readToString(expectedYamlResource); assertThat(generatedYaml).isEqualToIgnoringWhitespace(expectedYaml); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java index 6869b9ecea..ba582c7038 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java @@ -1,5 +1,9 @@ package org.citrusframework.openapi.generator.util; +import org.apache.commons.fileupload.MultipartStream; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.http.message.HttpMessage; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -8,9 +12,6 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.fileupload.MultipartStream; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.http.message.HttpMessage; /** * Provides utility method to convert a multipart http message to a map for simplified assertion. @@ -30,7 +31,7 @@ public static Map multipartMessageToMap(HttpMessage message) { try { inputStream = new ByteArrayInputStream(message.getPayload(String.class).getBytes()); MultipartStream multipartStream = new MultipartStream(inputStream, boundary.getBytes(), - 4096, null); + 4096, null); boolean nextPart = multipartStream.skipPreamble(); while (nextPart) { @@ -61,7 +62,7 @@ private static String getHeaderGroup(String headers, Pattern groupPattern) { return m.group(1); } else { throw new CitrusRuntimeException( - "unable to determine header group name: " + groupPattern); + "unable to determine header group name: " + groupPattern); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index 7f57903b45..eab1dca899 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -1,119 +1,118 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * Category */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Category { - private Long id; + private Long id; + + private String _name; - private String _name; + public Category() { + } - public Category() { - } + public Category id(Long id) { - public Category id(Long id) { - - this.id = id; - return this; - } + this.id = id; + return this; + } + + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public Category _name(String _name) { + this._name = _name; + return this; + } - public Category _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public String getName() { - return _name; - } + public void setName(String _name) { + this._name = _name; + } - public void setName(String _name) { - this._name = _name; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(id, _name); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); } - Category category = (Category) o; - return Objects.equals(this.id, category.id) && - Objects.equals(this._name, category._name); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Category {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index 1763cfd8c5..1518e9b85e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -1,120 +1,119 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.extpetstore.model; -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.time.LocalDate; +import java.util.Objects; /** - * Additional historical data for a vaccination report, not contained in internal storage. + * Additional historical data for a vaccination report, not contained in internal storage. */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class HistoricalData { - private LocalDate lastVaccinationDate; + private LocalDate lastVaccinationDate; + + private Integer vaccinationCount; - private Integer vaccinationCount; + public HistoricalData() { + } + + public HistoricalData lastVaccinationDate(LocalDate lastVaccinationDate) { + + this.lastVaccinationDate = lastVaccinationDate; + return this; + } - public HistoricalData() { - } + /** + * The date of the last vaccination. + * + * @return lastVaccinationDate + **/ + @jakarta.annotation.Nullable - public HistoricalData lastVaccinationDate(LocalDate lastVaccinationDate) { - - this.lastVaccinationDate = lastVaccinationDate; - return this; - } + public LocalDate getLastVaccinationDate() { + return lastVaccinationDate; + } - /** - * The date of the last vaccination. - * @return lastVaccinationDate - **/ - @jakarta.annotation.Nullable - public LocalDate getLastVaccinationDate() { - return lastVaccinationDate; - } + public void setLastVaccinationDate(LocalDate lastVaccinationDate) { + this.lastVaccinationDate = lastVaccinationDate; + } - public void setLastVaccinationDate(LocalDate lastVaccinationDate) { - this.lastVaccinationDate = lastVaccinationDate; - } + public HistoricalData vaccinationCount(Integer vaccinationCount) { + this.vaccinationCount = vaccinationCount; + return this; + } - public HistoricalData vaccinationCount(Integer vaccinationCount) { - - this.vaccinationCount = vaccinationCount; - return this; - } + /** + * The number of vaccinations the pet has received. + * + * @return vaccinationCount + **/ + @jakarta.annotation.Nullable - /** - * The number of vaccinations the pet has received. - * @return vaccinationCount - **/ - @jakarta.annotation.Nullable + public Integer getVaccinationCount() { + return vaccinationCount; + } - public Integer getVaccinationCount() { - return vaccinationCount; - } + public void setVaccinationCount(Integer vaccinationCount) { + this.vaccinationCount = vaccinationCount; + } - public void setVaccinationCount(Integer vaccinationCount) { - this.vaccinationCount = vaccinationCount; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + HistoricalData historicalData = (HistoricalData) o; + return Objects.equals(this.lastVaccinationDate, historicalData.lastVaccinationDate) && + Objects.equals(this.vaccinationCount, historicalData.vaccinationCount); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(lastVaccinationDate, vaccinationCount); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HistoricalData {\n"); + sb.append(" lastVaccinationDate: ").append(toIndentedString(lastVaccinationDate)).append("\n"); + sb.append(" vaccinationCount: ").append(toIndentedString(vaccinationCount)).append("\n"); + sb.append("}"); + return sb.toString(); } - HistoricalData historicalData = (HistoricalData) o; - return Objects.equals(this.lastVaccinationDate, historicalData.lastVaccinationDate) && - Objects.equals(this.vaccinationCount, historicalData.vaccinationCount); - } - - @Override - public int hashCode() { - return Objects.hash(lastVaccinationDate, vaccinationCount); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class HistoricalData {\n"); - sb.append(" lastVaccinationDate: ").append(toIndentedString(lastVaccinationDate)).append("\n"); - sb.append(" vaccinationCount: ").append(toIndentedString(vaccinationCount)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index 82b87e69b6..f83c998f23 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -1,279 +1,270 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.extpetstore.model; -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.citrusframework.openapi.generator.rest.extpetstore.model.Category; import org.citrusframework.openapi.generator.rest.extpetstore.model.Tag; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + /** * Pet */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Pet { - private Long id; + private Long id; - private String _name; + private String _name; - private Category category; + private Category category; - private List photoUrls = new ArrayList<>(); + private List photoUrls = new ArrayList<>(); - private List tags = new ArrayList<>(); + private List tags = new ArrayList<>(); + private StatusEnum status; - /** - * pet status in the store - */ - public enum StatusEnum { - AVAILABLE("available"), - - PENDING("pending"), - - SOLD("sold"); + public Pet() { + } - private String value; + public Pet id(Long id) { - StatusEnum(String value) { - this.value = value; + this.id = id; + return this; } - public String getValue() { - return value; - } + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable - @Override - public String toString() { - return String.valueOf(value); + public Long getId() { + return id; } - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); + public void setId(Long id) { + this.id = id; } - } - - private StatusEnum status; - public Pet() { - } + public Pet _name(String _name) { - public Pet id(Long id) { - - this.id = id; - return this; - } + this._name = _name; + return this; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nonnull - public Long getId() { - return id; - } + public String getName() { + return _name; + } + public void setName(String _name) { + this._name = _name; + } - public void setId(Long id) { - this.id = id; - } + public Pet category(Category category) { + this.category = category; + return this; + } - public Pet _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get category + * + * @return category + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nonnull + public Category getCategory() { + return category; + } - public String getName() { - return _name; - } + public void setCategory(Category category) { + this.category = category; + } + public Pet photoUrls(List photoUrls) { - public void setName(String _name) { - this._name = _name; - } + this.photoUrls = photoUrls; + return this; + } + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); + } + this.photoUrls.add(photoUrlsItem); + return this; + } - public Pet category(Category category) { - - this.category = category; - return this; - } + /** + * Get photoUrls + * + * @return photoUrls + **/ + @jakarta.annotation.Nonnull - /** - * Get category - * @return category - **/ - @jakarta.annotation.Nullable + public List getPhotoUrls() { + return photoUrls; + } - public Category getCategory() { - return category; - } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + public Pet tags(List tags) { - public void setCategory(Category category) { - this.category = category; - } + this.tags = tags; + return this; + } + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); + } + this.tags.add(tagsItem); + return this; + } - public Pet photoUrls(List photoUrls) { - - this.photoUrls = photoUrls; - return this; - } + /** + * Get tags + * + * @return tags + **/ + @jakarta.annotation.Nullable - public Pet addPhotoUrlsItem(String photoUrlsItem) { - if (this.photoUrls == null) { - this.photoUrls = new ArrayList<>(); + public List getTags() { + return tags; } - this.photoUrls.add(photoUrlsItem); - return this; - } - /** - * Get photoUrls - * @return photoUrls - **/ - @jakarta.annotation.Nonnull + public void setTags(List tags) { + this.tags = tags; + } - public List getPhotoUrls() { - return photoUrls; - } + public Pet status(StatusEnum status) { + this.status = status; + return this; + } - public void setPhotoUrls(List photoUrls) { - this.photoUrls = photoUrls; - } + /** + * pet status in the store + * + * @return status + **/ + @jakarta.annotation.Nullable + public StatusEnum getStatus() { + return status; + } - public Pet tags(List tags) { - - this.tags = tags; - return this; - } + public void setStatus(StatusEnum status) { + this.status = status; + } - public Pet addTagsItem(Tag tagsItem) { - if (this.tags == null) { - this.tags = new ArrayList<>(); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); } - this.tags.add(tagsItem); - return this; - } - /** - * Get tags - * @return tags - **/ - @jakarta.annotation.Nullable + @Override + public int hashCode() { + return Objects.hash(id, _name, category, photoUrls, tags, status); + } - public List getTags() { - return tags; - } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } - public void setTags(List tags) { - this.tags = tags; - } + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + PENDING("pending"), - public Pet status(StatusEnum status) { - - this.status = status; - return this; - } + SOLD("sold"); - /** - * pet status in the store - * @return status - **/ - @jakarta.annotation.Nullable + private String value; - public StatusEnum getStatus() { - return status; - } + StatusEnum(String value) { + this.value = value; + } + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } - public void setStatus(StatusEnum status) { - this.status = status; - } + public String getValue() { + return value; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Pet pet = (Pet) o; - return Objects.equals(this.id, pet.id) && - Objects.equals(this._name, pet._name) && - Objects.equals(this.category, pet.category) && - Objects.equals(this.photoUrls, pet.photoUrls) && - Objects.equals(this.tags, pet.tags) && - Objects.equals(this.status, pet.status); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name, category, photoUrls, tags, status); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Pet {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append(" category: ").append(toIndentedString(category)).append("\n"); - sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); - sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + @Override + public String toString() { + return String.valueOf(value); + } } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index 59471e20ad..6286eacf72 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -1,119 +1,118 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * Tag */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Tag { - private Long id; + private Long id; + + private String _name; - private String _name; + public Tag() { + } - public Tag() { - } + public Tag id(Long id) { - public Tag id(Long id) { - - this.id = id; - return this; - } + this.id = id; + return this; + } + + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public Tag _name(String _name) { + this._name = _name; + return this; + } - public Tag _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public String getName() { - return _name; - } + public void setName(String _name) { + this._name = _name; + } - public void setName(String _name) { - this._name = _name; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(id, _name); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); } - Tag tag = (Tag) o; - return Objects.equals(this.id, tag.id) && - Objects.equals(this._name, tag._name); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Tag {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 5713e91f12..37c83480a2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -1,93 +1,91 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * VaccinationDocumentResult */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class VaccinationDocumentResult { - private String documentId; + private String documentId; + + public VaccinationDocumentResult() { + } - public VaccinationDocumentResult() { - } + public VaccinationDocumentResult documentId(String documentId) { + + this.documentId = documentId; + return this; + } - public VaccinationDocumentResult documentId(String documentId) { - - this.documentId = documentId; - return this; - } + /** + * The unique ID of the uploaded vaccination document. + * + * @return documentId + **/ + @jakarta.annotation.Nullable - /** - * The unique ID of the uploaded vaccination document. - * @return documentId - **/ - @jakarta.annotation.Nullable + public String getDocumentId() { + return documentId; + } - public String getDocumentId() { - return documentId; - } + public void setDocumentId(String documentId) { + this.documentId = documentId; + } - public void setDocumentId(String documentId) { - this.documentId = documentId; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VaccinationDocumentResult vaccinationDocumentResult = (VaccinationDocumentResult) o; + return Objects.equals(this.documentId, vaccinationDocumentResult.documentId); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(documentId); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VaccinationDocumentResult {\n"); + sb.append(" documentId: ").append(toIndentedString(documentId)).append("\n"); + sb.append("}"); + return sb.toString(); } - VaccinationDocumentResult vaccinationDocumentResult = (VaccinationDocumentResult) o; - return Objects.equals(this.documentId, vaccinationDocumentResult.documentId); - } - - @Override - public int hashCode() { - return Objects.hash(documentId); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class VaccinationDocumentResult {\n"); - sb.append(" documentId: ").append(toIndentedString(documentId)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index e8fcfb646e..271c5ce2ce 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -1,73 +1,61 @@ package org.citrusframework.openapi.generator.rest.extpetstore.request; -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static org.citrusframework.util.StringUtils.isEmpty; -import static org.citrusframework.util.StringUtils.isNotEmpty; - import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.net.URL; -import java.time.LocalDate; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; +import org.citrusframework.openapi.generator.rest.extpetstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.TestApiUtils; import org.citrusframework.spi.Resource; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; -import org.citrusframework.openapi.generator.rest.extpetstore.model.*; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; @SuppressWarnings("unused") @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class ExtPetApi implements GeneratedApi -{ +public class ExtPetApi implements GeneratedApi { + private final List customizers; + private final Endpoint endpoint; + private final OpenApiSpecification openApiSpecification; @Value("${" + "extpetstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; - @Value("${" + "extpetstore.basic.username:#{null}}") private String basicUsername; - @Value("${" + "extpetstore.basic.password:#{null}}") private String basicPassword; - @Value("${" + "extpetstore.bearer.token:#{null}}") private String basicAuthBearer; - @Value("${" + "extpetstore.api-key-header:#{null}}") private String defaultApiKeyHeader; - @Value("${" + "extpetstore.api-key-cookie:#{null}}") private String defaultApiKeyCookie; - @Value("${" + "extpetstore.api-key-query:#{null}}") private String defaultApiKeyQuery; - private final List customizers; - - private final Endpoint endpoint; - - private final OpenApiSpecification openApiSpecification; - - public ExtPetApi(Endpoint endpoint) { + public ExtPetApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public ExtPetApi(Endpoint endpoint, List customizers) { + public ExtPetApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -115,731 +103,731 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport(Resource template, Integer reqIntVal) { - return new GenerateVaccinationReportSendActionBuilder(this, openApiSpecification, template, reqIntVal); + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport(Resource template, Integer reqIntVal) { + return new GenerateVaccinationReportSendActionBuilder(this, openApiSpecification, template, reqIntVal); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport$(String templateExpression, String reqIntValExpression ) { - return new GenerateVaccinationReportSendActionBuilder(openApiSpecification, this, templateExpression, reqIntValExpression); + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport$(String templateExpression, String reqIntValExpression) { + return new GenerateVaccinationReportSendActionBuilder(openApiSpecification, this, templateExpression, reqIntValExpression); } - public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull HttpStatus statusCode) { + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull HttpStatus statusCode) { return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull String statusCode) { - return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, statusCode); + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull String statusCode) { + return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication$(String petIdExpression, String allDetailsExpression ) { - GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - builder.setApiKeyQuery(defaultApiKeyQuery); - builder.setApiKeyHeader(defaultApiKeyHeader); - builder.setApiKeyCookie(defaultApiKeyCookie); - return builder; + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication$(String petIdExpression, String allDetailsExpression) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKeyQuery(defaultApiKeyQuery); + builder.setApiKeyHeader(defaultApiKeyHeader); + builder.setApiKeyCookie(defaultApiKeyCookie); + return builder; } - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - return builder; + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication$(String petIdExpression, String allDetailsExpression ) { - GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBasicAuthUsername(basicUsername); - builder.setBasicAuthPassword(basicPassword); - return builder; + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication$(String petIdExpression, String allDetailsExpression) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthUsername(basicUsername); + builder.setBasicAuthPassword(basicPassword); + return builder; } - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - return builder; + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication$(String petIdExpression, String allDetailsExpression ) { - GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBasicAuthBearer(basicAuthBearer); - return builder; + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication$(String petIdExpression, String allDetailsExpression) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthBearer(basicAuthBearer); + return builder; } - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithCookieSendActionBuilder sendGetPetWithCookie(Long petId, String sessionId) { - return new GetPetWithCookieSendActionBuilder(this, openApiSpecification, petId, sessionId); + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie(Long petId, String sessionId) { + return new GetPetWithCookieSendActionBuilder(this, openApiSpecification, petId, sessionId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithCookieSendActionBuilder sendGetPetWithCookie$(String petIdExpression, String sessionIdExpression ) { - return new GetPetWithCookieSendActionBuilder(openApiSpecification, this, petIdExpression, sessionIdExpression); + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie$(String petIdExpression, String sessionIdExpression) { + return new GetPetWithCookieSendActionBuilder(openApiSpecification, this, petIdExpression, sessionIdExpression); } - public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull HttpStatus statusCode) { + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull HttpStatus statusCode) { return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull String statusCode) { - return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull String statusCode) { + return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery(PetIdentifier petId) { - return new GetPetWithDeepObjectTypeQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery(PetIdentifier petId) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery$(String petIdExpression ) { - return new GetPetWithDeepObjectTypeQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery$(String petIdExpression) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull HttpStatus statusCode) { + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull HttpStatus statusCode) { return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull String statusCode) { - return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull String statusCode) { + return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie(List petId) { - return new GetPetWithFormExplodedStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie(List petId) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie$(List petIdExpression ) { - return new GetPetWithFormExplodedStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie$(List petIdExpression) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie(PetIdentifier petId) { - return new GetPetWithFormObjectStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie(PetIdentifier petId) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie$(String petIdExpression ) { - return new GetPetWithFormObjectStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie$(String petIdExpression) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie(List petId) { - return new GetPetWithFormStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie(List petId) { + return new GetPetWithFormStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie$(List petIdExpression ) { - return new GetPetWithFormStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie$(List petIdExpression) { + return new GetPetWithFormStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery(PetIdentifier petId) { - return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery$(String petIdExpression ) { - return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery$(String petIdExpression) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery(List petId) { - return new GetPetWithFormStyleExplodedQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery(List petId) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery$(List petIdExpression ) { - return new GetPetWithFormStyleExplodedQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery$(List petIdExpression) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery(PetIdentifier petId) { - return new GetPetWithFormStyleObjectQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery$(String petIdExpression ) { - return new GetPetWithFormStyleObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery$(String petIdExpression) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery(List petId) { - return new GetPetWithFormStyleQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery(List petId) { + return new GetPetWithFormStyleQuerySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery$(List petIdExpression ) { - return new GetPetWithFormStyleQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery$(List petIdExpression) { + return new GetPetWithFormStyleQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray(List petId) { - return new GetPetWithLabelStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray(List petId) { + return new GetPetWithLabelStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray$(List petIdExpression ) { - return new GetPetWithLabelStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray$(List petIdExpression) { + return new GetPetWithLabelStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull String statusCode) { - return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded(List petId) { - return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded(List petId) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded$(List petIdExpression ) { - return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded$(List petIdExpression) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject(PetIdentifier petId) { - return new GetPetWithLabelStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject$(String petIdExpression ) { - return new GetPetWithLabelStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject$(String petIdExpression) { + return new GetPetWithLabelStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull String statusCode) { - return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded$(String petIdExpression ) { - return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded$(String petIdExpression) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray(List petId) { - return new GetPetWithMatrixStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray(List petId) { + return new GetPetWithMatrixStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray$(List petIdExpression ) { - return new GetPetWithMatrixStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray$(List petIdExpression) { + return new GetPetWithMatrixStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull String statusCode) { - return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded(List petId) { - return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded(List petId) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded$(List petIdExpression ) { - return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded$(List petIdExpression) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject(PetIdentifier petId) { - return new GetPetWithMatrixStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject$(String petIdExpression ) { - return new GetPetWithMatrixStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject$(String petIdExpression) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull String statusCode) { - return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded$(String petIdExpression ) { - return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded$(String petIdExpression) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray(List petId) { - return new GetPetWithSimpleStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray(List petId) { + return new GetPetWithSimpleStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray$(List petIdExpression ) { - return new GetPetWithSimpleStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray$(List petIdExpression) { + return new GetPetWithSimpleStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull String statusCode) { - return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded(List petId) { - return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded(List petId) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded$(List petIdExpression ) { - return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded$(List petIdExpression) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader(List petId) { - return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader(List petId) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader$(List petIdExpression ) { - return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader$(List petIdExpression) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader(PetIdentifier petId) { - return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader$(String petIdExpression ) { - return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader$(String petIdExpression) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader(List petId) { - return new GetPetWithSimpleStyleHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader(List petId) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader$(List petIdExpression ) { - return new GetPetWithSimpleStyleHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader$(List petIdExpression) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject$(String petIdExpression ) { - return new GetPetWithSimpleStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject$(String petIdExpression) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded$(String petIdExpression ) { - return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded$(String petIdExpression) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader$(String petIdExpression ) { - return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader$(String petIdExpression) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PostVaccinationDocumentSendActionBuilder sendPostVaccinationDocument(String bucket, String filename) { - return new PostVaccinationDocumentSendActionBuilder(this, openApiSpecification, bucket, filename); + public PostVaccinationDocumentSendActionBuilder sendPostVaccinationDocument(String bucket, String filename) { + return new PostVaccinationDocumentSendActionBuilder(this, openApiSpecification, bucket, filename); } - public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull HttpStatus statusCode) { + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull HttpStatus statusCode) { return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull String statusCode) { - return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, statusCode); + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull String statusCode) { + return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PostVaccinationFormDataSendActionBuilder sendPostVaccinationFormData() { - return new PostVaccinationFormDataSendActionBuilder(this, openApiSpecification); + public PostVaccinationFormDataSendActionBuilder sendPostVaccinationFormData() { + return new PostVaccinationFormDataSendActionBuilder(this, openApiSpecification); } - public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull HttpStatus statusCode) { + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull HttpStatus statusCode) { return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull String statusCode) { - return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, statusCode); + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull String statusCode) { + return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData(Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { - return new UpdatePetWithArrayQueryDataSendActionBuilder(this, openApiSpecification, petId, _name, status, tags, nicknames, sampleStringHeader); + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData(Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(this, openApiSpecification, petId, _name, status, tags, nicknames, sampleStringHeader); } /** * Builder with required parameters as string to allow for dynamic content. */ - public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData$(String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression ) { - return new UpdatePetWithArrayQueryDataSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, tagsExpression, nicknamesExpression, sampleStringHeaderExpression); + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData$(String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, tagsExpression, nicknamesExpression, sampleStringHeaderExpression); } - public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull HttpStatus statusCode) { + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull HttpStatus statusCode) { return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull String statusCode) { - return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull String statusCode) { + return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded(Long petId, String _name, String status, Integer age, List tags) { - return new UpdatePetWithFormUrlEncodedSendActionBuilder(this, openApiSpecification, petId, _name, status, age, tags); + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded(Long petId, String _name, String status, Integer age, List tags) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(this, openApiSpecification, petId, _name, status, age, tags); } /** * Builder with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded$(String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression ) { - return new UpdatePetWithFormUrlEncodedSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, ageExpression, tagsExpression); + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded$(String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, ageExpression, tagsExpression); } - public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull HttpStatus statusCode) { + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull HttpStatus statusCode) { return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull String statusCode) { - return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull String statusCode) { + return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class GenerateVaccinationReportSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -852,17 +840,17 @@ public static class GenerateVaccinationReportSendActionBuilder extends */ public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Resource template, Integer reqIntVal) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(template) ); - formParameter("reqIntVal", reqIntVal); + formParameter("template", toBinary(template)); + formParameter("reqIntVal", reqIntVal); } /** * Constructor with required parameters as string to allow for dynamic content. */ - public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String templateExpression, String reqIntValExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(templateExpression) ); - formParameter("reqIntVal", reqIntValExpression); + public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String templateExpression, String reqIntValExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + formParameter("template", toBinary(templateExpression)); + formParameter("reqIntVal", reqIntValExpression); } /** @@ -870,145 +858,145 @@ public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSp */ public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String templateExpression, String reqIntValExpression) { super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(templateExpression) ); - formParameter("reqIntVal", reqIntValExpression); + formParameter("template", toBinary(templateExpression)); + formParameter("reqIntVal", reqIntValExpression); } public GenerateVaccinationReportSendActionBuilder template(Resource template) { - formParameter("template", toBinary(template) ); + formParameter("template", toBinary(template)); return this; } public GenerateVaccinationReportSendActionBuilder template(String templateExpression) { - formParameter("template", toBinary(templateExpression) ); - return this; + formParameter("template", toBinary(templateExpression)); + return this; } public GenerateVaccinationReportSendActionBuilder reqIntVal(Integer reqIntVal) { - formParameter("reqIntVal", reqIntVal); + formParameter("reqIntVal", reqIntVal); return this; } public GenerateVaccinationReportSendActionBuilder reqIntVal(String reqIntValExpression) { - formParameter("reqIntVal", reqIntValExpression); - return this; + formParameter("reqIntVal", reqIntValExpression); + return this; } public GenerateVaccinationReportSendActionBuilder optIntVal(Integer optIntVal) { - formParameter("optIntVal", optIntVal); + formParameter("optIntVal", optIntVal); return this; } public void setOptIntVal(Integer optIntVal) { - formParameter("optIntVal", optIntVal); + formParameter("optIntVal", optIntVal); } public GenerateVaccinationReportSendActionBuilder optIntVal(String optIntValExpression) { - formParameter("optIntVal", optIntValExpression); + formParameter("optIntVal", optIntValExpression); return this; } public void setOptIntVal(String optIntValExpression) { - formParameter("optIntVal", optIntValExpression); + formParameter("optIntVal", optIntValExpression); } public GenerateVaccinationReportSendActionBuilder optBoolVal(Boolean optBoolVal) { - formParameter("optBoolVal", optBoolVal); + formParameter("optBoolVal", optBoolVal); return this; } public void setOptBoolVal(Boolean optBoolVal) { - formParameter("optBoolVal", optBoolVal); + formParameter("optBoolVal", optBoolVal); } public GenerateVaccinationReportSendActionBuilder optBoolVal(String optBoolValExpression) { - formParameter("optBoolVal", optBoolValExpression); + formParameter("optBoolVal", optBoolValExpression); return this; } public void setOptBoolVal(String optBoolValExpression) { - formParameter("optBoolVal", optBoolValExpression); + formParameter("optBoolVal", optBoolValExpression); } public GenerateVaccinationReportSendActionBuilder optNumberVal(BigDecimal optNumberVal) { - formParameter("optNumberVal", optNumberVal); + formParameter("optNumberVal", optNumberVal); return this; } public void setOptNumberVal(BigDecimal optNumberVal) { - formParameter("optNumberVal", optNumberVal); + formParameter("optNumberVal", optNumberVal); } public GenerateVaccinationReportSendActionBuilder optNumberVal(String optNumberValExpression) { - formParameter("optNumberVal", optNumberValExpression); + formParameter("optNumberVal", optNumberValExpression); return this; } public void setOptNumberVal(String optNumberValExpression) { - formParameter("optNumberVal", optNumberValExpression); + formParameter("optNumberVal", optNumberValExpression); } public GenerateVaccinationReportSendActionBuilder optStringVal(String optStringVal) { - formParameter("optStringVal", optStringVal); + formParameter("optStringVal", optStringVal); return this; } public void setOptStringVal(String optStringVal) { - formParameter("optStringVal", optStringVal); + formParameter("optStringVal", optStringVal); } public GenerateVaccinationReportSendActionBuilder optDateVal(LocalDate optDateVal) { - formParameter("optDateVal", optDateVal); + formParameter("optDateVal", optDateVal); return this; } public void setOptDateVal(LocalDate optDateVal) { - formParameter("optDateVal", optDateVal); + formParameter("optDateVal", optDateVal); } public GenerateVaccinationReportSendActionBuilder optDateVal(String optDateValExpression) { - formParameter("optDateVal", optDateValExpression); + formParameter("optDateVal", optDateValExpression); return this; } public void setOptDateVal(String optDateValExpression) { - formParameter("optDateVal", optDateValExpression); + formParameter("optDateVal", optDateValExpression); } public GenerateVaccinationReportSendActionBuilder additionalData(HistoricalData additionalData) { - formParameter("additionalData", additionalData); + formParameter("additionalData", additionalData); return this; } public void setAdditionalData(HistoricalData additionalData) { - formParameter("additionalData", additionalData); + formParameter("additionalData", additionalData); } public GenerateVaccinationReportSendActionBuilder additionalData(String additionalDataExpression) { - formParameter("additionalData", additionalDataExpression); + formParameter("additionalData", additionalDataExpression); return this; } public void setAdditionalData(String additionalDataExpression) { - formParameter("additionalData", additionalDataExpression); + formParameter("additionalData", additionalDataExpression); } public GenerateVaccinationReportSendActionBuilder schema(Resource schema) { - formParameter("schema", toBinary(schema) ); + formParameter("schema", toBinary(schema)); return this; } public void setSchema(Resource schema) { - formParameter("schema", toBinary(schema) ); + formParameter("schema", toBinary(schema)); } public GenerateVaccinationReportSendActionBuilder schema(String schemaExpression) { - formParameter("schema", toBinary(schemaExpression) ); + formParameter("schema", toBinary(schemaExpression)); return this; } public void setSchema(String schemaExpression) { - formParameter("schema", toBinary(schemaExpression) ); + formParameter("schema", toBinary(schemaExpression)); } @Override @@ -1023,7 +1011,7 @@ public SendMessageAction doBuild() { } public static class GenerateVaccinationReportReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -1031,7 +1019,7 @@ public static class GenerateVaccinationReportReceiveActionBuilder extends private static final String OPERATION_NAME = "generateVaccinationReport"; - public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1052,7 +1040,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithApiKeyAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1090,8 +1078,8 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1112,7 +1100,7 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1122,24 +1110,24 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(Boolean al public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder details(String...details) { + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder details(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String...details) { + public void setDetails(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String...requesterInformation) { + public void setRequesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1189,7 +1177,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1197,7 +1185,7 @@ public static class GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetByIdWithApiKeyAuthentication"; - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1218,7 +1206,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithBasicAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1248,8 +1236,8 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithBasicAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1270,7 +1258,7 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1280,24 +1268,24 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(Boolean all public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithBasicAuthenticationSendActionBuilder details(String...details) { + public GetPetByIdWithBasicAuthenticationSendActionBuilder details(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String...details) { + public void setDetails(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithBasicAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + public GetPetByIdWithBasicAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String...requesterInformation) { + public void setRequesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1320,11 +1308,11 @@ public void setBasicAuthPassword(String password) { } protected void addBasicAuthHeader(String basicUsername, String basicPassword, - HttpMessageBuilderSupport messageBuilderSupport) { + HttpMessageBuilderSupport messageBuilderSupport) { TestApiUtils.addBasicAuthHeader( - isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, - isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, - messageBuilderSupport); + isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, + isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, + messageBuilderSupport); } @Override @@ -1340,7 +1328,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithBasicAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1348,7 +1336,7 @@ public static class GetPetByIdWithBasicAuthenticationReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetByIdWithBasicAuthentication"; - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1369,7 +1357,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithBearerAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1394,8 +1382,8 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithBearerAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1416,7 +1404,7 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1426,24 +1414,24 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(Boolean al public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithBearerAuthenticationSendActionBuilder details(String...details) { + public GetPetByIdWithBearerAuthenticationSendActionBuilder details(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String...details) { + public void setDetails(String... details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithBearerAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { + public GetPetByIdWithBearerAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String...requesterInformation) { + public void setRequesterInformation(String... requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1459,7 +1447,7 @@ public void setBasicAuthBearer(String basicAuthBearer) { @Override public SendMessageAction doBuild() { if (!isEmpty(basicAuthBearer) || !isEmpty(defaultBasicAuthBearer)) { - headerParameter("Authorization", "Bearer " +getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); + headerParameter("Authorization", "Bearer " + getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); } if (getCustomizers() != null) { @@ -1471,7 +1459,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithBearerAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1479,7 +1467,7 @@ public static class GetPetByIdWithBearerAuthenticationReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetByIdWithBearerAuthentication"; - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1500,7 +1488,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1520,8 +1508,8 @@ public GetPetWithCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecificati /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String sessionIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String sessionIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); cookieParameter("session_id", sessionIdExpression, ParameterStyle.FORM, true, false); } @@ -1542,7 +1530,7 @@ public GetPetWithCookieSendActionBuilder petId(Long petId) { public GetPetWithCookieSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetWithCookieSendActionBuilder sessionId(String sessionId) { @@ -1571,7 +1559,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1579,7 +1567,7 @@ public static class GetPetWithCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithCookie"; - public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1600,7 +1588,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithDeepObjectTypeQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1619,8 +1607,8 @@ public GetPetWithDeepObjectTypeQuerySendActionBuilder(ExtPetApi extPetApi, OpenA /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithDeepObjectTypeQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); } @@ -1639,7 +1627,7 @@ public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(PetIdentifier petId) public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); - return this; + return this; } @Override @@ -1654,7 +1642,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithDeepObjectTypeQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1662,7 +1650,7 @@ public static class GetPetWithDeepObjectTypeQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithDeepObjectTypeQuery"; - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1683,7 +1671,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormExplodedStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1702,8 +1690,8 @@ public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormExplodedStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); } @@ -1715,14 +1703,14 @@ public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, O cookieParameter("petId", petId, ParameterStyle.FORM, true, false); } - public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(Integer...petId) { + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(Integer... petId) { cookieParameter("petId", petId, ParameterStyle.FORM, true, false); return this; } - public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String...petIdExpression) { + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String... petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); - return this; + return this; } @Override @@ -1737,7 +1725,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormExplodedStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1745,7 +1733,7 @@ public static class GetPetWithFormExplodedStyleCookieReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithFormExplodedStyleCookie"; - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1766,7 +1754,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormObjectStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1785,8 +1773,8 @@ public GetPetWithFormObjectStyleCookieSendActionBuilder(ExtPetApi extPetApi, Ope /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormObjectStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); } @@ -1805,7 +1793,7 @@ public GetPetWithFormObjectStyleCookieSendActionBuilder petId(PetIdentifier petI public GetPetWithFormObjectStyleCookieSendActionBuilder petId(String petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); - return this; + return this; } @Override @@ -1820,7 +1808,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormObjectStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1828,7 +1816,7 @@ public static class GetPetWithFormObjectStyleCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormObjectStyleCookie"; - public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1849,7 +1837,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1868,8 +1856,8 @@ public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); } @@ -1881,14 +1869,14 @@ public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSp cookieParameter("petId", petId, ParameterStyle.FORM, false, false); } - public GetPetWithFormStyleCookieSendActionBuilder petId(Integer...petId) { + public GetPetWithFormStyleCookieSendActionBuilder petId(Integer... petId) { cookieParameter("petId", petId, ParameterStyle.FORM, false, false); return this; } - public GetPetWithFormStyleCookieSendActionBuilder petId(String...petIdExpression) { + public GetPetWithFormStyleCookieSendActionBuilder petId(String... petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); - return this; + return this; } @Override @@ -1903,7 +1891,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1911,7 +1899,7 @@ public static class GetPetWithFormStyleCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleCookie"; - public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1932,7 +1920,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedObjectQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1951,8 +1939,8 @@ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(ExtPetApi extPetA /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); } @@ -1971,7 +1959,7 @@ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(PetIdentifi public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); - return this; + return this; } @Override @@ -1986,7 +1974,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1994,7 +1982,7 @@ public static class GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder e private static final String OPERATION_NAME = "getPetWithFormStyleExplodedObjectQuery"; - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2015,7 +2003,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2034,8 +2022,8 @@ public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, Op /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleExplodedQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); } @@ -2047,14 +2035,14 @@ public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, Op queryParameter("petId", petId, ParameterStyle.FORM, true, false); } - public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(Integer...petId) { + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(Integer... petId) { queryParameter("petId", petId, ParameterStyle.FORM, true, false); return this; } - public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String...petIdExpression) { + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String... petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); - return this; + return this; } @Override @@ -2069,7 +2057,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2077,7 +2065,7 @@ public static class GetPetWithFormStyleExplodedQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleExplodedQuery"; - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2098,7 +2086,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleObjectQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2117,8 +2105,8 @@ public GetPetWithFormStyleObjectQuerySendActionBuilder(ExtPetApi extPetApi, Open /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); } @@ -2137,7 +2125,7 @@ public GetPetWithFormStyleObjectQuerySendActionBuilder petId(PetIdentifier petId public GetPetWithFormStyleObjectQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); - return this; + return this; } @Override @@ -2152,7 +2140,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleObjectQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2160,7 +2148,7 @@ public static class GetPetWithFormStyleObjectQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleObjectQuery"; - public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2181,7 +2169,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2200,8 +2188,8 @@ public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpe /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); } @@ -2213,14 +2201,14 @@ public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpe queryParameter("petId", petId, ParameterStyle.FORM, false, false); } - public GetPetWithFormStyleQuerySendActionBuilder petId(Integer...petId) { + public GetPetWithFormStyleQuerySendActionBuilder petId(Integer... petId) { queryParameter("petId", petId, ParameterStyle.FORM, false, false); return this; } - public GetPetWithFormStyleQuerySendActionBuilder petId(String...petIdExpression) { + public GetPetWithFormStyleQuerySendActionBuilder petId(String... petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); - return this; + return this; } @Override @@ -2235,7 +2223,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2243,7 +2231,7 @@ public static class GetPetWithFormStyleQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleQuery"; - public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2264,7 +2252,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2283,8 +2271,8 @@ public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); } @@ -2296,14 +2284,14 @@ public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSp pathParameter("petId", petId, ParameterStyle.LABEL, false, false); } - public GetPetWithLabelStyleArraySendActionBuilder petId(Integer...petId) { + public GetPetWithLabelStyleArraySendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.LABEL, false, false); return this; } - public GetPetWithLabelStyleArraySendActionBuilder petId(String...petIdExpression) { + public GetPetWithLabelStyleArraySendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); - return this; + return this; } @Override @@ -2318,7 +2306,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2326,7 +2314,7 @@ public static class GetPetWithLabelStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithLabelStyleArray"; - public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2347,7 +2335,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2366,8 +2354,8 @@ public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); } @@ -2379,14 +2367,14 @@ public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, O pathParameter("petId", petId, ParameterStyle.LABEL, true, false); } - public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.LABEL, true, false); return this; } - public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); - return this; + return this; } @Override @@ -2401,7 +2389,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2409,7 +2397,7 @@ public static class GetPetWithLabelStyleArrayExplodedReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithLabelStyleArrayExploded"; - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2430,7 +2418,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2449,8 +2437,8 @@ public GetPetWithLabelStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); } @@ -2469,7 +2457,7 @@ public GetPetWithLabelStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithLabelStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); - return this; + return this; } @Override @@ -2484,7 +2472,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2492,7 +2480,7 @@ public static class GetPetWithLabelStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithLabelStyleObject"; - public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2513,7 +2501,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2532,8 +2520,8 @@ public GetPetWithLabelStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); } @@ -2552,7 +2540,7 @@ public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(PetIdentifier p public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); - return this; + return this; } @Override @@ -2567,7 +2555,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2575,7 +2563,7 @@ public static class GetPetWithLabelStyleObjectExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithLabelStyleObjectExploded"; - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2596,7 +2584,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2615,8 +2603,8 @@ public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); } @@ -2628,14 +2616,14 @@ public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); } - public GetPetWithMatrixStyleArraySendActionBuilder petId(Integer...petId) { + public GetPetWithMatrixStyleArraySendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); return this; } - public GetPetWithMatrixStyleArraySendActionBuilder petId(String...petIdExpression) { + public GetPetWithMatrixStyleArraySendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); - return this; + return this; } @Override @@ -2650,7 +2638,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2658,7 +2646,7 @@ public static class GetPetWithMatrixStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithMatrixStyleArray"; - public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2679,7 +2667,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2698,8 +2686,8 @@ public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); } @@ -2711,14 +2699,14 @@ public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); } - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); return this; } - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); - return this; + return this; } @Override @@ -2733,7 +2721,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2741,7 +2729,7 @@ public static class GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithMatrixStyleArrayExploded"; - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2762,7 +2750,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2781,8 +2769,8 @@ public GetPetWithMatrixStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); } @@ -2801,7 +2789,7 @@ public GetPetWithMatrixStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithMatrixStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); - return this; + return this; } @Override @@ -2816,7 +2804,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2824,7 +2812,7 @@ public static class GetPetWithMatrixStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithMatrixStyleObject"; - public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2845,7 +2833,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2864,8 +2852,8 @@ public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); } @@ -2884,7 +2872,7 @@ public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(PetIdentifier public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); - return this; + return this; } @Override @@ -2899,7 +2887,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2907,7 +2895,7 @@ public static class GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithMatrixStyleObjectExploded"; - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2928,7 +2916,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2947,8 +2935,8 @@ public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -2960,14 +2948,14 @@ public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleArraySendActionBuilder petId(Integer...petId) { + public GetPetWithSimpleStyleArraySendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleArraySendActionBuilder petId(String...petIdExpression) { + public GetPetWithSimpleStyleArraySendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -2982,7 +2970,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2990,7 +2978,7 @@ public static class GetPetWithSimpleStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleArray"; - public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3011,7 +2999,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3030,8 +3018,8 @@ public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -3043,14 +3031,14 @@ public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(Integer...petId) { + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(Integer... petId) { pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -3065,7 +3053,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3073,7 +3061,7 @@ public static class GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithSimpleStyleArrayExploded"; - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3094,7 +3082,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3113,8 +3101,8 @@ public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); } @@ -3126,14 +3114,14 @@ public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); } - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(Integer...petId) { + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(Integer... petId) { headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); return this; } - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String...petIdExpression) { + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String... petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); - return this; + return this; } @Override @@ -3148,7 +3136,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3156,7 +3144,7 @@ public static class GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedHeader"; - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3177,7 +3165,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3196,8 +3184,8 @@ public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(ExtPetApi extP /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); } @@ -3216,7 +3204,7 @@ public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(PetIdent public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(String petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); - return this; + return this; } @Override @@ -3231,7 +3219,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3239,7 +3227,7 @@ public static class GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilde private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedObjectHeader"; - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3260,7 +3248,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3279,8 +3267,8 @@ public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -3292,14 +3280,14 @@ public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApi headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleHeaderSendActionBuilder petId(Integer...petId) { + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(Integer... petId) { headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String...petIdExpression) { + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String... petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -3314,7 +3302,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3322,7 +3310,7 @@ public static class GetPetWithSimpleStyleHeaderReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleHeader"; - public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3343,7 +3331,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3362,8 +3350,8 @@ public GetPetWithSimpleStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); } @@ -3382,7 +3370,7 @@ public GetPetWithSimpleStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithSimpleStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); - return this; + return this; } @Override @@ -3397,7 +3385,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3405,7 +3393,7 @@ public static class GetPetWithSimpleStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleObject"; - public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3426,7 +3414,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3445,8 +3433,8 @@ public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); } @@ -3465,7 +3453,7 @@ public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(PetIdentifier public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); - return this; + return this; } @Override @@ -3480,7 +3468,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3488,7 +3476,7 @@ public static class GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectExploded"; - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3509,7 +3497,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3528,8 +3516,8 @@ public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); } @@ -3548,7 +3536,7 @@ public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(PetIdentifier pe public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(String petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); - return this; + return this; } @Override @@ -3563,7 +3551,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3571,7 +3559,7 @@ public static class GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectHeader"; - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3592,7 +3580,7 @@ public ReceiveMessageAction doBuild() { } public static class PostVaccinationDocumentSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -3640,7 +3628,7 @@ public SendMessageAction doBuild() { } public static class PostVaccinationDocumentReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -3648,7 +3636,7 @@ public static class PostVaccinationDocumentReceiveActionBuilder extends private static final String OPERATION_NAME = "postVaccinationDocument"; - public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3669,7 +3657,7 @@ public ReceiveMessageAction doBuild() { } public static class PostVaccinationFormDataSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -3689,66 +3677,66 @@ public PostVaccinationFormDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpec } public PostVaccinationFormDataSendActionBuilder vaccine(String vaccine) { - formParameter("vaccine", vaccine); + formParameter("vaccine", vaccine); return this; } public void setVaccine(String vaccine) { - formParameter("vaccine", vaccine); + formParameter("vaccine", vaccine); } public PostVaccinationFormDataSendActionBuilder isFirstVaccination(Boolean isFirstVaccination) { - formParameter("isFirstVaccination", isFirstVaccination); + formParameter("isFirstVaccination", isFirstVaccination); return this; } public void setIsFirstVaccination(Boolean isFirstVaccination) { - formParameter("isFirstVaccination", isFirstVaccination); + formParameter("isFirstVaccination", isFirstVaccination); } public PostVaccinationFormDataSendActionBuilder isFirstVaccination(String isFirstVaccinationExpression) { - formParameter("isFirstVaccination", isFirstVaccinationExpression); + formParameter("isFirstVaccination", isFirstVaccinationExpression); return this; } public void setIsFirstVaccination(String isFirstVaccinationExpression) { - formParameter("isFirstVaccination", isFirstVaccinationExpression); + formParameter("isFirstVaccination", isFirstVaccinationExpression); } public PostVaccinationFormDataSendActionBuilder doseNumber(Integer doseNumber) { - formParameter("doseNumber", doseNumber); + formParameter("doseNumber", doseNumber); return this; } public void setDoseNumber(Integer doseNumber) { - formParameter("doseNumber", doseNumber); + formParameter("doseNumber", doseNumber); } public PostVaccinationFormDataSendActionBuilder doseNumber(String doseNumberExpression) { - formParameter("doseNumber", doseNumberExpression); + formParameter("doseNumber", doseNumberExpression); return this; } public void setDoseNumber(String doseNumberExpression) { - formParameter("doseNumber", doseNumberExpression); + formParameter("doseNumber", doseNumberExpression); } public PostVaccinationFormDataSendActionBuilder vaccinationDate(LocalDate vaccinationDate) { - formParameter("vaccinationDate", vaccinationDate); + formParameter("vaccinationDate", vaccinationDate); return this; } public void setVaccinationDate(LocalDate vaccinationDate) { - formParameter("vaccinationDate", vaccinationDate); + formParameter("vaccinationDate", vaccinationDate); } public PostVaccinationFormDataSendActionBuilder vaccinationDate(String vaccinationDateExpression) { - formParameter("vaccinationDate", vaccinationDateExpression); + formParameter("vaccinationDate", vaccinationDateExpression); return this; } public void setVaccinationDate(String vaccinationDateExpression) { - formParameter("vaccinationDate", vaccinationDateExpression); + formParameter("vaccinationDate", vaccinationDateExpression); } @Override @@ -3763,7 +3751,7 @@ public SendMessageAction doBuild() { } public static class PostVaccinationFormDataReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -3771,7 +3759,7 @@ public static class PostVaccinationFormDataReceiveActionBuilder extends private static final String OPERATION_NAME = "postVaccinationFormData"; - public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3792,7 +3780,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithArrayQueryDataSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3816,8 +3804,8 @@ public UpdatePetWithArrayQueryDataSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithArrayQueryDataSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithArrayQueryDataSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("name", _nameExpression, ParameterStyle.FORM, true, false); queryParameter("status", statusExpression, ParameterStyle.FORM, true, false); @@ -3846,7 +3834,7 @@ public UpdatePetWithArrayQueryDataSendActionBuilder petId(Long petId) { public UpdatePetWithArrayQueryDataSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithArrayQueryDataSendActionBuilder _name(String _name) { @@ -3859,12 +3847,12 @@ public UpdatePetWithArrayQueryDataSendActionBuilder status(String status) { return this; } - public UpdatePetWithArrayQueryDataSendActionBuilder tags(String...tags) { + public UpdatePetWithArrayQueryDataSendActionBuilder tags(String... tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); return this; } - public UpdatePetWithArrayQueryDataSendActionBuilder nicknames(String...nicknames) { + public UpdatePetWithArrayQueryDataSendActionBuilder nicknames(String... nicknames) { queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); return this; } @@ -3904,7 +3892,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithArrayQueryDataReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3912,7 +3900,7 @@ public static class UpdatePetWithArrayQueryDataReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithArrayQueryData"; - public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3933,7 +3921,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithFormUrlEncodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3947,22 +3935,22 @@ public static class UpdatePetWithFormUrlEncodedSendActionBuilder extends public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, String _name, String status, Integer age, List tags) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - formParameter("name", _name); - formParameter("status", status); - formParameter("age", age); - formParameter("tags", tags); + formParameter("name", _name); + formParameter("status", status); + formParameter("age", age); + formParameter("tags", tags); } /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - formParameter("name", _nameExpression); - formParameter("status", statusExpression); - formParameter("age", ageExpression); - formParameter("tags", tagsExpression); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tagsExpression); } /** @@ -3971,10 +3959,10 @@ public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApi public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tags) { super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - formParameter("name", _nameExpression); - formParameter("status", statusExpression); - formParameter("age", ageExpression); - formParameter("tags", tags); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tags); } public UpdatePetWithFormUrlEncodedSendActionBuilder petId(Long petId) { @@ -3984,59 +3972,59 @@ public UpdatePetWithFormUrlEncodedSendActionBuilder petId(Long petId) { public UpdatePetWithFormUrlEncodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder _name(String _name) { - formParameter("name", _name); + formParameter("name", _name); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder status(String status) { - formParameter("status", status); + formParameter("status", status); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder age(Integer age) { - formParameter("age", age); + formParameter("age", age); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder age(String ageExpression) { - formParameter("age", ageExpression); - return this; + formParameter("age", ageExpression); + return this; } - public UpdatePetWithFormUrlEncodedSendActionBuilder tags(String...tags) { - formParameter("tags", tags); + public UpdatePetWithFormUrlEncodedSendActionBuilder tags(String... tags) { + formParameter("tags", tags); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder owners(Integer owners) { - formParameter("owners", owners); + formParameter("owners", owners); return this; } public void setOwners(Integer owners) { - formParameter("owners", owners); + formParameter("owners", owners); } public UpdatePetWithFormUrlEncodedSendActionBuilder owners(String ownersExpression) { - formParameter("owners", ownersExpression); + formParameter("owners", ownersExpression); return this; } public void setOwners(String ownersExpression) { - formParameter("owners", ownersExpression); + formParameter("owners", ownersExpression); } - public UpdatePetWithFormUrlEncodedSendActionBuilder nicknames(String...nicknames) { - formParameter("nicknames", nicknames); + public UpdatePetWithFormUrlEncodedSendActionBuilder nicknames(String... nicknames) { + formParameter("nicknames", nicknames); return this; } - public void setNicknames(String...nicknames) { - formParameter("nicknames", nicknames); + public void setNicknames(String... nicknames) { + formParameter("nicknames", nicknames); } @Override @@ -4051,7 +4039,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithFormUrlEncodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -4059,7 +4047,7 @@ public static class UpdatePetWithFormUrlEncodedReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithFormUrlEncoded"; - public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index 3929d725f9..f527937765 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -1,16 +1,17 @@ package org.citrusframework.openapi.generator.rest.extpetstore.spring; -import java.util.List; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; + +import java.util.List; @Configuration @@ -21,11 +22,11 @@ public class ExtPetStoreBeanConfiguration { public OpenApiRepository extPetStoreOpenApiRepository() { var openApiRepository = new OpenApiRepository(); openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( - ExtPetStore.extPetStoreApi())); + ExtPetStore.extPetStoreApi())); return openApiRepository; } - @Bean(name="ExtPetApi") + @Bean(name = "ExtPetApi") public ExtPetApi extPetApi(@Qualifier("extpetstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new ExtPetApi(endpoint, customizers); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index 3676ef192e..52e08f2e11 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -1,242 +1,242 @@ package org.citrusframework.openapi.generator.rest.extpetstore.spring; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( - ExtPetStore.extPetStoreApi()); + ExtPetStore.extPetStoreApi()); @Override public void init() { - registerOperationParsers(ExtPetApi.class,"generate-vaccination-report", "generateVaccinationReport", "/pet/vaccination/status-report", + registerOperationParsers(ExtPetApi.class, "generate-vaccination-report", "generateVaccinationReport", "/pet/vaccination/status-report", ExtPetApi.GenerateVaccinationReportSendActionBuilder.class, ExtPetApi.GenerateVaccinationReportReceiveActionBuilder.class, - new String[]{ "template", "reqIntVal" }, - new String[]{ "optIntVal", "optBoolVal", "optNumberVal", "optStringVal", "optDateVal", "additionalData", "schema" }); + new String[]{"template", "reqIntVal"}, + new String[]{"optIntVal", "optBoolVal", "optNumberVal", "optStringVal", "optDateVal", "additionalData", "schema"}); - registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-api-key-authentication", "getPetByIdWithApiKeyAuthentication", "/secure-api-key/pet/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-api-key-authentication", "getPetByIdWithApiKeyAuthentication", "/secure-api-key/pet/{petId}", ExtPetApi.GetPetByIdWithApiKeyAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder.class, - new String[]{ "petId", "allDetails" }, - new String[]{ "details", "requesterInformation", "apiKeyQuery", "apiKeyHeader", "apiKeyCookie" }); + new String[]{"petId", "allDetails"}, + new String[]{"details", "requesterInformation", "apiKeyQuery", "apiKeyHeader", "apiKeyCookie"}); - registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-basic-authentication", "getPetByIdWithBasicAuthentication", "/secure-basic/pet/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-basic-authentication", "getPetByIdWithBasicAuthentication", "/secure-basic/pet/{petId}", ExtPetApi.GetPetByIdWithBasicAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithBasicAuthenticationReceiveActionBuilder.class, - new String[]{ "petId", "allDetails" }, - new String[]{ "details", "requesterInformation", "basicAuthUsername", "basicAuthPassword" }); + new String[]{"petId", "allDetails"}, + new String[]{"details", "requesterInformation", "basicAuthUsername", "basicAuthPassword"}); - registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-bearer-authentication", "getPetByIdWithBearerAuthentication", "/secure-bearer/pet/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-bearer-authentication", "getPetByIdWithBearerAuthentication", "/secure-bearer/pet/{petId}", ExtPetApi.GetPetByIdWithBearerAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithBearerAuthenticationReceiveActionBuilder.class, - new String[]{ "petId", "allDetails" }, - new String[]{ "details", "requesterInformation", "basicAuthBearer" }); + new String[]{"petId", "allDetails"}, + new String[]{"details", "requesterInformation", "basicAuthBearer"}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-cookie", "getPetWithCookie", "/pet/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-cookie", "getPetWithCookie", "/pet/{petId}", ExtPetApi.GetPetWithCookieSendActionBuilder.class, ExtPetApi.GetPetWithCookieReceiveActionBuilder.class, - new String[]{ "petId", "sessionId" }, - new String[]{ "optTrxId" }); + new String[]{"petId", "sessionId"}, + new String[]{"optTrxId"}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-deep-object-type-query", "getPetWithDeepObjectTypeQuery", "/pet/query/deep/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-deep-object-type-query", "getPetWithDeepObjectTypeQuery", "/pet/query/deep/object", ExtPetApi.GetPetWithDeepObjectTypeQuerySendActionBuilder.class, ExtPetApi.GetPetWithDeepObjectTypeQueryReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-exploded-style-cookie", "getPetWithFormExplodedStyleCookie", "/pet/cookie/form/exploded", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-exploded-style-cookie", "getPetWithFormExplodedStyleCookie", "/pet/cookie/form/exploded", ExtPetApi.GetPetWithFormExplodedStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormExplodedStyleCookieReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-object-style-cookie", "getPetWithFormObjectStyleCookie", "/pet/cookie/form/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-object-style-cookie", "getPetWithFormObjectStyleCookie", "/pet/cookie/form/object", ExtPetApi.GetPetWithFormObjectStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormObjectStyleCookieReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-cookie", "getPetWithFormStyleCookie", "/pet/cookie/form", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-cookie", "getPetWithFormStyleCookie", "/pet/cookie/form", ExtPetApi.GetPetWithFormStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormStyleCookieReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-object-query", "getPetWithFormStyleExplodedObjectQuery", "/pet/query/form/exploded/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-exploded-object-query", "getPetWithFormStyleExplodedObjectQuery", "/pet/query/form/exploded/object", ExtPetApi.GetPetWithFormStyleExplodedObjectQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-query", "getPetWithFormStyleExplodedQuery", "/pet/query/form/exploded", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-exploded-query", "getPetWithFormStyleExplodedQuery", "/pet/query/form/exploded", ExtPetApi.GetPetWithFormStyleExplodedQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleExplodedQueryReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-object-query", "getPetWithFormStyleObjectQuery", "/pet/query/form/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-object-query", "getPetWithFormStyleObjectQuery", "/pet/query/form/object", ExtPetApi.GetPetWithFormStyleObjectQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleObjectQueryReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-query", "getPetWithFormStyleQuery", "/pet/query/form", + registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-query", "getPetWithFormStyleQuery", "/pet/query/form", ExtPetApi.GetPetWithFormStyleQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleQueryReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array", "getPetWithLabelStyleArray", "/pet/label/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-array", "getPetWithLabelStyleArray", "/pet/label/{petId}", ExtPetApi.GetPetWithLabelStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleArrayReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array-exploded", "getPetWithLabelStyleArrayExploded", "/pet/label/exploded/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-array-exploded", "getPetWithLabelStyleArrayExploded", "/pet/label/exploded/{petId}", ExtPetApi.GetPetWithLabelStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleArrayExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object", "getPetWithLabelStyleObject", "/pet/label/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-object", "getPetWithLabelStyleObject", "/pet/label/object/{petId}", ExtPetApi.GetPetWithLabelStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleObjectReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object-exploded", "getPetWithLabelStyleObjectExploded", "/pet/label/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-object-exploded", "getPetWithLabelStyleObjectExploded", "/pet/label/exploded/object/{petId}", ExtPetApi.GetPetWithLabelStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleObjectExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array", "getPetWithMatrixStyleArray", "/pet/matrix/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-array", "getPetWithMatrixStyleArray", "/pet/matrix/{petId}", ExtPetApi.GetPetWithMatrixStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleArrayReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array-exploded", "getPetWithMatrixStyleArrayExploded", "/pet/matrix/exploded/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-array-exploded", "getPetWithMatrixStyleArrayExploded", "/pet/matrix/exploded/{petId}", ExtPetApi.GetPetWithMatrixStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object", "getPetWithMatrixStyleObject", "/pet/matrix/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-object", "getPetWithMatrixStyleObject", "/pet/matrix/object/{petId}", ExtPetApi.GetPetWithMatrixStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleObjectReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object-exploded", "getPetWithMatrixStyleObjectExploded", "/pet/matrix/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-object-exploded", "getPetWithMatrixStyleObjectExploded", "/pet/matrix/exploded/object/{petId}", ExtPetApi.GetPetWithMatrixStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", ExtPetApi.GetPetWithSimpleStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleArrayReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array-exploded", "getPetWithSimpleStyleArrayExploded", "/pet/simple/exploded/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-array-exploded", "getPetWithSimpleStyleArrayExploded", "/pet/simple/exploded/{petId}", ExtPetApi.GetPetWithSimpleStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-header", "getPetWithSimpleStyleExplodedHeader", "/pet/header/simple/exploded", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-exploded-header", "getPetWithSimpleStyleExplodedHeader", "/pet/header/simple/exploded", ExtPetApi.GetPetWithSimpleStyleExplodedHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-object-header", "getPetWithSimpleStyleExplodedObjectHeader", "/pet/header/simple/exploded/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-exploded-object-header", "getPetWithSimpleStyleExplodedObjectHeader", "/pet/header/simple/exploded/object", ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-header", "getPetWithSimpleStyleHeader", "/pet/header/simple", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-header", "getPetWithSimpleStyleHeader", "/pet/header/simple", ExtPetApi.GetPetWithSimpleStyleHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleHeaderReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object", "getPetWithSimpleStyleObject", "/pet/simple/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object", "getPetWithSimpleStyleObject", "/pet/simple/object/{petId}", ExtPetApi.GetPetWithSimpleStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-exploded", "getPetWithSimpleStyleObjectExploded", "/pet/simple/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object-exploded", "getPetWithSimpleStyleObjectExploded", "/pet/simple/exploded/object/{petId}", ExtPetApi.GetPetWithSimpleStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-header", "getPetWithSimpleStyleObjectHeader", "/pet/header/simple/object", + registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object-header", "getPetWithSimpleStyleObjectHeader", "/pet/header/simple/object", ExtPetApi.GetPetWithSimpleStyleObjectHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ }); + new String[]{"petId"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}", + registerOperationParsers(ExtPetApi.class, "post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}", ExtPetApi.PostVaccinationDocumentSendActionBuilder.class, ExtPetApi.PostVaccinationDocumentReceiveActionBuilder.class, - new String[]{ "bucket", "filename" }, - new String[]{ }); + new String[]{"bucket", "filename"}, + new String[]{}); - registerOperationParsers(ExtPetApi.class,"post-vaccination-form-data", "postVaccinationFormData", "/pet/vaccination/form", + registerOperationParsers(ExtPetApi.class, "post-vaccination-form-data", "postVaccinationFormData", "/pet/vaccination/form", ExtPetApi.PostVaccinationFormDataSendActionBuilder.class, ExtPetApi.PostVaccinationFormDataReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "vaccine", "isFirstVaccination", "doseNumber", "vaccinationDate" }); + new String[]{}, + new String[]{"vaccine", "isFirstVaccination", "doseNumber", "vaccinationDate"}); - registerOperationParsers(ExtPetApi.class,"update-pet-with-array-query-data", "updatePetWithArrayQueryData", "/pet/{petId}", + registerOperationParsers(ExtPetApi.class, "update-pet-with-array-query-data", "updatePetWithArrayQueryData", "/pet/{petId}", ExtPetApi.UpdatePetWithArrayQueryDataSendActionBuilder.class, ExtPetApi.UpdatePetWithArrayQueryDataReceiveActionBuilder.class, - new String[]{ "petId", "_name", "status", "tags", "nicknames", "sampleStringHeader" }, - new String[]{ "sampleIntHeader" }); + new String[]{"petId", "_name", "status", "tags", "nicknames", "sampleStringHeader"}, + new String[]{"sampleIntHeader"}); - registerOperationParsers(ExtPetApi.class,"update-pet-with-form-url-encoded", "updatePetWithFormUrlEncoded", "/pet/form/{petId}", + registerOperationParsers(ExtPetApi.class, "update-pet-with-form-url-encoded", "updatePetWithFormUrlEncoded", "/pet/form/{petId}", ExtPetApi.UpdatePetWithFormUrlEncodedSendActionBuilder.class, ExtPetApi.UpdatePetWithFormUrlEncodedReceiveActionBuilder.class, - new String[]{ "petId", "_name", "status", "age", "tags" }, - new String[]{ "owners", "nicknames" }); + new String[]{"petId", "_name", "status", "age", "tags"}, + new String[]{"owners", "nicknames"}); } private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, - Class sendBeanClass, - Class receiveBeanClass, - String[] constructorParameters, - String[] nonConstructorParameters) { + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, - path, - apiClass, - sendBeanClass, - receiveBeanClass, - "extpetstore.endpoint"); + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "extpetstore.endpoint"); sendParser.setConstructorParameters(constructorParameters); sendParser.setNonConstructorParameters(nonConstructorParameters); - registerBeanDefinitionParser("send-"+elementName, sendParser); + registerBeanDefinitionParser("send-" + elementName, sendParser); RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, - operationName, apiClass, receiveBeanClass, "extpetstore.endpoint"); - registerBeanDefinitionParser("receive-"+elementName, receiveParser); + operationName, apiClass, receiveBeanClass, "extpetstore.endpoint"); + registerBeanDefinitionParser("receive-" + elementName, receiveParser); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index dd280d1b47..da3af60ddf 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -1,171 +1,172 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * Address */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Address { - private String street; + private String street; + + private String city; - private String city; + private String state; - private String state; + private String zip; - private String zip; + public Address() { + } - public Address() { - } + public Address street(String street) { - public Address street(String street) { - - this.street = street; - return this; - } + this.street = street; + return this; + } - /** - * Get street - * @return street - **/ - @jakarta.annotation.Nullable + /** + * Get street + * + * @return street + **/ + @jakarta.annotation.Nullable - public String getStreet() { - return street; - } + public String getStreet() { + return street; + } - public void setStreet(String street) { - this.street = street; - } + public void setStreet(String street) { + this.street = street; + } - public Address city(String city) { - - this.city = city; - return this; - } + public Address city(String city) { + + this.city = city; + return this; + } + + /** + * Get city + * + * @return city + **/ + @jakarta.annotation.Nullable + + public String getCity() { + return city; + } + + + public void setCity(String city) { + this.city = city; + } + + + public Address state(String state) { + + this.state = state; + return this; + } + + /** + * Get state + * + * @return state + **/ + @jakarta.annotation.Nullable + + public String getState() { + return state; + } - /** - * Get city - * @return city - **/ - @jakarta.annotation.Nullable - - public String getCity() { - return city; - } - - - public void setCity(String city) { - this.city = city; - } - - - public Address state(String state) { - - this.state = state; - return this; - } - - /** - * Get state - * @return state - **/ - @jakarta.annotation.Nullable - - public String getState() { - return state; - } - - - public void setState(String state) { - this.state = state; - } - - - public Address zip(String zip) { - - this.zip = zip; - return this; - } - - /** - * Get zip - * @return zip - **/ - @jakarta.annotation.Nullable - - public String getZip() { - return zip; - } - - - public void setZip(String zip) { - this.zip = zip; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Address address = (Address) o; - return Objects.equals(this.street, address.street) && - Objects.equals(this.city, address.city) && - Objects.equals(this.state, address.state) && - Objects.equals(this.zip, address.zip); - } - - @Override - public int hashCode() { - return Objects.hash(street, city, state, zip); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Address {\n"); - sb.append(" street: ").append(toIndentedString(street)).append("\n"); - sb.append(" city: ").append(toIndentedString(city)).append("\n"); - sb.append(" state: ").append(toIndentedString(state)).append("\n"); - sb.append(" zip: ").append(toIndentedString(zip)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + + public void setState(String state) { + this.state = state; + } + + + public Address zip(String zip) { + + this.zip = zip; + return this; + } + + /** + * Get zip + * + * @return zip + **/ + @jakarta.annotation.Nullable + + public String getZip() { + return zip; + } + + + public void setZip(String zip) { + this.zip = zip; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Address address = (Address) o; + return Objects.equals(this.street, address.street) && + Objects.equals(this.city, address.city) && + Objects.equals(this.state, address.state) && + Objects.equals(this.zip, address.zip); + } + + @Override + public int hashCode() { + return Objects.hash(street, city, state, zip); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Address {\n"); + sb.append(" street: ").append(toIndentedString(street)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" zip: ").append(toIndentedString(zip)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index 15ad5a078c..a76481be55 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -1,119 +1,118 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * Category */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Category { - private Long id; + private Long id; + + private String _name; - private String _name; + public Category() { + } - public Category() { - } + public Category id(Long id) { - public Category id(Long id) { - - this.id = id; - return this; - } + this.id = id; + return this; + } + + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public Category _name(String _name) { + this._name = _name; + return this; + } - public Category _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public String getName() { - return _name; - } + public void setName(String _name) { + this._name = _name; + } - public void setName(String _name) { - this._name = _name; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(id, _name); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); } - Category category = (Category) o; - return Objects.equals(this.id, category.id) && - Objects.equals(this._name, category._name); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Category {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index 6e9a6cb7ca..d541f5317b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -1,157 +1,157 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; +import org.citrusframework.openapi.generator.rest.petstore.model.Address; + import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import org.citrusframework.openapi.generator.rest.petstore.model.Address; +import java.util.Objects; /** * Customer */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Customer { - private Long id; + private Long id; - private String username; + private String username; - private List
      address = new ArrayList<>(); + private List
      address = new ArrayList<>(); - public Customer() { - } + public Customer() { + } - public Customer id(Long id) { - - this.id = id; - return this; - } + public Customer id(Long id) { - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable + this.id = id; + return this; + } - public Long getId() { - return id; - } + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable + public Long getId() { + return id; + } - public void setId(Long id) { - this.id = id; - } + public void setId(Long id) { + this.id = id; + } - public Customer username(String username) { - - this.username = username; - return this; - } - /** - * Get username - * @return username - **/ - @jakarta.annotation.Nullable + public Customer username(String username) { - public String getUsername() { - return username; - } + this.username = username; + return this; + } + /** + * Get username + * + * @return username + **/ + @jakarta.annotation.Nullable - public void setUsername(String username) { - this.username = username; - } + public String getUsername() { + return username; + } - public Customer address(List
      address) { - - this.address = address; - return this; - } + public void setUsername(String username) { + this.username = username; + } + + + public Customer address(List
      address) { - public Customer addAddressItem(Address addressItem) { - if (this.address == null) { - this.address = new ArrayList<>(); + this.address = address; + return this; } - this.address.add(addressItem); - return this; - } - /** - * Get address - * @return address - **/ - @jakarta.annotation.Nullable + public Customer addAddressItem(Address addressItem) { + if (this.address == null) { + this.address = new ArrayList<>(); + } + this.address.add(addressItem); + return this; + } - public List
      getAddress() { - return address; - } + /** + * Get address + * + * @return address + **/ + @jakarta.annotation.Nullable + public List
      getAddress() { + return address; + } - public void setAddress(List
      address) { - this.address = address; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + public void setAddress(List
      address) { + this.address = address; } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Customer customer = (Customer) o; + return Objects.equals(this.id, customer.id) && + Objects.equals(this.username, customer.username) && + Objects.equals(this.address, customer.address); } - Customer customer = (Customer) o; - return Objects.equals(this.id, customer.id) && - Objects.equals(this.username, customer.username) && - Objects.equals(this.address, customer.address); - } - - @Override - public int hashCode() { - return Objects.hash(id, username, address); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Customer {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" username: ").append(toIndentedString(username)).append("\n"); - sb.append(" address: ").append(toIndentedString(address)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + @Override + public int hashCode() { + return Objects.hash(id, username, address); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Customer {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" address: ").append(toIndentedString(address)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index 9d60ff92ad..27d204e2cb 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -1,145 +1,145 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * ModelApiResponse */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ModelApiResponse { - private Integer code; + private Integer code; + + private String type; - private String type; + private String _message; - private String _message; + public ModelApiResponse() { + } - public ModelApiResponse() { - } + public ModelApiResponse code(Integer code) { + + this.code = code; + return this; + } - public ModelApiResponse code(Integer code) { - - this.code = code; - return this; - } + /** + * Get code + * + * @return code + **/ + @jakarta.annotation.Nullable - /** - * Get code - * @return code - **/ - @jakarta.annotation.Nullable + public Integer getCode() { + return code; + } + + + public void setCode(Integer code) { + this.code = code; + } - public Integer getCode() { - return code; - } + public ModelApiResponse type(String type) { - public void setCode(Integer code) { - this.code = code; - } + this.type = type; + return this; + } + /** + * Get type + * + * @return type + **/ + @jakarta.annotation.Nullable - public ModelApiResponse type(String type) { - - this.type = type; - return this; - } + public String getType() { + return type; + } - /** - * Get type - * @return type - **/ - @jakarta.annotation.Nullable - public String getType() { - return type; - } + public void setType(String type) { + this.type = type; + } - public void setType(String type) { - this.type = type; - } + public ModelApiResponse _message(String _message) { + this._message = _message; + return this; + } - public ModelApiResponse _message(String _message) { - - this._message = _message; - return this; - } + /** + * Get _message + * + * @return _message + **/ + @jakarta.annotation.Nullable - /** - * Get _message - * @return _message - **/ - @jakarta.annotation.Nullable + public String getMessage() { + return _message; + } - public String getMessage() { - return _message; - } + public void setMessage(String _message) { + this._message = _message; + } - public void setMessage(String _message) { - this._message = _message; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ModelApiResponse _apiResponse = (ModelApiResponse) o; + return Objects.equals(this.code, _apiResponse.code) && + Objects.equals(this.type, _apiResponse.type) && + Objects.equals(this._message, _apiResponse._message); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(code, type, _message); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ModelApiResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" _message: ").append(toIndentedString(_message)).append("\n"); + sb.append("}"); + return sb.toString(); } - ModelApiResponse _apiResponse = (ModelApiResponse) o; - return Objects.equals(this.code, _apiResponse.code) && - Objects.equals(this.type, _apiResponse.type) && - Objects.equals(this._message, _apiResponse._message); - } - - @Override - public int hashCode() { - return Objects.hash(code, type, _message); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class ModelApiResponse {\n"); - sb.append(" code: ").append(toIndentedString(code)).append("\n"); - sb.append(" type: ").append(toIndentedString(type)).append("\n"); - sb.append(" _message: ").append(toIndentedString(_message)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index b97c340cc5..080663a5bb 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -1,259 +1,249 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import java.time.OffsetDateTime; +import java.util.Objects; /** * Order */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Order { - private Long id; + private Long id; - private Long petId; + private Long petId; - private Integer quantity; + private Integer quantity; - private OffsetDateTime shipDate; + private OffsetDateTime shipDate; + private StatusEnum status; + private Boolean complete; - /** - * Order Status - */ - public enum StatusEnum { - PLACED("placed"), - - APPROVED("approved"), - - DELIVERED("delivered"); + public Order() { + } - private String value; + public Order id(Long id) { - StatusEnum(String value) { - this.value = value; + this.id = id; + return this; } - public String getValue() { - return value; - } + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable - @Override - public String toString() { - return String.valueOf(value); + public Long getId() { + return id; } - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); + public void setId(Long id) { + this.id = id; } - } - - private StatusEnum status; - private Boolean complete; + public Order petId(Long petId) { - public Order() { - } - - public Order id(Long id) { - - this.id = id; - return this; - } + this.petId = petId; + return this; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable + /** + * Get petId + * + * @return petId + **/ + @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public Long getPetId() { + return petId; + } + public void setPetId(Long petId) { + this.petId = petId; + } - public void setId(Long id) { - this.id = id; - } + public Order quantity(Integer quantity) { + this.quantity = quantity; + return this; + } - public Order petId(Long petId) { - - this.petId = petId; - return this; - } + /** + * Get quantity + * + * @return quantity + **/ + @jakarta.annotation.Nullable - /** - * Get petId - * @return petId - **/ - @jakarta.annotation.Nullable + public Integer getQuantity() { + return quantity; + } - public Long getPetId() { - return petId; - } + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + public Order shipDate(OffsetDateTime shipDate) { - public void setPetId(Long petId) { - this.petId = petId; - } + this.shipDate = shipDate; + return this; + } + /** + * Get shipDate + * + * @return shipDate + **/ + @jakarta.annotation.Nullable - public Order quantity(Integer quantity) { - - this.quantity = quantity; - return this; - } + public OffsetDateTime getShipDate() { + return shipDate; + } - /** - * Get quantity - * @return quantity - **/ - @jakarta.annotation.Nullable + public void setShipDate(OffsetDateTime shipDate) { + this.shipDate = shipDate; + } - public Integer getQuantity() { - return quantity; - } + public Order status(StatusEnum status) { + this.status = status; + return this; + } - public void setQuantity(Integer quantity) { - this.quantity = quantity; - } + /** + * Order Status + * + * @return status + **/ + @jakarta.annotation.Nullable + public StatusEnum getStatus() { + return status; + } - public Order shipDate(OffsetDateTime shipDate) { - - this.shipDate = shipDate; - return this; - } + public void setStatus(StatusEnum status) { + this.status = status; + } - /** - * Get shipDate - * @return shipDate - **/ - @jakarta.annotation.Nullable + public Order complete(Boolean complete) { - public OffsetDateTime getShipDate() { - return shipDate; - } + this.complete = complete; + return this; + } + /** + * Get complete + * + * @return complete + **/ + @jakarta.annotation.Nullable - public void setShipDate(OffsetDateTime shipDate) { - this.shipDate = shipDate; - } + public Boolean getComplete() { + return complete; + } + public void setComplete(Boolean complete) { + this.complete = complete; + } - public Order status(StatusEnum status) { - - this.status = status; - return this; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(this.id, order.id) && + Objects.equals(this.petId, order.petId) && + Objects.equals(this.quantity, order.quantity) && + Objects.equals(this.shipDate, order.shipDate) && + Objects.equals(this.status, order.status) && + Objects.equals(this.complete, order.complete); + } - /** - * Order Status - * @return status - **/ - @jakarta.annotation.Nullable + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } - public StatusEnum getStatus() { - return status; - } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } - public void setStatus(StatusEnum status) { - this.status = status; - } + /** + * Order Status + */ + public enum StatusEnum { + PLACED("placed"), + APPROVED("approved"), - public Order complete(Boolean complete) { - - this.complete = complete; - return this; - } + DELIVERED("delivered"); - /** - * Get complete - * @return complete - **/ - @jakarta.annotation.Nullable + private String value; - public Boolean getComplete() { - return complete; - } + StatusEnum(String value) { + this.value = value; + } + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } - public void setComplete(Boolean complete) { - this.complete = complete; - } + public String getValue() { + return value; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Order order = (Order) o; - return Objects.equals(this.id, order.id) && - Objects.equals(this.petId, order.petId) && - Objects.equals(this.quantity, order.quantity) && - Objects.equals(this.shipDate, order.shipDate) && - Objects.equals(this.status, order.status) && - Objects.equals(this.complete, order.complete); - } - - @Override - public int hashCode() { - return Objects.hash(id, petId, quantity, shipDate, status, complete); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Order {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); - sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); - sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + @Override + public String toString() { + return String.valueOf(value); + } } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index 1bd1bebb69..b330e39068 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -1,279 +1,270 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; -import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import org.citrusframework.openapi.generator.rest.petstore.model.Category; import org.citrusframework.openapi.generator.rest.petstore.model.Tag; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + /** * Pet */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Pet { - private Long id; + private Long id; - private String _name; + private String _name; - private Category category; + private Category category; - private List photoUrls = new ArrayList<>(); + private List photoUrls = new ArrayList<>(); - private List tags = new ArrayList<>(); + private List tags = new ArrayList<>(); + private StatusEnum status; - /** - * pet status in the store - */ - public enum StatusEnum { - AVAILABLE("available"), - - PENDING("pending"), - - SOLD("sold"); + public Pet() { + } - private String value; + public Pet id(Long id) { - StatusEnum(String value) { - this.value = value; + this.id = id; + return this; } - public String getValue() { - return value; - } + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable - @Override - public String toString() { - return String.valueOf(value); + public Long getId() { + return id; } - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); + public void setId(Long id) { + this.id = id; } - } - - private StatusEnum status; - public Pet() { - } + public Pet _name(String _name) { - public Pet id(Long id) { - - this.id = id; - return this; - } + this._name = _name; + return this; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nonnull - public Long getId() { - return id; - } + public String getName() { + return _name; + } + public void setName(String _name) { + this._name = _name; + } - public void setId(Long id) { - this.id = id; - } + public Pet category(Category category) { + this.category = category; + return this; + } - public Pet _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get category + * + * @return category + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nonnull + public Category getCategory() { + return category; + } - public String getName() { - return _name; - } + public void setCategory(Category category) { + this.category = category; + } + public Pet photoUrls(List photoUrls) { - public void setName(String _name) { - this._name = _name; - } + this.photoUrls = photoUrls; + return this; + } + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); + } + this.photoUrls.add(photoUrlsItem); + return this; + } - public Pet category(Category category) { - - this.category = category; - return this; - } + /** + * Get photoUrls + * + * @return photoUrls + **/ + @jakarta.annotation.Nonnull - /** - * Get category - * @return category - **/ - @jakarta.annotation.Nullable + public List getPhotoUrls() { + return photoUrls; + } - public Category getCategory() { - return category; - } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } + public Pet tags(List tags) { - public void setCategory(Category category) { - this.category = category; - } + this.tags = tags; + return this; + } + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); + } + this.tags.add(tagsItem); + return this; + } - public Pet photoUrls(List photoUrls) { - - this.photoUrls = photoUrls; - return this; - } + /** + * Get tags + * + * @return tags + **/ + @jakarta.annotation.Nullable - public Pet addPhotoUrlsItem(String photoUrlsItem) { - if (this.photoUrls == null) { - this.photoUrls = new ArrayList<>(); + public List getTags() { + return tags; } - this.photoUrls.add(photoUrlsItem); - return this; - } - /** - * Get photoUrls - * @return photoUrls - **/ - @jakarta.annotation.Nonnull + public void setTags(List tags) { + this.tags = tags; + } - public List getPhotoUrls() { - return photoUrls; - } + public Pet status(StatusEnum status) { + this.status = status; + return this; + } - public void setPhotoUrls(List photoUrls) { - this.photoUrls = photoUrls; - } + /** + * pet status in the store + * + * @return status + **/ + @jakarta.annotation.Nullable + public StatusEnum getStatus() { + return status; + } - public Pet tags(List tags) { - - this.tags = tags; - return this; - } + public void setStatus(StatusEnum status) { + this.status = status; + } - public Pet addTagsItem(Tag tagsItem) { - if (this.tags == null) { - this.tags = new ArrayList<>(); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); } - this.tags.add(tagsItem); - return this; - } - /** - * Get tags - * @return tags - **/ - @jakarta.annotation.Nullable + @Override + public int hashCode() { + return Objects.hash(id, _name, category, photoUrls, tags, status); + } - public List getTags() { - return tags; - } + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } - public void setTags(List tags) { - this.tags = tags; - } + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + PENDING("pending"), - public Pet status(StatusEnum status) { - - this.status = status; - return this; - } + SOLD("sold"); - /** - * pet status in the store - * @return status - **/ - @jakarta.annotation.Nullable + private String value; - public StatusEnum getStatus() { - return status; - } + StatusEnum(String value) { + this.value = value; + } + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); + } - public void setStatus(StatusEnum status) { - this.status = status; - } + public String getValue() { + return value; + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Pet pet = (Pet) o; - return Objects.equals(this.id, pet.id) && - Objects.equals(this._name, pet._name) && - Objects.equals(this.category, pet.category) && - Objects.equals(this.photoUrls, pet.photoUrls) && - Objects.equals(this.tags, pet.tags) && - Objects.equals(this.status, pet.status); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name, category, photoUrls, tags, status); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Pet {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append(" category: ").append(toIndentedString(category)).append("\n"); - sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); - sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + @Override + public String toString() { + return String.valueOf(value); + } } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index 90947c523b..59a5de829b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -1,119 +1,118 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * Tag */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Tag { - private Long id; + private Long id; + + private String _name; - private String _name; + public Tag() { + } - public Tag() { - } + public Tag id(Long id) { - public Tag id(Long id) { - - this.id = id; - return this; - } + this.id = id; + return this; + } + + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable + + public Long getId() { + return id; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public Tag _name(String _name) { + this._name = _name; + return this; + } - public Tag _name(String _name) { - - this._name = _name; - return this; - } + /** + * Get _name + * + * @return _name + **/ + @jakarta.annotation.Nullable - /** - * Get _name - * @return _name - **/ - @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public String getName() { - return _name; - } + public void setName(String _name) { + this._name = _name; + } - public void setName(String _name) { - this._name = _name; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(id, _name); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); } - Tag tag = (Tag) o; - return Objects.equals(this.id, tag.id) && - Objects.equals(this._name, tag._name); - } - - @Override - public int hashCode() { - return Objects.hash(id, _name); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Tag {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index ae722fc9d2..7a049fe569 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -1,275 +1,280 @@ /* -* Copyright the original author or authors. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; -import java.util.Arrays; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; /** * User */ @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class User { - private Long id; + private Long id; + + private String username; + + private String firstName; - private String username; + private String lastName; - private String firstName; + private String email; - private String lastName; + private String password; - private String email; + private String phone; - private String password; + private Integer userStatus; + + public User() { + } - private String phone; + public User id(Long id) { - private Integer userStatus; + this.id = id; + return this; + } - public User() { - } + /** + * Get id + * + * @return id + **/ + @jakarta.annotation.Nullable - public User id(Long id) { - - this.id = id; - return this; - } + public Long getId() { + return id; + } - /** - * Get id - * @return id - **/ - @jakarta.annotation.Nullable - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public User username(String username) { + this.username = username; + return this; + } - public User username(String username) { - - this.username = username; - return this; - } + /** + * Get username + * + * @return username + **/ + @jakarta.annotation.Nullable - /** - * Get username - * @return username - **/ - @jakarta.annotation.Nullable + public String getUsername() { + return username; + } - public String getUsername() { - return username; - } + + public void setUsername(String username) { + this.username = username; + } + + + public User firstName(String firstName) { + + this.firstName = firstName; + return this; + } + + /** + * Get firstName + * + * @return firstName + **/ + @jakarta.annotation.Nullable + + public String getFirstName() { + return firstName; + } - public void setUsername(String username) { - this.username = username; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public User firstName(String firstName) { - - this.firstName = firstName; - return this; - } + public User lastName(String lastName) { - /** - * Get firstName - * @return firstName - **/ - @jakarta.annotation.Nullable + this.lastName = lastName; + return this; + } - public String getFirstName() { - return firstName; - } + /** + * Get lastName + * + * @return lastName + **/ + @jakarta.annotation.Nullable + public String getLastName() { + return lastName; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public void setLastName(String lastName) { + this.lastName = lastName; + } - public User lastName(String lastName) { - - this.lastName = lastName; - return this; - } - /** - * Get lastName - * @return lastName - **/ - @jakarta.annotation.Nullable + public User email(String email) { - public String getLastName() { - return lastName; - } + this.email = email; + return this; + } + /** + * Get email + * + * @return email + **/ + @jakarta.annotation.Nullable - public void setLastName(String lastName) { - this.lastName = lastName; - } + public String getEmail() { + return email; + } - public User email(String email) { - - this.email = email; - return this; - } + public void setEmail(String email) { + this.email = email; + } - /** - * Get email - * @return email - **/ - @jakarta.annotation.Nullable - public String getEmail() { - return email; - } + public User password(String password) { + this.password = password; + return this; + } - public void setEmail(String email) { - this.email = email; - } + /** + * Get password + * + * @return password + **/ + @jakarta.annotation.Nullable + public String getPassword() { + return password; + } - public User password(String password) { - - this.password = password; - return this; - } - /** - * Get password - * @return password - **/ - @jakarta.annotation.Nullable + public void setPassword(String password) { + this.password = password; + } - public String getPassword() { - return password; - } + public User phone(String phone) { - public void setPassword(String password) { - this.password = password; - } + this.phone = phone; + return this; + } + /** + * Get phone + * + * @return phone + **/ + @jakarta.annotation.Nullable - public User phone(String phone) { - - this.phone = phone; - return this; - } + public String getPhone() { + return phone; + } - /** - * Get phone - * @return phone - **/ - @jakarta.annotation.Nullable - public String getPhone() { - return phone; - } + public void setPhone(String phone) { + this.phone = phone; + } - public void setPhone(String phone) { - this.phone = phone; - } + public User userStatus(Integer userStatus) { + this.userStatus = userStatus; + return this; + } - public User userStatus(Integer userStatus) { - - this.userStatus = userStatus; - return this; - } + /** + * User Status + * + * @return userStatus + **/ + @jakarta.annotation.Nullable - /** - * User Status - * @return userStatus - **/ - @jakarta.annotation.Nullable + public Integer getUserStatus() { + return userStatus; + } - public Integer getUserStatus() { - return userStatus; - } + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } - public void setUserStatus(Integer userStatus) { - this.userStatus = userStatus; - } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + User user = (User) o; + return Objects.equals(this.id, user.id) && + Objects.equals(this.username, user.username) && + Objects.equals(this.firstName, user.firstName) && + Objects.equals(this.lastName, user.lastName) && + Objects.equals(this.email, user.email) && + Objects.equals(this.password, user.password) && + Objects.equals(this.phone, user.phone) && + Objects.equals(this.userStatus, user.userStatus); + } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); } - if (o == null || getClass() != o.getClass()) { - return false; + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(toIndentedString(email)).append("\n"); + sb.append(" password: ").append(toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); } - User user = (User) o; - return Objects.equals(this.id, user.id) && - Objects.equals(this.username, user.username) && - Objects.equals(this.firstName, user.firstName) && - Objects.equals(this.lastName, user.lastName) && - Objects.equals(this.email, user.email) && - Objects.equals(this.password, user.password) && - Objects.equals(this.phone, user.phone) && - Objects.equals(this.userStatus, user.userStatus); - } - - @Override - public int hashCode() { - return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class User {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" username: ").append(toIndentedString(username)).append("\n"); - sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); - sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); - sb.append(" email: ").append(toIndentedString(email)).append("\n"); - sb.append(" password: ").append(toIndentedString(password)).append("\n"); - sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); - sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); } - return o.toString().replace("\n", "\n "); - } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index 7f10ddeb85..f68399a060 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -1,58 +1,46 @@ package org.citrusframework.openapi.generator.rest.petstore.request; -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static org.citrusframework.util.StringUtils.isEmpty; -import static org.citrusframework.util.StringUtils.isNotEmpty; - import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.net.URL; -import java.time.LocalDate; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; -import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.spi.Resource; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; +import java.net.URL; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; @SuppressWarnings("unused") @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetApi implements GeneratedApi -{ +public class PetApi implements GeneratedApi { + private final List customizers; + private final Endpoint endpoint; + private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; - @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - private final List customizers; - - private final Endpoint endpoint; - - private final OpenApiSpecification openApiSpecification; - - public PetApi(Endpoint endpoint) { + public PetApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public PetApi(Endpoint endpoint, List customizers) { + public PetApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -100,158 +88,158 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public AddPetSendActionBuilder sendAddPet() { - return new AddPetSendActionBuilder(this, openApiSpecification); + public AddPetSendActionBuilder sendAddPet() { + return new AddPetSendActionBuilder(this, openApiSpecification); } - public AddPetReceiveActionBuilder receiveAddPet(@NotNull HttpStatus statusCode) { + public AddPetReceiveActionBuilder receiveAddPet(@NotNull HttpStatus statusCode) { return new AddPetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public AddPetReceiveActionBuilder receiveAddPet(@NotNull String statusCode) { - return new AddPetReceiveActionBuilder(this, openApiSpecification, statusCode); + public AddPetReceiveActionBuilder receiveAddPet(@NotNull String statusCode) { + return new AddPetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public DeletePetSendActionBuilder sendDeletePet(Long petId) { - return new DeletePetSendActionBuilder(this, openApiSpecification, petId); + public DeletePetSendActionBuilder sendDeletePet(Long petId) { + return new DeletePetSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public DeletePetSendActionBuilder sendDeletePet$(String petIdExpression ) { - return new DeletePetSendActionBuilder(openApiSpecification, this, petIdExpression); + public DeletePetSendActionBuilder sendDeletePet$(String petIdExpression) { + return new DeletePetSendActionBuilder(openApiSpecification, this, petIdExpression); } - public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull HttpStatus statusCode) { + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull HttpStatus statusCode) { return new DeletePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull String statusCode) { - return new DeletePetReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull String statusCode) { + return new DeletePetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public FindPetsByStatusSendActionBuilder sendFindPetsByStatus() { - return new FindPetsByStatusSendActionBuilder(this, openApiSpecification); + public FindPetsByStatusSendActionBuilder sendFindPetsByStatus() { + return new FindPetsByStatusSendActionBuilder(this, openApiSpecification); } - public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull HttpStatus statusCode) { + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull HttpStatus statusCode) { return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull String statusCode) { - return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, statusCode); + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull String statusCode) { + return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public FindPetsByTagsSendActionBuilder sendFindPetsByTags() { - return new FindPetsByTagsSendActionBuilder(this, openApiSpecification); + public FindPetsByTagsSendActionBuilder sendFindPetsByTags() { + return new FindPetsByTagsSendActionBuilder(this, openApiSpecification); } - public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull HttpStatus statusCode) { + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull HttpStatus statusCode) { return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull String statusCode) { - return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, statusCode); + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull String statusCode) { + return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdSendActionBuilder sendGetPetById(Long petId) { - GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(this, openApiSpecification, petId); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetPetByIdSendActionBuilder sendGetPetById(Long petId) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(this, openApiSpecification, petId); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetPetByIdSendActionBuilder sendGetPetById$(String petIdExpression ) { - GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(openApiSpecification, this, petIdExpression); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - builder.setApiKey(defaultApiKey); - return builder; + public GetPetByIdSendActionBuilder sendGetPetById$(String petIdExpression) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(openApiSpecification, this, petIdExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKey(defaultApiKey); + return builder; } - public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull HttpStatus statusCode) { + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull HttpStatus statusCode) { return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull String statusCode) { - return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull String statusCode) { + return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetSendActionBuilder sendUpdatePet() { - return new UpdatePetSendActionBuilder(this, openApiSpecification); + public UpdatePetSendActionBuilder sendUpdatePet() { + return new UpdatePetSendActionBuilder(this, openApiSpecification); } - public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull HttpStatus statusCode) { + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull HttpStatus statusCode) { return new UpdatePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull String statusCode) { - return new UpdatePetReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull String statusCode) { + return new UpdatePetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm(Long petId) { - return new UpdatePetWithFormSendActionBuilder(this, openApiSpecification, petId); + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm(Long petId) { + return new UpdatePetWithFormSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm$(String petIdExpression ) { - return new UpdatePetWithFormSendActionBuilder(openApiSpecification, this, petIdExpression); + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm$(String petIdExpression) { + return new UpdatePetWithFormSendActionBuilder(openApiSpecification, this, petIdExpression); } - public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull HttpStatus statusCode) { + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull HttpStatus statusCode) { return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull String statusCode) { - return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull String statusCode) { + return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UploadFileSendActionBuilder sendUploadFile(Long petId) { - return new UploadFileSendActionBuilder(this, openApiSpecification, petId); + public UploadFileSendActionBuilder sendUploadFile(Long petId) { + return new UploadFileSendActionBuilder(this, openApiSpecification, petId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public UploadFileSendActionBuilder sendUploadFile$(String petIdExpression ) { - return new UploadFileSendActionBuilder(openApiSpecification, this, petIdExpression); + public UploadFileSendActionBuilder sendUploadFile$(String petIdExpression) { + return new UploadFileSendActionBuilder(openApiSpecification, this, petIdExpression); } - public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull HttpStatus statusCode) { + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull HttpStatus statusCode) { return new UploadFileReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull String statusCode) { - return new UploadFileReceiveActionBuilder(this, openApiSpecification, statusCode); + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull String statusCode) { + return new UploadFileReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class AddPetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -282,7 +270,7 @@ public SendMessageAction doBuild() { } public static class AddPetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -290,7 +278,7 @@ public static class AddPetReceiveActionBuilder extends private static final String OPERATION_NAME = "addPet"; - public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -311,7 +299,7 @@ public ReceiveMessageAction doBuild() { } public static class DeletePetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -330,8 +318,8 @@ public DeletePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpe /** * Constructor with required parameters as string to allow for dynamic content. */ - public DeletePetSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public DeletePetSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -350,7 +338,7 @@ public DeletePetSendActionBuilder petId(Long petId) { public DeletePetSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public DeletePetSendActionBuilder apiKey(String apiKey) { @@ -374,7 +362,7 @@ public SendMessageAction doBuild() { } public static class DeletePetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -382,7 +370,7 @@ public static class DeletePetReceiveActionBuilder extends private static final String OPERATION_NAME = "deletePet"; - public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -403,7 +391,7 @@ public ReceiveMessageAction doBuild() { } public static class FindPetsByStatusSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -443,7 +431,7 @@ public SendMessageAction doBuild() { } public static class FindPetsByStatusReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -451,7 +439,7 @@ public static class FindPetsByStatusReceiveActionBuilder extends private static final String OPERATION_NAME = "findPetsByStatus"; - public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -472,7 +460,7 @@ public ReceiveMessageAction doBuild() { } public static class FindPetsByTagsSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -491,12 +479,12 @@ public FindPetsByTagsSendActionBuilder(PetApi petApi, OpenApiSpecification openA super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); } - public FindPetsByTagsSendActionBuilder tags(String...tags) { + public FindPetsByTagsSendActionBuilder tags(String... tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); return this; } - public void setTags(String...tags) { + public void setTags(String... tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); } @@ -512,7 +500,7 @@ public SendMessageAction doBuild() { } public static class FindPetsByTagsReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -520,7 +508,7 @@ public static class FindPetsByTagsReceiveActionBuilder extends private static final String OPERATION_NAME = "findPetsByTags"; - public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -541,7 +529,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -568,8 +556,8 @@ public GetPetByIdSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -588,7 +576,7 @@ public GetPetByIdSendActionBuilder petId(Long petId) { public GetPetByIdSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public void setBase64EncodeApiKey(boolean encode) { @@ -617,7 +605,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -625,7 +613,7 @@ public static class GetPetByIdReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetById"; - public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -646,7 +634,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -677,7 +665,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -685,7 +673,7 @@ public static class UpdatePetReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePet"; - public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -706,7 +694,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithFormSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -725,8 +713,8 @@ public UpdatePetWithFormSendActionBuilder(PetApi petApi, OpenApiSpecification op /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithFormSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -745,7 +733,7 @@ public UpdatePetWithFormSendActionBuilder petId(Long petId) { public UpdatePetWithFormSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithFormSendActionBuilder _name(String _name) { @@ -778,7 +766,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithFormReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -786,7 +774,7 @@ public static class UpdatePetWithFormReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithForm"; - public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -807,7 +795,7 @@ public ReceiveMessageAction doBuild() { } public static class UploadFileSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -826,8 +814,8 @@ public UploadFileSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public UploadFileSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UploadFileSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -846,7 +834,7 @@ public UploadFileSendActionBuilder petId(Long petId) { public UploadFileSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UploadFileSendActionBuilder additionalMetadata(String additionalMetadata) { @@ -884,7 +872,7 @@ public SendMessageAction doBuild() { } public static class UploadFileReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -892,7 +880,7 @@ public static class UploadFileReceiveActionBuilder extends private static final String OPERATION_NAME = "uploadFile"; - public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 449c9b4189..34595093b2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -1,58 +1,45 @@ package org.citrusframework.openapi.generator.rest.petstore.request; -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static org.citrusframework.util.StringUtils.isEmpty; -import static org.citrusframework.util.StringUtils.isNotEmpty; - import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.net.URL; -import java.time.LocalDate; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; -import org.citrusframework.openapi.testapi.TestApiUtils; -import org.citrusframework.spi.Resource; -import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; +import java.net.URL; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; @SuppressWarnings("unused") @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class StoreApi implements GeneratedApi -{ +public class StoreApi implements GeneratedApi { + private final List customizers; + private final Endpoint endpoint; + private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; - @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - private final List customizers; - - private final Endpoint endpoint; - - private final OpenApiSpecification openApiSpecification; - - public StoreApi(Endpoint endpoint) { + public StoreApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public StoreApi(Endpoint endpoint, List customizers) { + public StoreApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -100,81 +87,81 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public DeleteOrderSendActionBuilder sendDeleteOrder(Long orderId) { - return new DeleteOrderSendActionBuilder(this, openApiSpecification, orderId); + public DeleteOrderSendActionBuilder sendDeleteOrder(Long orderId) { + return new DeleteOrderSendActionBuilder(this, openApiSpecification, orderId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public DeleteOrderSendActionBuilder sendDeleteOrder$(String orderIdExpression ) { - return new DeleteOrderSendActionBuilder(openApiSpecification, this, orderIdExpression); + public DeleteOrderSendActionBuilder sendDeleteOrder$(String orderIdExpression) { + return new DeleteOrderSendActionBuilder(openApiSpecification, this, orderIdExpression); } - public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull HttpStatus statusCode) { + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull HttpStatus statusCode) { return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull String statusCode) { - return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull String statusCode) { + return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetInventorySendActionBuilder sendGetInventory() { - GetInventorySendActionBuilder builder = new GetInventorySendActionBuilder(this, openApiSpecification); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetInventorySendActionBuilder sendGetInventory() { + GetInventorySendActionBuilder builder = new GetInventorySendActionBuilder(this, openApiSpecification); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } - public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull HttpStatus statusCode) { + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull HttpStatus statusCode) { return new GetInventoryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull String statusCode) { - return new GetInventoryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull String statusCode) { + return new GetInventoryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetOrderByIdSendActionBuilder sendGetOrderById(Long orderId) { - return new GetOrderByIdSendActionBuilder(this, openApiSpecification, orderId); + public GetOrderByIdSendActionBuilder sendGetOrderById(Long orderId) { + return new GetOrderByIdSendActionBuilder(this, openApiSpecification, orderId); } /** * Builder with required parameters as string to allow for dynamic content. */ - public GetOrderByIdSendActionBuilder sendGetOrderById$(String orderIdExpression ) { - return new GetOrderByIdSendActionBuilder(openApiSpecification, this, orderIdExpression); + public GetOrderByIdSendActionBuilder sendGetOrderById$(String orderIdExpression) { + return new GetOrderByIdSendActionBuilder(openApiSpecification, this, orderIdExpression); } - public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull HttpStatus statusCode) { + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull HttpStatus statusCode) { return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull String statusCode) { - return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull String statusCode) { + return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PlaceOrderSendActionBuilder sendPlaceOrder() { - return new PlaceOrderSendActionBuilder(this, openApiSpecification); + public PlaceOrderSendActionBuilder sendPlaceOrder() { + return new PlaceOrderSendActionBuilder(this, openApiSpecification); } - public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull HttpStatus statusCode) { + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull HttpStatus statusCode) { return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull String statusCode) { - return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull String statusCode) { + return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class DeleteOrderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -193,8 +180,8 @@ public DeleteOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification open /** * Constructor with required parameters as string to allow for dynamic content. */ - public DeleteOrderSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { - super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public DeleteOrderSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -213,7 +200,7 @@ public DeleteOrderSendActionBuilder orderId(Long orderId) { public DeleteOrderSendActionBuilder orderId(String orderIdExpression) { pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -228,7 +215,7 @@ public SendMessageAction doBuild() { } public static class DeleteOrderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -236,7 +223,7 @@ public static class DeleteOrderReceiveActionBuilder extends private static final String OPERATION_NAME = "deleteOrder"; - public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -257,7 +244,7 @@ public ReceiveMessageAction doBuild() { } public static class GetInventorySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -310,7 +297,7 @@ public SendMessageAction doBuild() { } public static class GetInventoryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -318,7 +305,7 @@ public static class GetInventoryReceiveActionBuilder extends private static final String OPERATION_NAME = "getInventory"; - public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -339,7 +326,7 @@ public ReceiveMessageAction doBuild() { } public static class GetOrderByIdSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -358,8 +345,8 @@ public GetOrderByIdSendActionBuilder(StoreApi storeApi, OpenApiSpecification ope /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetOrderByIdSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { - super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetOrderByIdSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -378,7 +365,7 @@ public GetOrderByIdSendActionBuilder orderId(Long orderId) { public GetOrderByIdSendActionBuilder orderId(String orderIdExpression) { pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -393,7 +380,7 @@ public SendMessageAction doBuild() { } public static class GetOrderByIdReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -401,7 +388,7 @@ public static class GetOrderByIdReceiveActionBuilder extends private static final String OPERATION_NAME = "getOrderById"; - public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -422,7 +409,7 @@ public ReceiveMessageAction doBuild() { } public static class PlaceOrderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -467,7 +454,7 @@ public SendMessageAction doBuild() { } public static class PlaceOrderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -475,7 +462,7 @@ public static class PlaceOrderReceiveActionBuilder extends private static final String OPERATION_NAME = "placeOrder"; - public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index 2814877653..75f7a48b04 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -1,58 +1,45 @@ package org.citrusframework.openapi.generator.rest.petstore.request; -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static org.citrusframework.util.StringUtils.isEmpty; -import static org.citrusframework.util.StringUtils.isNotEmpty; - import jakarta.validation.constraints.NotNull; -import java.math.BigDecimal; -import java.net.URL; -import java.time.LocalDate; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; -import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; -import org.citrusframework.openapi.testapi.TestApiUtils; -import org.citrusframework.spi.Resource; -import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; +import java.net.URL; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; @SuppressWarnings("unused") @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class UserApi implements GeneratedApi -{ +public class UserApi implements GeneratedApi { + private final List customizers; + private final Endpoint endpoint; + private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; - @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - private final List customizers; - - private final Endpoint endpoint; - - private final OpenApiSpecification openApiSpecification; - - public UserApi(Endpoint endpoint) { + public UserApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public UserApi(Endpoint endpoint, List customizers) { + public UserApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -100,110 +87,110 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public CreateUserSendActionBuilder sendCreateUser() { - return new CreateUserSendActionBuilder(this, openApiSpecification); + public CreateUserSendActionBuilder sendCreateUser() { + return new CreateUserSendActionBuilder(this, openApiSpecification); } - public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull HttpStatus statusCode) { + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull HttpStatus statusCode) { return new CreateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull String statusCode) { - return new CreateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull String statusCode) { + return new CreateUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public CreateUsersWithListInputSendActionBuilder sendCreateUsersWithListInput() { - return new CreateUsersWithListInputSendActionBuilder(this, openApiSpecification); + public CreateUsersWithListInputSendActionBuilder sendCreateUsersWithListInput() { + return new CreateUsersWithListInputSendActionBuilder(this, openApiSpecification); } - public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull HttpStatus statusCode) { + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull HttpStatus statusCode) { return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull String statusCode) { - return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, statusCode); + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull String statusCode) { + return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public DeleteUserSendActionBuilder sendDeleteUser(String username) { - return new DeleteUserSendActionBuilder(this, openApiSpecification, username); + public DeleteUserSendActionBuilder sendDeleteUser(String username) { + return new DeleteUserSendActionBuilder(this, openApiSpecification, username); } - public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull HttpStatus statusCode) { + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull HttpStatus statusCode) { return new DeleteUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull String statusCode) { - return new DeleteUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull String statusCode) { + return new DeleteUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetUserByNameSendActionBuilder sendGetUserByName(String username) { - return new GetUserByNameSendActionBuilder(this, openApiSpecification, username); + public GetUserByNameSendActionBuilder sendGetUserByName(String username) { + return new GetUserByNameSendActionBuilder(this, openApiSpecification, username); } - public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull HttpStatus statusCode) { + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull HttpStatus statusCode) { return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull String statusCode) { - return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull String statusCode) { + return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public LoginUserSendActionBuilder sendLoginUser() { - return new LoginUserSendActionBuilder(this, openApiSpecification); + public LoginUserSendActionBuilder sendLoginUser() { + return new LoginUserSendActionBuilder(this, openApiSpecification); } - public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull HttpStatus statusCode) { + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull HttpStatus statusCode) { return new LoginUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull String statusCode) { - return new LoginUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull String statusCode) { + return new LoginUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public LogoutUserSendActionBuilder sendLogoutUser() { - return new LogoutUserSendActionBuilder(this, openApiSpecification); + public LogoutUserSendActionBuilder sendLogoutUser() { + return new LogoutUserSendActionBuilder(this, openApiSpecification); } - public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull HttpStatus statusCode) { + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull HttpStatus statusCode) { return new LogoutUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull String statusCode) { - return new LogoutUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull String statusCode) { + return new LogoutUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdateUserSendActionBuilder sendUpdateUser(String username) { - return new UpdateUserSendActionBuilder(this, openApiSpecification, username); + public UpdateUserSendActionBuilder sendUpdateUser(String username) { + return new UpdateUserSendActionBuilder(this, openApiSpecification, username); } - public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull HttpStatus statusCode) { + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull HttpStatus statusCode) { return new UpdateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull String statusCode) { - return new UpdateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull String statusCode) { + return new UpdateUserReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class CreateUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -248,7 +235,7 @@ public SendMessageAction doBuild() { } public static class CreateUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -256,7 +243,7 @@ public static class CreateUserReceiveActionBuilder extends private static final String OPERATION_NAME = "createUser"; - public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -277,7 +264,7 @@ public ReceiveMessageAction doBuild() { } public static class CreateUsersWithListInputSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -296,18 +283,18 @@ public CreateUsersWithListInputSendActionBuilder(UserApi userApi, OpenApiSpecifi super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); } - public CreateUsersWithListInputSendActionBuilder user(User...user) { + public CreateUsersWithListInputSendActionBuilder user(User... user) { return this; } - public void setUser(User...user) { + public void setUser(User... user) { } - public CreateUsersWithListInputSendActionBuilder user(String...userExpression) { + public CreateUsersWithListInputSendActionBuilder user(String... userExpression) { return this; } - public void setUser(String...userExpression) { + public void setUser(String... userExpression) { } @Override @@ -322,7 +309,7 @@ public SendMessageAction doBuild() { } public static class CreateUsersWithListInputReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -330,7 +317,7 @@ public static class CreateUsersWithListInputReceiveActionBuilder extends private static final String OPERATION_NAME = "createUsersWithListInput"; - public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -351,7 +338,7 @@ public ReceiveMessageAction doBuild() { } public static class DeleteUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -392,7 +379,7 @@ public SendMessageAction doBuild() { } public static class DeleteUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -400,7 +387,7 @@ public static class DeleteUserReceiveActionBuilder extends private static final String OPERATION_NAME = "deleteUser"; - public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -421,7 +408,7 @@ public ReceiveMessageAction doBuild() { } public static class GetUserByNameSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -462,7 +449,7 @@ public SendMessageAction doBuild() { } public static class GetUserByNameReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -470,7 +457,7 @@ public static class GetUserByNameReceiveActionBuilder extends private static final String OPERATION_NAME = "getUserByName"; - public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -491,7 +478,7 @@ public ReceiveMessageAction doBuild() { } public static class LoginUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -540,7 +527,7 @@ public SendMessageAction doBuild() { } public static class LoginUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -548,7 +535,7 @@ public static class LoginUserReceiveActionBuilder extends private static final String OPERATION_NAME = "loginUser"; - public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -569,7 +556,7 @@ public ReceiveMessageAction doBuild() { } public static class LogoutUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -600,7 +587,7 @@ public SendMessageAction doBuild() { } public static class LogoutUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -608,7 +595,7 @@ public static class LogoutUserReceiveActionBuilder extends private static final String OPERATION_NAME = "logoutUser"; - public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -629,7 +616,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdateUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -684,7 +671,7 @@ public SendMessageAction doBuild() { } public static class UpdateUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -692,7 +679,7 @@ public static class UpdateUserReceiveActionBuilder extends private static final String OPERATION_NAME = "updateUser"; - public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index 7dcb02ad39..e319031c3d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -1,18 +1,19 @@ package org.citrusframework.openapi.generator.rest.petstore.spring; -import java.util.List; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; + +import java.util.List; @Configuration @@ -23,21 +24,21 @@ public class PetStoreBeanConfiguration { public OpenApiRepository petStoreOpenApiRepository() { var openApiRepository = new OpenApiRepository(); openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( - PetStore.petStoreApi())); + PetStore.petStoreApi())); return openApiRepository; } - @Bean(name="PetApi") + @Bean(name = "PetApi") public PetApi petApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new PetApi(endpoint, customizers); } - @Bean(name="StoreApi") + @Bean(name = "StoreApi") public StoreApi storeApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new StoreApi(endpoint, customizers); } - @Bean(name="UserApi") + @Bean(name = "UserApi") public UserApi userApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new UserApi(endpoint, customizers); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index db8d84d5bc..7f78d34841 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -1,160 +1,160 @@ package org.citrusframework.openapi.generator.rest.petstore.spring; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( - PetStore.petStoreApi()); + PetStore.petStoreApi()); @Override public void init() { - registerOperationParsers(PetApi.class,"add-pet", "addPet", "/pet", + registerOperationParsers(PetApi.class, "add-pet", "addPet", "/pet", PetApi.AddPetSendActionBuilder.class, PetApi.AddPetReceiveActionBuilder.class, - new String[]{ }, - new String[]{ }); + new String[]{}, + new String[]{}); - registerOperationParsers(PetApi.class,"delete-pet", "deletePet", "/pet/{petId}", + registerOperationParsers(PetApi.class, "delete-pet", "deletePet", "/pet/{petId}", PetApi.DeletePetSendActionBuilder.class, PetApi.DeletePetReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ "apiKey" }); + new String[]{"petId"}, + new String[]{"apiKey"}); - registerOperationParsers(PetApi.class,"find-pets-by-status", "findPetsByStatus", "/pet/findByStatus", + registerOperationParsers(PetApi.class, "find-pets-by-status", "findPetsByStatus", "/pet/findByStatus", PetApi.FindPetsByStatusSendActionBuilder.class, PetApi.FindPetsByStatusReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "status" }); + new String[]{}, + new String[]{"status"}); - registerOperationParsers(PetApi.class,"find-pets-by-tags", "findPetsByTags", "/pet/findByTags", + registerOperationParsers(PetApi.class, "find-pets-by-tags", "findPetsByTags", "/pet/findByTags", PetApi.FindPetsByTagsSendActionBuilder.class, PetApi.FindPetsByTagsReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "tags" }); + new String[]{}, + new String[]{"tags"}); - registerOperationParsers(PetApi.class,"get-pet-by-id", "getPetById", "/pet/{petId}", + registerOperationParsers(PetApi.class, "get-pet-by-id", "getPetById", "/pet/{petId}", PetApi.GetPetByIdSendActionBuilder.class, PetApi.GetPetByIdReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ "apiKey" }); + new String[]{"petId"}, + new String[]{"apiKey"}); - registerOperationParsers(PetApi.class,"update-pet", "updatePet", "/pet", + registerOperationParsers(PetApi.class, "update-pet", "updatePet", "/pet", PetApi.UpdatePetSendActionBuilder.class, PetApi.UpdatePetReceiveActionBuilder.class, - new String[]{ }, - new String[]{ }); + new String[]{}, + new String[]{}); - registerOperationParsers(PetApi.class,"update-pet-with-form", "updatePetWithForm", "/pet/{petId}", + registerOperationParsers(PetApi.class, "update-pet-with-form", "updatePetWithForm", "/pet/{petId}", PetApi.UpdatePetWithFormSendActionBuilder.class, PetApi.UpdatePetWithFormReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ "_name", "status" }); + new String[]{"petId"}, + new String[]{"_name", "status"}); - registerOperationParsers(PetApi.class,"upload-file", "uploadFile", "/pet/{petId}/uploadImage", + registerOperationParsers(PetApi.class, "upload-file", "uploadFile", "/pet/{petId}/uploadImage", PetApi.UploadFileSendActionBuilder.class, PetApi.UploadFileReceiveActionBuilder.class, - new String[]{ "petId" }, - new String[]{ "additionalMetadata", "ERROR_UNKNOWN" }); + new String[]{"petId"}, + new String[]{"additionalMetadata", "ERROR_UNKNOWN"}); - registerOperationParsers(StoreApi.class,"delete-order", "deleteOrder", "/store/order/{orderId}", + registerOperationParsers(StoreApi.class, "delete-order", "deleteOrder", "/store/order/{orderId}", StoreApi.DeleteOrderSendActionBuilder.class, StoreApi.DeleteOrderReceiveActionBuilder.class, - new String[]{ "orderId" }, - new String[]{ }); + new String[]{"orderId"}, + new String[]{}); - registerOperationParsers(StoreApi.class,"get-inventory", "getInventory", "/store/inventory", + registerOperationParsers(StoreApi.class, "get-inventory", "getInventory", "/store/inventory", StoreApi.GetInventorySendActionBuilder.class, StoreApi.GetInventoryReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "apiKey" }); + new String[]{}, + new String[]{"apiKey"}); - registerOperationParsers(StoreApi.class,"get-order-by-id", "getOrderById", "/store/order/{orderId}", + registerOperationParsers(StoreApi.class, "get-order-by-id", "getOrderById", "/store/order/{orderId}", StoreApi.GetOrderByIdSendActionBuilder.class, StoreApi.GetOrderByIdReceiveActionBuilder.class, - new String[]{ "orderId" }, - new String[]{ }); + new String[]{"orderId"}, + new String[]{}); - registerOperationParsers(StoreApi.class,"place-order", "placeOrder", "/store/order", + registerOperationParsers(StoreApi.class, "place-order", "placeOrder", "/store/order", StoreApi.PlaceOrderSendActionBuilder.class, StoreApi.PlaceOrderReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "ERROR_UNKNOWN" }); + new String[]{}, + new String[]{"ERROR_UNKNOWN"}); - registerOperationParsers(UserApi.class,"create-user", "createUser", "/user", + registerOperationParsers(UserApi.class, "create-user", "createUser", "/user", UserApi.CreateUserSendActionBuilder.class, UserApi.CreateUserReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "ERROR_UNKNOWN" }); + new String[]{}, + new String[]{"ERROR_UNKNOWN"}); - registerOperationParsers(UserApi.class,"create-users-with-list-input", "createUsersWithListInput", "/user/createWithList", + registerOperationParsers(UserApi.class, "create-users-with-list-input", "createUsersWithListInput", "/user/createWithList", UserApi.CreateUsersWithListInputSendActionBuilder.class, UserApi.CreateUsersWithListInputReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "user" }); + new String[]{}, + new String[]{"user"}); - registerOperationParsers(UserApi.class,"delete-user", "deleteUser", "/user/{username}", + registerOperationParsers(UserApi.class, "delete-user", "deleteUser", "/user/{username}", UserApi.DeleteUserSendActionBuilder.class, UserApi.DeleteUserReceiveActionBuilder.class, - new String[]{ "username" }, - new String[]{ }); + new String[]{"username"}, + new String[]{}); - registerOperationParsers(UserApi.class,"get-user-by-name", "getUserByName", "/user/{username}", + registerOperationParsers(UserApi.class, "get-user-by-name", "getUserByName", "/user/{username}", UserApi.GetUserByNameSendActionBuilder.class, UserApi.GetUserByNameReceiveActionBuilder.class, - new String[]{ "username" }, - new String[]{ }); + new String[]{"username"}, + new String[]{}); - registerOperationParsers(UserApi.class,"login-user", "loginUser", "/user/login", + registerOperationParsers(UserApi.class, "login-user", "loginUser", "/user/login", UserApi.LoginUserSendActionBuilder.class, UserApi.LoginUserReceiveActionBuilder.class, - new String[]{ }, - new String[]{ "username", "password" }); + new String[]{}, + new String[]{"username", "password"}); - registerOperationParsers(UserApi.class,"logout-user", "logoutUser", "/user/logout", + registerOperationParsers(UserApi.class, "logout-user", "logoutUser", "/user/logout", UserApi.LogoutUserSendActionBuilder.class, UserApi.LogoutUserReceiveActionBuilder.class, - new String[]{ }, - new String[]{ }); + new String[]{}, + new String[]{}); - registerOperationParsers(UserApi.class,"update-user", "updateUser", "/user/{username}", + registerOperationParsers(UserApi.class, "update-user", "updateUser", "/user/{username}", UserApi.UpdateUserSendActionBuilder.class, UserApi.UpdateUserReceiveActionBuilder.class, - new String[]{ "username" }, - new String[]{ "ERROR_UNKNOWN" }); + new String[]{"username"}, + new String[]{"ERROR_UNKNOWN"}); } private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, - Class sendBeanClass, - Class receiveBeanClass, - String[] constructorParameters, - String[] nonConstructorParameters) { + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, - path, - apiClass, - sendBeanClass, - receiveBeanClass, - "petstore.endpoint"); + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "petstore.endpoint"); sendParser.setConstructorParameters(constructorParameters); sendParser.setNonConstructorParameters(nonConstructorParameters); - registerBeanDefinitionParser("send-"+elementName, sendParser); + registerBeanDefinitionParser("send-" + elementName, sendParser); RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, - operationName, apiClass, receiveBeanClass, "petstore.endpoint"); - registerBeanDefinitionParser("receive-"+elementName, receiveParser); + operationName, apiClass, receiveBeanClass, "petstore.endpoint"); + registerBeanDefinitionParser("receive-" + elementName, receiveParser); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index 9fa4b1a025..c6992817a8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -1,33 +1,32 @@ package org.citrusframework.openapi.generator.soap.bookservice.request; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction; -import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction; + +import java.util.List; +import java.util.Map; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; @SuppressWarnings("unused") @jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.419751700+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class BookServiceSoapApi implements GeneratedApi -{ +public class BookServiceSoapApi implements GeneratedApi { private final Endpoint endpoint; private final List customizers; - public BookServiceSoapApi(Endpoint endpoint) { + public BookServiceSoapApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public BookServiceSoapApi(Endpoint endpoint, List customizers) { + public BookServiceSoapApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; } @@ -66,27 +65,27 @@ public List getCustomizers() { return customizers; } - public AddBookSendActionBuilder sendAddBook() { + public AddBookSendActionBuilder sendAddBook() { return new AddBookSendActionBuilder(this); } - public AddBookReceiveActionBuilder receiveAddBook() { + public AddBookReceiveActionBuilder receiveAddBook() { return new AddBookReceiveActionBuilder(this); } - public GetAllBooksSendActionBuilder sendGetAllBooks() { + public GetAllBooksSendActionBuilder sendGetAllBooks() { return new GetAllBooksSendActionBuilder(this); } - public GetAllBooksReceiveActionBuilder receiveGetAllBooks() { + public GetAllBooksReceiveActionBuilder receiveGetAllBooks() { return new GetAllBooksReceiveActionBuilder(this); } - public GetBookSendActionBuilder sendGetBook() { + public GetBookSendActionBuilder sendGetBook() { return new GetBookSendActionBuilder(this); } - public GetBookReceiveActionBuilder receiveGetBook() { + public GetBookReceiveActionBuilder receiveGetBook() { return new GetBookReceiveActionBuilder(this); } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index f672feb374..63d380f1ad 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -16,18 +16,19 @@ package org.citrusframework.maven.plugin; -import static java.lang.String.format; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.citrusframework.openapi.generator.CitrusJavaCodegen; import org.openapitools.codegen.plugin.CodeGenMojo; +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import static java.lang.String.format; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; + /** * Wrapper class that uses reflection to expose several properties of the {@link CodeGenMojo} for explicit assignment. */ @@ -42,7 +43,7 @@ public CodeGenMojoWrapper() throws MojoExecutionException { private void setFixedConfigOptions() throws MojoExecutionException { setPrivateField("generateSupportingFiles", true); - setPrivateField( "generatorName", CODEGEN_NAME); + setPrivateField("generatorName", CODEGEN_NAME); } public CodeGenMojoWrapper project(MavenProject mavenProject) throws MojoExecutionException { @@ -93,7 +94,7 @@ private void setPrivateField(String fieldName, Object fieldValue) throws MojoExe field.set(this, fieldValue); } catch (NoSuchFieldException | IllegalAccessException e) { throw new MojoExecutionException( - format("Could not reflectively set field value '%s' for field '%s'", fieldValue, fieldName)); + format("Could not reflectively set field value '%s' for field '%s'", fieldValue, fieldName)); } } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java index 1d1f475bee..76680e8909 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -16,8 +16,9 @@ package org.citrusframework.maven.plugin; -import static java.lang.String.format; -import static java.util.Collections.emptyList; +import org.apache.maven.plugin.MojoExecutionException; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; import java.io.BufferedReader; import java.io.File; @@ -27,9 +28,9 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; -import org.apache.maven.plugin.MojoExecutionException; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; + +import static java.lang.String.format; +import static java.util.Collections.emptyList; /** * Utility class responsible for generating the Spring meta files 'spring.handlers' and 'spring.schemas', used @@ -41,7 +42,6 @@ * files and tries to keep non generated information unchanged. Therefore, a special segment in the namespace uri is used, namely * {@link TestApiGeneratorMojo#CITRUS_TEST_SCHEMA}. *

      - * */ public class SpringMetaFileGenerator { @@ -51,12 +51,49 @@ public SpringMetaFileGenerator(TestApiGeneratorMojo testApiGeneratorMojo) { this.testApiGeneratorMojo = testApiGeneratorMojo; } + /** + * Reads the lines from the specified file and filters out lines indicating a generated test API, + * while maintaining all non-generated test API lines. This method is used to process files + * containing both generated and non-generated test APIs, allowing seamless integration and + * modification of both types of APIs in the same source files. + * + *

      + * Generated test API lines are identified by the presence of the {@code CITRUS_TEST_SCHEMA} + * string and excluded from the output of this method, while all other lines are preserved. + * This enables the algorithm to operate on files that are not purely generated, for example, + * when mixing generated with non-generated APIs in 'src/main/META-INF'. + *

      + * + * @param file the file to read and filter + * @return a list of filtered lines, excluding lines indicating a generated test API + * @throws CitrusRuntimeException if an error occurs while reading the file + */ + private static List readAndFilterLines(File file) { + if (!file.exists()) { + return emptyList(); + } + + List filteredLines = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.contains(TestApiGeneratorMojo.CITRUS_TEST_SCHEMA)) { + filteredLines.add(line); + } + } + } catch (IOException e) { + throw new CitrusRuntimeException(format("Unable to read file file: '%s'", file.getPath()), e); + } + + return filteredLines; + } + public void generateSpringIntegrationMetaFiles() throws MojoExecutionException { String springMetafileDirectory = format("%s/%s", testApiGeneratorMojo.getMavenProject().getBasedir(), testApiGeneratorMojo.metaInfFolder()); File metaFolder = new File(springMetafileDirectory); if (!metaFolder.exists() && !metaFolder.mkdirs()) { throw new CitrusRuntimeException( - format("Unable to create spring meta file directory: '%s'", springMetafileDirectory)); + format("Unable to create spring meta file directory: '%s'", springMetafileDirectory)); } try { @@ -71,9 +108,9 @@ private void writeSpringSchemaMetaFile(File springMetafileDirectory) throws Mojo String filename = "spring.schemas"; writeSpringMetaFile(springMetafileDirectory, filename, (fileWriter, apiConfig) -> { String targetXmlnsNamespace = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), - apiConfig.getVersion()); + apiConfig.getVersion()); String schemaFolderPath = TestApiGeneratorMojo.replaceDynamicVars(testApiGeneratorMojo.schemaFolder(apiConfig), apiConfig.getPrefix(), - apiConfig.getVersion()); + apiConfig.getVersion()); String schemaPath = String.format("%s/%s-api.xsd", schemaFolderPath, apiConfig.getPrefix().toLowerCase()); appendLine(fileWriter, format("%s.xsd=%s%n", targetXmlnsNamespace.replace("http://", "http\\://"), schemaPath), filename); }); @@ -83,11 +120,11 @@ private void writeSpringHandlerMetaFile(File springMetafileDirectory) throws Moj String filename = "spring.handlers"; writeSpringMetaFile(springMetafileDirectory, filename, (fileWriter, apiConfig) -> { String targetXmlnsNamespace = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), - apiConfig.getVersion()); + apiConfig.getVersion()); String invokerPackage = TestApiGeneratorMojo.replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion()); String namespaceHandlerClass = invokerPackage + ".citrus.extension." + apiConfig.getPrefix() + "NamespaceHandler"; appendLine(fileWriter, format("%s=%s%n", targetXmlnsNamespace.replace("http://", "http\\://"), namespaceHandlerClass), - filename); + filename); }); } @@ -108,43 +145,6 @@ private void writeSpringMetaFile(File springMetafileDirectory, String filename, } } - /** - * Reads the lines from the specified file and filters out lines indicating a generated test API, - * while maintaining all non-generated test API lines. This method is used to process files - * containing both generated and non-generated test APIs, allowing seamless integration and - * modification of both types of APIs in the same source files. - * - *

      - * Generated test API lines are identified by the presence of the {@code CITRUS_TEST_SCHEMA} - * string and excluded from the output of this method, while all other lines are preserved. - * This enables the algorithm to operate on files that are not purely generated, for example, - * when mixing generated with non-generated APIs in 'src/main/META-INF'. - *

      - * - * @param file the file to read and filter - * @return a list of filtered lines, excluding lines indicating a generated test API - * @throws CitrusRuntimeException if an error occurs while reading the file - */ - private static List readAndFilterLines(File file) { - if (!file.exists()) { - return emptyList(); - } - - List filteredLines = new ArrayList<>(); - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - while ((line = reader.readLine()) != null) { - if (!line.contains(TestApiGeneratorMojo.CITRUS_TEST_SCHEMA)) { - filteredLines.add(line); - } - } - } catch (IOException e) { - throw new CitrusRuntimeException(format("Unable to read file file: '%s'", file.getPath()), e); - } - - return filteredLines; - } - private void appendLine(FileWriter fileWriter, String format, String filename) { try { fileWriter.append(format); diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index 491ac48363..dc6931f01b 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -16,18 +16,7 @@ package org.citrusframework.maven.plugin; -import static java.lang.String.format; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_ENDPOINT; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_TYPE; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.PREFIX; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.TARGET_XMLNS_NAMESPACE; - import com.google.common.annotations.VisibleForTesting; -import java.io.File; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import lombok.Getter; import lombok.Setter; import org.apache.maven.plugin.AbstractMojo; @@ -43,6 +32,18 @@ import org.sonatype.plexus.build.incremental.BuildContext; import org.sonatype.plexus.build.incremental.DefaultBuildContext; +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_ENDPOINT; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_TYPE; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.PREFIX; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.TARGET_XMLNS_NAMESPACE; + /** * The Citrus OpenAPI Generator Maven Plugin is designed to facilitate the integration of multiple OpenAPI specifications * into the Citrus testing framework by automatically generating necessary test classes and XSDs. This plugin wraps the @@ -51,16 +52,15 @@ * Features: * - Multiple API Configurations: Easily configure multiple OpenAPI specifications to generate test APIs with specific prefixes. * - Citrus Integration: Generates classes and XSDs tailored for use within the Citrus framework, streamlining the process - * of creating robust integration tests. + * of creating robust integration tests. *

      - * */ @Mojo( - name = "create-test-api", - defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, - requiresDependencyCollection = ResolutionScope.TEST, - requiresDependencyResolution = ResolutionScope.TEST, - threadSafe = true + name = "create-test-api", + defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, + requiresDependencyCollection = ResolutionScope.TEST, + requiresDependencyResolution = ResolutionScope.TEST, + threadSafe = true ) public class TestApiGeneratorMojo extends AbstractMojo { @@ -85,59 +85,51 @@ public class TestApiGeneratorMojo extends AbstractMojo { * supporting Spring files such as 'spring.handlers' and 'spring.schemas'. */ public static final String DEFAULT_TARGET_NAMESPACE_TEMPLATE = - "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; + "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; /** * The default META-INF folder. Note that it points into the main resources, not generated resources, to allow for non generated * schemas/handlers. See also {@link TestApiGeneratorMojo}#DEFAULT_TARGET_NAMESPACE_TEMPLATE. */ public static final String DEFAULT_META_INF_FOLDER = "target/generated-test-resources/META-INF"; - - @Component - private final BuildContext buildContext = new DefaultBuildContext(); - - @Parameter(defaultValue = "${project}", readonly = true) - private MavenProject mavenProject; - - @Parameter(defaultValue = "${mojoExecution}", readonly = true) - private MojoExecution mojoExecution; - /** * sourceFolder: specifies the location to which the sources are generated. Defaults to 'generated-test-sources'. */ public static final String SOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.source.folder"; - @Parameter(property = SOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_SOURCE_FOLDER) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String sourceFolder = DEFAULT_SOURCE_FOLDER; - /** * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-test-resources'. */ public static final String RESOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.resource.folder"; - @Parameter(property = RESOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_RESOURCE_FOLDER) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String resourceFolder = DEFAULT_RESOURCE_FOLDER; - /** * schemaFolder: specifies the location for the generated xsd schemas. Defaults to 'schema/xsd/%VERSION%' */ public static final String API_SCHEMA_FOLDER = "citrus.test.api.generator.schema.folder"; - @Parameter(property = API_SCHEMA_FOLDER, defaultValue = DEFAULT_SCHEMA_FOLDER_TEMPLATE) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String schemaFolder = DEFAULT_SCHEMA_FOLDER_TEMPLATE; - /** * metaInfFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. */ public static final String META_INF_FOLDER = "citrus.test.api.generator.meta.inf.folder"; - @Parameter(property = META_INF_FOLDER, defaultValue = DEFAULT_META_INF_FOLDER) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String metaInfFolder = DEFAULT_META_INF_FOLDER; - /** * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. */ public static final String GENERATE_SPRING_INTEGRATION_FILES = "citrus.test.api.generator.generate.spring.integration.files"; + @Component + private final BuildContext buildContext = new DefaultBuildContext(); + @Parameter(defaultValue = "${project}", readonly = true) + private MavenProject mavenProject; + @Parameter(defaultValue = "${mojoExecution}", readonly = true) + private MojoExecution mojoExecution; + @Parameter(property = SOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_SOURCE_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String sourceFolder = DEFAULT_SOURCE_FOLDER; + @Parameter(property = RESOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_RESOURCE_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String resourceFolder = DEFAULT_RESOURCE_FOLDER; + @Parameter(property = API_SCHEMA_FOLDER, defaultValue = DEFAULT_SCHEMA_FOLDER_TEMPLATE) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String schemaFolder = DEFAULT_SCHEMA_FOLDER_TEMPLATE; + @Parameter(property = META_INF_FOLDER, defaultValue = DEFAULT_META_INF_FOLDER) + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private String metaInfFolder = DEFAULT_META_INF_FOLDER; @Parameter(property = GENERATE_SPRING_INTEGRATION_FILES, defaultValue = "true") @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected private boolean generateSpringIntegrationFiles = true; @@ -145,6 +137,28 @@ public class TestApiGeneratorMojo extends AbstractMojo { @Parameter private List apis; + /** + * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text. + */ + static String replaceDynamicVars(String text, String prefix, String version) { + if (text == null) { + return null; + } + + return text.replace("%PREFIX%", prefix) + .replace(".%VERSION%", version != null ? "." + version : "") + .replace("/%VERSION%", version != null ? "/" + version : "") + .replace("-%VERSION%", version != null ? "-" + version : "") + .replace("%VERSION%", version != null ? version : ""); + } + + /** + * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text, performing a toLowerCase on the prefix. + */ + static String replaceDynamicVarsToLowerCase(String text, String prefix, String version) { + return replaceDynamicVars(text, prefix.toLowerCase(), version); + } + protected MavenProject getMavenProject() { return mavenProject; } @@ -178,7 +192,7 @@ public void execute() throws MojoExecutionException { for (int index = 0; index < apis.size(); index++) { ApiConfig apiConfig = apis.get(index); validateApiConfig(index, apiConfig); - CodeGenMojo codeGenMojo = configureCodeGenMojo(apiConfig); + CodeGenMojo codeGenMojo = configureCodeGenMojo(apiConfig); codeGenMojo.execute(); } @@ -189,14 +203,14 @@ public void execute() throws MojoExecutionException { CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionException { CodeGenMojo codeGenMojo = new CodeGenMojoWrapper() - .resourceFolder(resourceFolder) - .sourceFolder(sourceFolder) - .schemaFolder(schemaFolder(apiConfig)) - .output(new File(mavenProject.getBuild().getDirectory())) - .mojoExecution(mojoExecution) - .project(mavenProject) - .inputSpec(apiConfig.getSource()) - .configOptions(apiConfig.toConfigOptionsProperties()); + .resourceFolder(resourceFolder) + .sourceFolder(sourceFolder) + .schemaFolder(schemaFolder(apiConfig)) + .output(new File(mavenProject.getBuild().getDirectory())) + .mojoExecution(mojoExecution) + .project(mavenProject) + .inputSpec(apiConfig.getSource()) + .configOptions(apiConfig.toConfigOptionsProperties()); codeGenMojo.setPluginContext(getPluginContext()); codeGenMojo.setBuildContext(buildContext); @@ -215,28 +229,6 @@ private void requireNonBlankParameter(String name, int index, String parameterVa } } - /** - * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text. - */ - static String replaceDynamicVars(String text, String prefix, String version) { - if (text == null) { - return null; - } - - return text.replace("%PREFIX%", prefix) - .replace(".%VERSION%", version != null ? "." + version : "") - .replace("/%VERSION%", version != null ? "/" + version : "") - .replace("-%VERSION%", version != null ? "-" + version : "") - .replace("%VERSION%", version != null ? version : ""); - } - - /** - * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text, performing a toLowerCase on the prefix. - */ - static String replaceDynamicVarsToLowerCase(String text, String prefix, String version) { - return replaceDynamicVars(text, prefix.toLowerCase(), version); - } - public enum ApiType { REST, SOAP } @@ -255,75 +247,66 @@ public static class ApiConfig { * prefix: specifies the prefixed used for the test api. Typically, an acronym for the application which is being tested. */ public static final String API_PREFIX_PROPERTY = "citrus.test.api.generator.prefix"; - @Parameter(required = true, property = API_PREFIX_PROPERTY) - private String prefix; - /** * source: specifies the source of the test api. */ public static final String API_SOURCE_PROPERTY = "citrus.test.api.generator.source"; - @Parameter(required = true, property = API_SOURCE_PROPERTY) - private String source; - /** * version: specifies the version of the api. May be null. */ public static final String API_VERSION_PROPERTY = "citrus.test.api.generator.version"; - @Parameter(property = API_VERSION_PROPERTY) - private String version; - /** * endpoint: specifies the endpoint of the test api. Defaults to 'prefixEndpoint'. */ public static final String API_ENDPOINT_PROPERTY = "citrus.test.api.generator.endpoint"; - @Parameter(property = API_ENDPOINT_PROPERTY, defaultValue = DEFAULT_ENDPOINT) - private String endpoint = DEFAULT_ENDPOINT; - /** * type: specifies the type of the test api. Defaults to 'REST' */ public static final String API_TYPE_PROPERTY = "citrus.test.api.generator.type"; - @Parameter(property = API_TYPE_PROPERTY, defaultValue = "REST") - private ApiType type = DEFAULT_API_TYPE; - /** * useTags: specifies whether tags should be used by the generator. Defaults to 'true'. If useTags is set to true, the generator * will organize the generated code based on the tags defined in your API specification. */ public static final String API_USE_TAGS_PROPERTY = "citrus.test.api.generator.use.tags"; - @Parameter(property = API_USE_TAGS_PROPERTY, defaultValue = "true") - private boolean useTags = true; - /** * invokerPackage: specifies the package for the test api classes. Defaults to * 'org.citrusframework.automation.%PREFIX%.%VERSION%'. */ public static final String API_INVOKER_PACKAGE_PROPERTY = "citrus.test.api.generator.invoker.package"; - @Parameter(property = API_INVOKER_PACKAGE_PROPERTY, defaultValue = DEFAULT_INVOKER_PACKAGE) - private String invokerPackage = DEFAULT_INVOKER_PACKAGE; - /** * apiPackage: specifies the package for the test api classes. Defaults to * 'org.citrusframework.automation.%PREFIX%.%VERSION%.api'. */ public static final String API_API_PACKAGE_PROPERTY = "citrus.test.api.generator.api.package"; - @Parameter(property = API_API_PACKAGE_PROPERTY, defaultValue = DEFAULT_API_PACKAGE) - private String apiPackage = DEFAULT_API_PACKAGE; - /** * modelPackage: specifies the package for the test api classes. Defaults to * 'org.citrusframework.automation.%PREFIX%.%VERSION%.model'. */ public static final String API_MODEL_PACKAGE_PROPERTY = "citrus.test.api.generator.model.package"; - @Parameter(property = API_MODEL_PACKAGE_PROPERTY, defaultValue = DEFAULT_MODEL_PACKAGE) - private String modelPackage = DEFAULT_MODEL_PACKAGE; - /** * targetXmlNamespace: specifies the xml namespace to be used by the api. Defaults to * 'http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api' */ @SuppressWarnings("JavadocLinkAsPlainText") public static final String API_NAMESPACE_PROPERTY = "citrus.test.api.generator.namespace"; + @Parameter(required = true, property = API_PREFIX_PROPERTY) + private String prefix; + @Parameter(required = true, property = API_SOURCE_PROPERTY) + private String source; + @Parameter(property = API_VERSION_PROPERTY) + private String version; + @Parameter(property = API_ENDPOINT_PROPERTY, defaultValue = DEFAULT_ENDPOINT) + private String endpoint = DEFAULT_ENDPOINT; + @Parameter(property = API_TYPE_PROPERTY, defaultValue = "REST") + private ApiType type = DEFAULT_API_TYPE; + @Parameter(property = API_USE_TAGS_PROPERTY, defaultValue = "true") + private boolean useTags = true; + @Parameter(property = API_INVOKER_PACKAGE_PROPERTY, defaultValue = DEFAULT_INVOKER_PACKAGE) + private String invokerPackage = DEFAULT_INVOKER_PACKAGE; + @Parameter(property = API_API_PACKAGE_PROPERTY, defaultValue = DEFAULT_API_PACKAGE) + private String apiPackage = DEFAULT_API_PACKAGE; + @Parameter(property = API_MODEL_PACKAGE_PROPERTY, defaultValue = DEFAULT_MODEL_PACKAGE) + private String modelPackage = DEFAULT_MODEL_PACKAGE; @Parameter(property = API_NAMESPACE_PROPERTY, defaultValue = DEFAULT_TARGET_NAMESPACE_TEMPLATE) private String targetXmlnsNamespace = DEFAULT_TARGET_NAMESPACE_TEMPLATE; @@ -337,13 +320,13 @@ Map toConfigOptionsProperties() { configOptionsProperties.put(API_ENDPOINT, qualifiedEndpoint()); configOptionsProperties.put(API_TYPE, type.toString()); configOptionsProperties.put(TARGET_XMLNS_NAMESPACE, - replaceDynamicVarsToLowerCase(targetXmlnsNamespace, prefix, version)); + replaceDynamicVarsToLowerCase(targetXmlnsNamespace, prefix, version)); configOptionsProperties.put("invokerPackage", - replaceDynamicVarsToLowerCase(invokerPackage, prefix, version)); + replaceDynamicVarsToLowerCase(invokerPackage, prefix, version)); configOptionsProperties.put("apiPackage", - replaceDynamicVarsToLowerCase(apiPackage, prefix, version)); + replaceDynamicVarsToLowerCase(apiPackage, prefix, version)); configOptionsProperties.put("modelPackage", - replaceDynamicVarsToLowerCase(modelPackage, prefix, version)); + replaceDynamicVarsToLowerCase(modelPackage, prefix, version)); configOptionsProperties.put("useTags", useTags); return configOptionsProperties; diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java index 3408d5f74d..94bfbaa065 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -1,27 +1,6 @@ package org.citrusframework.maven.plugin; -import static com.google.common.collect.Streams.concat; -import static java.lang.Boolean.TRUE; -import static java.util.Arrays.stream; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; -import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.springframework.test.util.ReflectionTestUtils.getField; - import jakarta.validation.constraints.NotNull; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; -import java.util.stream.Stream; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugin.testing.AbstractMojoTestCase; @@ -36,6 +15,28 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.stream.Stream; + +import static com.google.common.collect.Streams.concat; +import static java.lang.Boolean.TRUE; +import static java.util.Arrays.stream; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.springframework.test.util.ReflectionTestUtils.getField; + class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { public static final String OTHER_META_FILE_CONTENT = "somenamespace=somevalue"; @@ -46,15 +47,15 @@ class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { * Array containing path templates for each generated file, specified with tokens. Tokens can be replaced with values of the respective * testing scenario. */ - private static final String[] STANDARD_FILE_PATH_TEMPLATES = new String[]{ - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/%CAMEL_PREFIX%.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%NamespaceHandler.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%BeanConfiguration.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingReqType.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingRespType.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PingApi.java", - "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PungApi.java", - "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%SCHEMA_FOLDER%/%LOWER_PREFIX%-api.xsd" + private static final String[] STANDARD_FILE_PATH_TEMPLATES = new String[]{ + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/%CAMEL_PREFIX%.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%NamespaceHandler.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%INVOKER_FOLDER%/spring/%CAMEL_PREFIX%BeanConfiguration.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingReqType.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%MODEL_FOLDER%/PingRespType.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PingApi.java", + "%TARGET_FOLDER%/%GENERATED_SOURCES_FOLDER%/%REQUEST_FOLDER%/PungApi.java", + "%TARGET_FOLDER%/%GENERATED_RESOURCES_FOLDER%/%SCHEMA_FOLDER%/%LOWER_PREFIX%-api.xsd" }; /** @@ -62,37 +63,37 @@ class TestApiGeneratorMojoIntegrationTest extends AbstractMojoTestCase { * testing scenario. */ private static final String[] SPRING_META_FILE_TEMPLATES = new String[]{ - "%BASE_FOLDER%/%META_INF_FOLDER%/spring.handlers", - "%BASE_FOLDER%/%META_INF_FOLDER%/spring.schemas" + "%BASE_FOLDER%/%META_INF_FOLDER%/spring.handlers", + "%BASE_FOLDER%/%META_INF_FOLDER%/spring.schemas" }; private TestApiGeneratorMojo fixture; + static Stream executeMojoWithConfigurations() { + return Stream.of( + arguments("pom-missing-prefix", + new MojoExecutionException("Required parameter 'prefix' not set for api at index '0'!")), + arguments("pom-missing-source", + new MojoExecutionException("Required parameter 'source' not set for api at index '0'!")), + arguments("pom-minimal-config", null), + arguments("pom-minimal-with-version-config", null), + arguments("pom-multi-config", null), + arguments("pom-full-config", null), + arguments("pom-full-with-version-config", null), + arguments("pom-soap-config", null) + ); + } + @BeforeEach @SuppressWarnings("JUnitMixedFramework") void beforeEachSetup() throws Exception { setUp(); } - static Stream executeMojoWithConfigurations() { - return Stream.of( - arguments("pom-missing-prefix", - new MojoExecutionException("Required parameter 'prefix' not set for api at index '0'!")), - arguments("pom-missing-source", - new MojoExecutionException("Required parameter 'source' not set for api at index '0'!")), - arguments("pom-minimal-config", null), - arguments("pom-minimal-with-version-config", null), - arguments("pom-multi-config", null), - arguments("pom-full-config", null), - arguments("pom-full-with-version-config", null), - arguments("pom-soap-config", null) - ); - } - @ParameterizedTest @MethodSource void executeMojoWithConfigurations(String configName, Exception expectedException) - throws Exception { + throws Exception { try { fixture = fixtureFromPom(configName); @@ -120,7 +121,7 @@ void executeMojoWithConfigurations(String configName, Exception expectedExceptio } else { // When/Then assertThatThrownBy(() -> fixture.execute()).isInstanceOf(expectedException.getClass()) - .hasMessage(expectedException.getMessage()); + .hasMessage(expectedException.getMessage()); } } @@ -192,7 +193,7 @@ private void assertSchemasInSpringSchemas(ApiConfig apiConfig) throws IOExceptio String targetNamespace = replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()); targetNamespace = targetNamespace.replace(":", "\\:"); - String schemaPath = replaceDynamicVarsToLowerCase((String)getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion()); + String schemaPath = replaceDynamicVarsToLowerCase((String) getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion()); String text = String.format("%s.xsd=%s/%s-api.xsd", targetNamespace, schemaPath, apiConfig.getPrefix().toLowerCase()); @@ -204,13 +205,13 @@ private void assertSchemasInSpringSchemas(ApiConfig apiConfig) throws IOExceptio private void assertTargetNamespace(ApiConfig apiConfig) throws IOException { assertThat(getContentOfFile(apiConfig, "-api.xsd")).contains( - String.format("targetNamespace=\"%s\"", - replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()))); + String.format("targetNamespace=\"%s\"", + replaceDynamicVarsToLowerCase(apiConfig.getTargetXmlnsNamespace(), apiConfig.getPrefix(), apiConfig.getVersion()))); } private void assertEndpointName(ApiConfig apiConfig) throws IOException { assertThat(getContentOfFile(apiConfig, "BeanConfiguration")).contains( - String.format("@Qualifier(\"%s\")", apiConfig.qualifiedEndpoint())); + String.format("@Qualifier(\"%s\")", apiConfig.qualifiedEndpoint())); } private String getContentOfFile(ApiConfig apiConfig, String fileIdentifier) throws IOException { @@ -227,8 +228,8 @@ private String getContentOfFile(ApiConfig apiConfig, String fileIdentifier) thro private String getTemplateContaining(String text) { return concat(stream(STANDARD_FILE_PATH_TEMPLATES), stream(SPRING_META_FILE_TEMPLATES)) - .filter(path -> path.contains(text)).findFirst() - .orElseThrow(() -> new AssertionError(String.format("Can't find file template with content: '%s'", text))); + .filter(path -> path.contains(text)).findFirst() + .orElseThrow(() -> new AssertionError(String.format("Can't find file template with content: '%s'", text))); } @NotNull @@ -240,31 +241,31 @@ private String resolveFilePath(ApiConfig apiConfig, String filePathTemplate) { String camelCasePrefix = new String(prefixCharArray); String invokerFolder = toFolder( - replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVarsToLowerCase(apiConfig.getInvokerPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); String modelFolder = toFolder( - replaceDynamicVarsToLowerCase(apiConfig.getModelPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVarsToLowerCase(apiConfig.getModelPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); String requestFolder = toFolder( - replaceDynamicVarsToLowerCase(apiConfig.getApiPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVarsToLowerCase(apiConfig.getApiPackage(), apiConfig.getPrefix(), apiConfig.getVersion())); String schemaFolder = toFolder( - replaceDynamicVars((String)getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVars((String) getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); String generatedSourcesFolder = toFolder( - replaceDynamicVars((String)getField(fixture, "sourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVars((String) getField(fixture, "sourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); String generatedResourcesFolder = toFolder( - replaceDynamicVars((String)getField(fixture, "resourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); + replaceDynamicVars((String) getField(fixture, "resourceFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); return filePathTemplate - .replace("%BASE_FOLDER%", fixture.getMavenProject().getBasedir().getPath()) - .replace("%TARGET_FOLDER%", fixture.getMavenProject().getBuild().getDirectory()) - .replace("%SOURCE_FOLDER%", fixture.getMavenProject().getBuild().getSourceDirectory()) - .replace("%GENERATED_SOURCES_FOLDER%", generatedSourcesFolder) - .replace("%GENERATED_RESOURCES_FOLDER%", generatedResourcesFolder) - .replace("%INVOKER_FOLDER%", invokerFolder) - .replace("%MODEL_FOLDER%", modelFolder) - .replace("%REQUEST_FOLDER%", requestFolder) - .replace("%SCHEMA_FOLDER%", schemaFolder) - .replace("%LOWER_PREFIX%", lowerCasePrefix) - .replace("%CAMEL_PREFIX%", camelCasePrefix) - .replace("%META_INF_FOLDER%", toFolder((String) getField(fixture, "metaInfFolder"))); + .replace("%BASE_FOLDER%", fixture.getMavenProject().getBasedir().getPath()) + .replace("%TARGET_FOLDER%", fixture.getMavenProject().getBuild().getDirectory()) + .replace("%SOURCE_FOLDER%", fixture.getMavenProject().getBuild().getSourceDirectory()) + .replace("%GENERATED_SOURCES_FOLDER%", generatedSourcesFolder) + .replace("%GENERATED_RESOURCES_FOLDER%", generatedResourcesFolder) + .replace("%INVOKER_FOLDER%", invokerFolder) + .replace("%MODEL_FOLDER%", modelFolder) + .replace("%REQUEST_FOLDER%", requestFolder) + .replace("%SCHEMA_FOLDER%", schemaFolder) + .replace("%LOWER_PREFIX%", lowerCasePrefix) + .replace("%CAMEL_PREFIX%", camelCasePrefix) + .replace("%META_INF_FOLDER%", toFolder((String) getField(fixture, "metaInfFolder"))); } private String toFolder(String text) { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java index 8309b94dcb..c9c8bc042c 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -1,27 +1,6 @@ package org.citrusframework.maven.plugin; -import static java.lang.Boolean.TRUE; -import static org.assertj.core.api.Assertions.assertThat; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_PACKAGE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_TYPE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_INVOKER_PACKAGE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_META_INF_FOLDER; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_MODEL_PACKAGE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_RESOURCE_FOLDER; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SCHEMA_FOLDER_TEMPLATE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SOURCE_FOLDER; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_TARGET_NAMESPACE_TEMPLATE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; -import static org.junit.jupiter.params.provider.Arguments.arguments; -import static org.mockito.Mockito.doReturn; -import static org.springframework.test.util.ReflectionTestUtils.getField; - import jakarta.validation.constraints.NotNull; -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.stream.Stream; import org.apache.maven.model.Build; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -40,6 +19,28 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.openapitools.codegen.plugin.CodeGenMojo; +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +import static java.lang.Boolean.TRUE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_TYPE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_INVOKER_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_META_INF_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_MODEL_PACKAGE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_RESOURCE_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SCHEMA_FOLDER_TEMPLATE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SOURCE_FOLDER; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_TARGET_NAMESPACE_TEMPLATE; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; +import static org.junit.jupiter.params.provider.Arguments.arguments; +import static org.mockito.Mockito.doReturn; +import static org.springframework.test.util.ReflectionTestUtils.getField; + @ExtendWith(MockitoExtension.class) @SuppressWarnings({"JUnitMalformedDeclaration", "JUnitMixedFramework"}) @@ -56,93 +57,54 @@ class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase { @Mock private MojoExecution mojoExecutionMock; - @BeforeEach - void beforeEach() { - fixture = new TestApiGeneratorMojo(); - } - static Stream replaceDynamicVarsInPattern() { return Stream.of( - arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", "1", false, "MyPrefix-aa-1"), - arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", null, false, "MyPrefix-aa"), - arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", "1", false, "MyPrefix/aa/1"), - arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", null, false, "MyPrefix/aa"), - arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", "1", true, "myprefix.aa.1"), - arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", null, true, "myprefix.aa") + arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", "1", false, "MyPrefix-aa-1"), + arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", null, false, "MyPrefix-aa"), + arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", "1", false, "MyPrefix/aa/1"), + arguments("%PREFIX%/aa/%VERSION%", "MyPrefix", null, false, "MyPrefix/aa"), + arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", "1", true, "myprefix.aa.1"), + arguments("%PREFIX%.aa.%VERSION%", "MyPrefix", null, true, "myprefix.aa") ); } - @ParameterizedTest - @MethodSource - void replaceDynamicVarsInPattern(String pattern, String prefix, String version, boolean toLowerCasePrefix, String expectedResult) { - - if (toLowerCasePrefix) { - assertThat( - replaceDynamicVarsToLowerCase(pattern, prefix, version)).isEqualTo(expectedResult); - } else { - assertThat( - replaceDynamicVars(pattern, prefix, version)).isEqualTo(expectedResult); - } - } - static Stream configureMojo() { return Stream.of( - arguments("DefaultConfigWithoutVersion", createMinimalApiConfig(null), - createMinimalCodeGenMojoParams( - "schema/xsd", - "org.citrusframework.automation.mydefaultprefix", - "org.citrusframework.automation.mydefaultprefix.model", - "org.citrusframework.automation.mydefaultprefix.api", - "http://www.citrusframework.org/citrus-test-schema/mydefaultprefix-api" - )), - arguments("DefaultConfigWithVersion", createMinimalApiConfig("v1"), - createMinimalCodeGenMojoParams( - "schema/xsd/v1", - "org.citrusframework.automation.mydefaultprefix.v1", - "org.citrusframework.automation.mydefaultprefix.v1.model", - "org.citrusframework.automation.mydefaultprefix.v1.api", - "http://www.citrusframework.org/citrus-test-schema/v1/mydefaultprefix-api" - )), - arguments("CustomConfigWithoutVersion", createFullApiConfig(null), - createCustomCodeGenMojoParams( - "schema/xsd", - "my.mycustomprefix.invoker.package", - "my.mycustomprefix.model.package", - "my.mycustomprefix.api.package", - "myNamespace/citrus-test-schema/mycustomprefix" - )), - arguments("CustomConfigWithVersion", createFullApiConfig("v1"), - createCustomCodeGenMojoParams( - "schema/xsd/v1", - "my.mycustomprefix.v1.invoker.package", - "my.mycustomprefix.v1.model.package", - "my.mycustomprefix.v1.api.package", - "myNamespace/citrus-test-schema/mycustomprefix/v1" - )) + arguments("DefaultConfigWithoutVersion", createMinimalApiConfig(null), + createMinimalCodeGenMojoParams( + "schema/xsd", + "org.citrusframework.automation.mydefaultprefix", + "org.citrusframework.automation.mydefaultprefix.model", + "org.citrusframework.automation.mydefaultprefix.api", + "http://www.citrusframework.org/citrus-test-schema/mydefaultprefix-api" + )), + arguments("DefaultConfigWithVersion", createMinimalApiConfig("v1"), + createMinimalCodeGenMojoParams( + "schema/xsd/v1", + "org.citrusframework.automation.mydefaultprefix.v1", + "org.citrusframework.automation.mydefaultprefix.v1.model", + "org.citrusframework.automation.mydefaultprefix.v1.api", + "http://www.citrusframework.org/citrus-test-schema/v1/mydefaultprefix-api" + )), + arguments("CustomConfigWithoutVersion", createFullApiConfig(null), + createCustomCodeGenMojoParams( + "schema/xsd", + "my.mycustomprefix.invoker.package", + "my.mycustomprefix.model.package", + "my.mycustomprefix.api.package", + "myNamespace/citrus-test-schema/mycustomprefix" + )), + arguments("CustomConfigWithVersion", createFullApiConfig("v1"), + createCustomCodeGenMojoParams( + "schema/xsd/v1", + "my.mycustomprefix.v1.invoker.package", + "my.mycustomprefix.v1.model.package", + "my.mycustomprefix.v1.api.package", + "myNamespace/citrus-test-schema/mycustomprefix/v1" + )) ); } - @ParameterizedTest(name = "{0}") - @MethodSource - void configureMojo(String name, ApiConfig apiConfig, CodeGenMojoParams controlParams) throws MojoExecutionException { - doReturn("target").when(buildMock).getDirectory(); - doReturn(buildMock).when(mavenProjectMock).getBuild(); - fixture.setMavenProject(mavenProjectMock); - fixture.setMojoExecution(mojoExecutionMock); - - CodeGenMojo codeGenMojo = fixture.configureCodeGenMojo(apiConfig); - assertThat(getField(codeGenMojo, "project")).isEqualTo(mavenProjectMock); - assertThat(getField(codeGenMojo, "mojo")).isEqualTo(mojoExecutionMock); - assertThat(((File) getField(codeGenMojo, "output"))).hasName(controlParams.output); - assertThat(getField(codeGenMojo, "inputSpec")).isEqualTo(controlParams.source); - assertThat(getField(codeGenMojo, "generateSupportingFiles")).isEqualTo(TRUE); - assertThat(getField(codeGenMojo, "generatorName")).isEqualTo("java-citrus"); - - //noinspection unchecked - assertThat((Map)getField(codeGenMojo, "configOptions")) - .containsExactlyInAnyOrderEntriesOf(controlParams.configOptions); - } - /** * Create an {@link ApiConfig} with the minimal configuration, that is required. All other values will be chosen as defaults. */ @@ -192,7 +154,7 @@ private static CodeGenMojoParams createMinimalCodeGenMojoParams(String schemaFol configOptionsControlMap.put("apiType", "REST"); configOptionsControlMap.put("useTags", true); - return new CodeGenMojoParams("target", "myDefaultSource", configOptionsControlMap); + return new CodeGenMojoParams("target", "myDefaultSource", configOptionsControlMap); } @NotNull @@ -211,7 +173,50 @@ private static CodeGenMojoParams createCustomCodeGenMojoParams(String schemaFold configOptionsControlMap.put("apiType", "SOAP"); configOptionsControlMap.put("useTags", false); - return new CodeGenMojoParams("target", "myCustomSource", configOptionsControlMap); + return new CodeGenMojoParams("target", "myCustomSource", configOptionsControlMap); + } + + @BeforeEach + void beforeEach() { + fixture = new TestApiGeneratorMojo(); + } + + @ParameterizedTest + @MethodSource + void replaceDynamicVarsInPattern(String pattern, String prefix, String version, boolean toLowerCasePrefix, String expectedResult) { + + if (toLowerCasePrefix) { + assertThat( + replaceDynamicVarsToLowerCase(pattern, prefix, version)).isEqualTo(expectedResult); + } else { + assertThat( + replaceDynamicVars(pattern, prefix, version)).isEqualTo(expectedResult); + } + } + + @ParameterizedTest(name = "{0}") + @MethodSource + void configureMojo(String name, ApiConfig apiConfig, CodeGenMojoParams controlParams) throws MojoExecutionException { + doReturn("target").when(buildMock).getDirectory(); + doReturn(buildMock).when(mavenProjectMock).getBuild(); + fixture.setMavenProject(mavenProjectMock); + fixture.setMojoExecution(mojoExecutionMock); + + CodeGenMojo codeGenMojo = fixture.configureCodeGenMojo(apiConfig); + assertThat(getField(codeGenMojo, "project")).isEqualTo(mavenProjectMock); + assertThat(getField(codeGenMojo, "mojo")).isEqualTo(mojoExecutionMock); + assertThat(((File) getField(codeGenMojo, "output"))).hasName(controlParams.output); + assertThat(getField(codeGenMojo, "inputSpec")).isEqualTo(controlParams.source); + assertThat(getField(codeGenMojo, "generateSupportingFiles")).isEqualTo(TRUE); + assertThat(getField(codeGenMojo, "generatorName")).isEqualTo("java-citrus"); + + //noinspection unchecked + assertThat((Map) getField(codeGenMojo, "configOptions")) + .containsExactlyInAnyOrderEntriesOf(controlParams.configOptions); + } + + private record CodeGenMojoParams(String output, String source, Map configOptions) { + } @Nested @@ -257,7 +262,7 @@ void apiTypeDefault() { @Test void schemaFolderDefault() { - assertThat((String)getField(fixture, "schemaFolder")).isEqualTo(DEFAULT_SCHEMA_FOLDER_TEMPLATE); + assertThat((String) getField(fixture, "schemaFolder")).isEqualTo(DEFAULT_SCHEMA_FOLDER_TEMPLATE); } @Test @@ -275,8 +280,4 @@ void metaInfFolderDefault() { assertThat((String) getField(fixture, "metaInfFolder")).isEqualTo(DEFAULT_META_INF_FOLDER); } } - - private record CodeGenMojoParams(String output, String source, Map configOptions) { - - } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java index 94345c88ad..4ad183393b 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/stubs/CitrusOpenApiGeneratorMavenProjectStub.java @@ -1,14 +1,15 @@ package org.citrusframework.maven.plugin.stubs; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; import org.apache.maven.model.Build; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.plugin.testing.stubs.MavenProjectStub; import org.codehaus.plexus.PlexusTestCase; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + public class CitrusOpenApiGeneratorMavenProjectStub extends MavenProjectStub { private final String config; diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java index 6c8bed9e16..37277ee4a2 100644 --- a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java @@ -16,7 +16,6 @@ package org.citrusframework.openapi.testapi.spring; -import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.config.xml.AbstractReceiveMessageActionFactoryBean; @@ -28,9 +27,9 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder.OpenApiClientResponseMessageBuilder; import org.citrusframework.openapi.actions.OpenApiSpecificationSource; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.validation.context.ValidationContext; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.RuntimeBeanReference; @@ -38,6 +37,8 @@ import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; +import java.util.List; + /** * Parses XML configuration for receiving API responses based on OpenAPI specifications. Extends * {@link HttpReceiveResponseActionParser} to handle OpenAPI-specific response builders and @@ -68,10 +69,10 @@ public class RestApiReceiveMessageActionParser extends HttpReceiveResponseAction private final String defaultApiEndpointName; public RestApiReceiveMessageActionParser(OpenApiSpecification openApiSpecification, - String operationId, - Class apiBeanClass, - Class beanClass, - String defaultApiEndpointName) { + String operationId, + Class apiBeanClass, + Class beanClass, + String defaultApiEndpointName) { this.openApiSpecification = openApiSpecification; this.operationId = operationId; this.apiBeanClass = apiBeanClass; @@ -81,21 +82,21 @@ public RestApiReceiveMessageActionParser(OpenApiSpecification openApiSpecificati @Override protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, - ParserContext parserContext) { + ParserContext parserContext) { BeanDefinitionBuilder beanDefinitionBuilder = super.createBeanDefinitionBuilder(element, - parserContext); + parserContext); // Remove the messageBuilder property and inject it directly into the action builder. BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); OpenApiClientResponseMessageBuilder messageBuilder = (OpenApiClientResponseMessageBuilder) beanDefinition.getPropertyValues() - .get("messageBuilder"); + .get("messageBuilder"); messageBuilder.statusCode(element.getAttribute("statusCode")); beanDefinition.getPropertyValues().removePropertyValue("messageBuilder"); BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - beanClass); + beanClass); actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); actionBuilder.addConstructorArgValue(openApiSpecification); actionBuilder.addConstructorArgValue(messageBuilder); @@ -116,7 +117,7 @@ private void setDefaultEndpoint(BeanDefinitionBuilder beanDefinitionBuilder) { } @Override - protected Class> getMessageFactoryClass() { + protected Class> getMessageFactoryClass() { return TestApiOpenApiClientReceiveActionBuilderFactoryBean.class; } @@ -128,16 +129,16 @@ protected void validateEndpointConfiguration(Element element) { @Override protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { return new OpenApiClientResponseMessageBuilder(httpMessage, - new OpenApiSpecificationSource(openApiSpecification), operationId, null); + new OpenApiSpecificationSource(openApiSpecification), operationId, null); } @Override protected List parseValidationContexts(Element messageElement, - BeanDefinitionBuilder builder) { + BeanDefinitionBuilder builder) { List validationContexts = super.parseValidationContexts(messageElement, - builder); + builder); OpenApiMessageValidationContext openApiMessageValidationContext = getOpenApiMessageValidationContext( - messageElement); + messageElement); validationContexts.add(openApiMessageValidationContext); return validationContexts; } @@ -146,9 +147,9 @@ protected List parseValidationContexts(Element messageElement * Constructs the OpenAPI message validation context based on the XML element. */ private OpenApiMessageValidationContext getOpenApiMessageValidationContext( - Element messageElement) { + Element messageElement) { OpenApiMessageValidationContext.Builder context = OpenApiMessageValidationContext.Builder.openApi( - openApiSpecification); + openApiSpecification); if (messageElement != null) { addSchemaInformationToValidationContext(messageElement, context); @@ -162,16 +163,12 @@ private OpenApiMessageValidationContext getOpenApiMessageValidationContext( * {@link RestApiReceiveMessageActionBuilder}. */ public static class TestApiOpenApiClientReceiveActionBuilderFactoryBean extends - AbstractReceiveMessageActionFactoryBean { + AbstractReceiveMessageActionFactoryBean { private RestApiReceiveMessageActionBuilder builder; public TestApiOpenApiClientReceiveActionBuilderFactoryBean( - RestApiReceiveMessageActionBuilder builder) { - this.builder = builder; - } - - public void setBuilder(RestApiReceiveMessageActionBuilder builder) { + RestApiReceiveMessageActionBuilder builder) { this.builder = builder; } @@ -189,6 +186,10 @@ public Class getObjectType() { public HttpClientResponseActionBuilder getBuilder() { return builder; } + + public void setBuilder(RestApiReceiveMessageActionBuilder builder) { + this.builder = builder; + } } } diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java index b244ef47cf..dd25d793a0 100644 --- a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java @@ -16,11 +16,6 @@ package org.citrusframework.openapi.testapi.spring; -import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; - -import java.util.List; -import java.util.stream.Collectors; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.config.xml.AbstractSendMessageActionFactoryBean; import org.citrusframework.config.xml.AbstractTestContainerFactoryBean; @@ -50,6 +45,12 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +import java.util.List; +import java.util.stream.Collectors; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; + /** * Parses the XML configuration for sending API requests based on OpenAPI specifications. Extends * {@link HttpSendRequestActionParser} to handle OpenAPI specific request and response builders. @@ -86,27 +87,24 @@ public class RestApiSendMessageActionParser extends HttpSendRequestActionParser * The OpenAPI operation path. */ private final String path; - + private final String defaultEndpointName; /** * Constructor parameters for the requestBeanClass. */ private List constructorParameters = emptyList(); - /** * Optional non constructor parameters for the requestBeanClass. */ private List nonConstructorParameters = emptyList(); - private final String defaultEndpointName; - public RestApiSendMessageActionParser( - OpenApiSpecification openApiSpecification, - String operationId, - String path, - Class apiBeanClass, - Class sendBeanClass, - Class receiveBeanClass, - String defaultEndpointName) { + OpenApiSpecification openApiSpecification, + String operationId, + String path, + Class apiBeanClass, + Class sendBeanClass, + Class receiveBeanClass, + String defaultEndpointName) { this.openApiSpecification = openApiSpecification; this.operationId = operationId; this.path = path; @@ -116,15 +114,23 @@ public RestApiSendMessageActionParser( this.defaultEndpointName = defaultEndpointName; } + private static List collectChildNodeContents(Element element, String parameterName) { + return DomUtils.getChildElementsByTagName(element, parameterName) + .stream() + .map(Node::getTextContent) + .filter(StringUtils::isNotEmpty) + .collect(Collectors.toList()); // For further processing, list must not be immutable + } + @Override protected BeanDefinitionBuilder createBeanDefinitionBuilder(final Element element, - ParserContext parserContext) { + ParserContext parserContext) { BeanDefinitionBuilder beanDefinitionBuilder = super.createBeanDefinitionBuilder(element, - parserContext); + parserContext); BeanDefinitionBuilder actionBuilder = createTestApiActionBuilder( - element, beanDefinitionBuilder); + element, beanDefinitionBuilder); beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); setDefaultEndpoint(beanDefinitionBuilder); @@ -133,16 +139,16 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(final Element elemen if (receive != null) { boolean fork = Boolean.parseBoolean(element.getAttribute("fork")); return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, - beanDefinitionBuilder); + beanDefinitionBuilder); } return beanDefinitionBuilder; } private BeanDefinitionBuilder createTestApiActionBuilder(Element element, - BeanDefinitionBuilder beanDefinitionBuilder) { + BeanDefinitionBuilder beanDefinitionBuilder) { BeanDefinitionBuilder actionBuilder = propagateMessageBuilderToActionBuilder( - beanDefinitionBuilder); + beanDefinitionBuilder); readConstructorParameters(element, actionBuilder); readNonConstructorParameters(element, actionBuilder); return actionBuilder; @@ -155,18 +161,18 @@ private BeanDefinitionBuilder createTestApiActionBuilder(Element element, * or asynchronously, depending on the {@code fork} parameter. */ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, Element receive, - ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { Class> containerClass = - fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; + fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; BeanDefinitionBuilder sequenceBuilder = BeanDefinitionBuilder.genericBeanDefinition( - containerClass); + containerClass); RestApiReceiveMessageActionParser receiveApiResponseActionParser = new RestApiReceiveMessageActionParser( - openApiSpecification, operationId, apiBeanClass, receiveBeanClass, defaultEndpointName); + openApiSpecification, operationId, apiBeanClass, receiveBeanClass, defaultEndpointName); BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse( - receive, parserContext); + receive, parserContext); ManagedList actions = new ManagedList<>(); actions.add(beanDefinitionBuilder.getBeanDefinition()); @@ -182,15 +188,15 @@ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, E * action builder. */ private BeanDefinitionBuilder propagateMessageBuilderToActionBuilder( - BeanDefinitionBuilder beanDefinitionBuilder) { + BeanDefinitionBuilder beanDefinitionBuilder) { BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition(); OpenApiClientRequestMessageBuilder messageBuilder = (OpenApiClientRequestMessageBuilder) beanDefinition.getPropertyValues() - .get("messageBuilder"); + .get("messageBuilder"); beanDefinition.getPropertyValues().removePropertyValue("messageBuilder"); BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - requestBeanClass); + requestBeanClass); actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); actionBuilder.addConstructorArgValue(openApiSpecification); @@ -220,7 +226,7 @@ private void readConstructorParameters(Element element, BeanDefinitionBuilder ac * provided {@link BeanDefinitionBuilder}. */ private void readNonConstructorParameters(Element element, - BeanDefinitionBuilder actionBuilder) { + BeanDefinitionBuilder actionBuilder) { for (String parameterName : nonConstructorParameters) { @@ -239,27 +245,19 @@ private void readNonConstructorParameters(Element element, Attr attribute = element.getAttributeNode(attributeName); if (attribute != null) { actionBuilder.addPropertyValue( - TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), - attribute.getValue()); + TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), + attribute.getValue()); } else { List values = collectChildNodeContents(element, attributeName); if (values != null && !values.isEmpty()) { actionBuilder.addPropertyValue( - TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), - values); + TestApiUtils.mapXmlAttributeNameToJavaPropertyName(parameterName), + values); } } } } - private static List collectChildNodeContents(Element element, String parameterName) { - return DomUtils.getChildElementsByTagName(element, parameterName) - .stream() - .map(Node::getTextContent) - .filter(StringUtils::isNotEmpty) - .collect(Collectors.toList()); // For further processing, list must not be immutable - } - /** * Sets the default endpoint for TestApi actions, if not already specified. */ @@ -298,19 +296,19 @@ protected Element getRequestElement(Element element) { protected HttpMessageBuilder createMessageBuilder(HttpMessage httpMessage) { httpMessage.path(path); return new TestApiClientRequestMessageBuilder(httpMessage, - new OpenApiSpecificationSource(openApiSpecification), operationId); + new OpenApiSpecificationSource(openApiSpecification), operationId); } public void setConstructorParameters(String... constructorParameters) { this.constructorParameters = - constructorParameters != null ? asList(constructorParameters) - : emptyList(); + constructorParameters != null ? asList(constructorParameters) + : emptyList(); } public void setNonConstructorParameters(String... nonConstructorParameters) { this.nonConstructorParameters = - nonConstructorParameters != null ? asList(nonConstructorParameters) - : emptyList(); + nonConstructorParameters != null ? asList(nonConstructorParameters) + : emptyList(); } /** @@ -318,16 +316,12 @@ public void setNonConstructorParameters(String... nonConstructorParameters) { * {@link RestApiSendMessageActionBuilder}. */ public static class TestApiOpenApiClientSendActionBuilderFactoryBean extends - AbstractSendMessageActionFactoryBean { + AbstractSendMessageActionFactoryBean { private RestApiSendMessageActionBuilder builder; public TestApiOpenApiClientSendActionBuilderFactoryBean( - RestApiSendMessageActionBuilder builder) { - this.builder = builder; - } - - public void setBuilder(RestApiSendMessageActionBuilder builder) { + RestApiSendMessageActionBuilder builder) { this.builder = builder; } @@ -345,6 +339,10 @@ public Class getObjectType() { public HttpClientRequestActionBuilder getBuilder() { return builder; } + + public void setBuilder(RestApiSendMessageActionBuilder builder) { + this.builder = builder; + } } } diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java index 89d6617060..2c7d54afad 100644 --- a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiReceiveMessageActionParser.java @@ -40,9 +40,9 @@ public class SoapApiReceiveMessageActionParser extends ReceiveSoapMessageActionP private final String defaultEndpointName; public SoapApiReceiveMessageActionParser( - Class apiBeanClass, - Class beanClass, - String defaultEndpointName) { + Class apiBeanClass, + Class beanClass, + String defaultEndpointName) { this.apiBeanClass = apiBeanClass; this.receiveBeanClass = beanClass; this.defaultEndpointName = defaultEndpointName; @@ -70,7 +70,7 @@ protected String parseEndpoint(Element element) { private BeanDefinitionBuilder createTestApiActionBuilder() { BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - receiveBeanClass); + receiveBeanClass); actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); return actionBuilder; @@ -85,10 +85,10 @@ protected Class getMessageFact * Test action factory bean. */ public static class TestApiSoapClientReceiveActionBuilderFactoryBean extends - ReceiveSoapMessageActionFactoryBean { + ReceiveSoapMessageActionFactoryBean { public TestApiSoapClientReceiveActionBuilderFactoryBean( - SoapApiReceiveMessageActionBuilder builder) { + SoapApiReceiveMessageActionBuilder builder) { super(builder); } } diff --git a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java index c498623a00..4c5e1a89f5 100644 --- a/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java +++ b/test-api-generator/citrus-test-api-spring/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java @@ -53,10 +53,10 @@ public class SoapApiSendMessageActionParser extends SendSoapMessageActionParser private final String defaultEndpointName; public SoapApiSendMessageActionParser( - Class apiBeanClass, - Class sendBeanClass, - Class receiveBeanClass, - String defaultEndpointName) { + Class apiBeanClass, + Class sendBeanClass, + Class receiveBeanClass, + String defaultEndpointName) { this.apiBeanClass = apiBeanClass; this.sendBeanClass = sendBeanClass; this.receiveBeanClass = receiveBeanClass; @@ -74,7 +74,7 @@ public BeanDefinitionBuilder parseComponent(Element element, ParserContext parse if (receive != null) { boolean fork = Boolean.parseBoolean(element.getAttribute("fork")); return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, - beanDefinitionBuilder); + beanDefinitionBuilder); } return beanDefinitionBuilder; @@ -92,7 +92,7 @@ protected String parseEndpoint(Element element) { private BeanDefinitionBuilder createTestApiActionBuilder() { BeanDefinitionBuilder actionBuilder = BeanDefinitionBuilder.genericBeanDefinition( - sendBeanClass); + sendBeanClass); actionBuilder.addConstructorArgValue(new RuntimeBeanReference(apiBeanClass)); return actionBuilder; @@ -111,18 +111,18 @@ protected Class getMessageFactory * or asynchronously, depending on the {@code fork} parameter. */ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, Element receive, - ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { + ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) { Class> containerClass = - fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; + fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; BeanDefinitionBuilder sequenceBuilder = BeanDefinitionBuilder.genericBeanDefinition( - containerClass); + containerClass); SoapApiReceiveMessageActionParser receiveApiResponseActionParser = new SoapApiReceiveMessageActionParser( - apiBeanClass, receiveBeanClass, defaultEndpointName); + apiBeanClass, receiveBeanClass, defaultEndpointName); BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse( - receive, parserContext); + receive, parserContext); ManagedList actions = new ManagedList<>(); actions.add(beanDefinitionBuilder.getBeanDefinition()); @@ -137,10 +137,10 @@ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, E * Test action factory bean. */ public static class TestApiSoapClientSendActionBuilderFactoryBean extends - SendSoapMessageActionFactoryBean { + SendSoapMessageActionFactoryBean { public TestApiSoapClientSendActionBuilderFactoryBean( - SoapApiSendMessageActionBuilder builder) { + SoapApiSendMessageActionBuilder builder) { super(builder); } } From 827aa46ff1164a7782f506c9c4c0bf860736db50 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Wed, 23 Oct 2024 20:47:10 +0200 Subject: [PATCH 20/47] chore(citrus-api): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-api` module. --- .../citrusframework/TestActionBuilder.java | 12 +++--- .../CitrusEndpointAnnotations.java | 8 ++-- .../citrusframework/common/TestLoader.java | 12 +++--- .../annotation/AnnotationConfigParser.java | 16 ++++---- .../citrusframework/context/TestContext.java | 26 ++++++------- .../context/resolver/TypeAliasResolver.java | 12 +++--- .../endpoint/DefaultEndpointFactory.java | 16 ++++---- .../endpoint/EndpointBuilder.java | 18 ++++----- .../endpoint/EndpointComponent.java | 10 ++--- .../endpoint/EndpointFactory.java | 6 +-- .../citrusframework/functions/Function.java | 10 ++--- .../functions/FunctionRegistry.java | 8 ++-- .../functions/FunctionUtils.java | 2 +- .../org/citrusframework/main/TestEngine.java | 2 +- .../message/AbstractMessageProcessor.java | 2 +- .../message/ErrorHandlingStrategy.java | 2 +- .../message/MessageHeaderType.java | 6 +-- .../message/MessageHeaderUtils.java | 2 +- .../message/MessagePayloadUtils.java | 2 +- .../message/MessageProcessor.java | 6 +-- .../message/MessageSelector.java | 8 ++-- .../message/ScriptPayloadBuilder.java | 6 +-- .../citrusframework/spi/BindToRegistry.java | 2 +- .../util/ReflectionHelper.java | 8 ++-- .../citrusframework/util/TypeConverter.java | 20 +++++----- .../validation/HeaderValidator.java | 12 +++--- .../validation/MessageValidator.java | 12 +++--- .../validation/MessageValidatorRegistry.java | 38 +++++++++---------- .../validation/SchemaValidator.java | 6 +-- .../validation/ValueMatcher.java | 14 +++---- .../DefaultControlExpressionParser.java | 6 +-- .../validation/matcher/ValidationMatcher.java | 10 ++--- .../SegmentVariableExtractorRegistry.java | 20 +++++----- .../variable/VariableExtractor.java | 6 +-- .../variable/VariableUtils.java | 18 ++++----- .../variable/dictionary/DataDictionary.java | 4 +- .../namespace/NamespaceContextBuilder.java | 12 +++--- .../message/MessagePayloadUtilsTest.java | 5 +-- 38 files changed, 188 insertions(+), 197 deletions(-) diff --git a/core/citrus-api/src/main/java/org/citrusframework/TestActionBuilder.java b/core/citrus-api/src/main/java/org/citrusframework/TestActionBuilder.java index b6b7db67bf..601c3926e6 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/TestActionBuilder.java +++ b/core/citrus-api/src/main/java/org/citrusframework/TestActionBuilder.java @@ -16,14 +16,14 @@ package org.citrusframework; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; + /** * Test action builder. * @since 2.3 @@ -64,7 +64,7 @@ static Map> lookup() { Map> builders = TYPE_RESOLVER.resolveAll(); if (logger.isDebugEnabled()) { - builders.forEach((k, v) -> logger.debug(String.format("Found test action builder '%s' as %s", k, v.getClass()))); + builders.forEach((k, v) -> logger.debug("Found test action builder '{}' as {}", k, v.getClass())); } return builders; } @@ -73,7 +73,7 @@ static Map> lookup() { * Resolves test action builder from resource path lookup with given resource name. Scans classpath for test action builder meta information * with given name and returns instance of the builder. Returns optional instead of throwing exception when no test action builder * could be found. - * + *

      * Given builder name is a combination of resource file name and type property separated by '.' character. * @param builder * @return @@ -82,7 +82,7 @@ static Optional> lookup(String builder) { try { return Optional.of(TYPE_RESOLVER.resolve(builder)); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve test action builder from resource '%s/%s'", RESOURCE_PATH, builder)); + logger.warn("Failed to resolve test action builder from resource '{}/{}'", RESOURCE_PATH, builder); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/annotations/CitrusEndpointAnnotations.java b/core/citrus-api/src/main/java/org/citrusframework/annotations/CitrusEndpointAnnotations.java index c14fc50dde..3a56669423 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/annotations/CitrusEndpointAnnotations.java +++ b/core/citrus-api/src/main/java/org/citrusframework/annotations/CitrusEndpointAnnotations.java @@ -16,9 +16,6 @@ package org.citrusframework.annotations; -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; - import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.spi.BindToRegistry; @@ -28,6 +25,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; + /** * Dependency injection support for {@link CitrusEndpoint} endpoint annotations. * @@ -57,7 +57,7 @@ public static void injectEndpoints(final Object target, final TestContext contex return; } - logger.debug(String.format("Injecting Citrus endpoint on test class field '%s'", field.getName())); + logger.debug("Injecting Citrus endpoint on test class field '{}'", field.getName()); CitrusEndpoint endpointAnnotation = field.getAnnotation(CitrusEndpoint.class); for (Annotation annotation : field.getAnnotations()) { diff --git a/core/citrus-api/src/main/java/org/citrusframework/common/TestLoader.java b/core/citrus-api/src/main/java/org/citrusframework/common/TestLoader.java index 79b3156d46..abbe9d5d5e 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/common/TestLoader.java +++ b/core/citrus-api/src/main/java/org/citrusframework/common/TestLoader.java @@ -16,16 +16,16 @@ package org.citrusframework.common; -import java.util.Map; -import java.util.Optional; -import java.util.function.Consumer; - import org.citrusframework.TestCase; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; +import java.util.function.Consumer; + /** * Test loader interface. * @since 2.1 @@ -86,7 +86,7 @@ static Map lookup() { Map loader = TYPE_RESOLVER.resolveAll(); if (logger.isDebugEnabled()) { - loader.forEach((k, v) -> logger.debug(String.format("Found test loader '%s' as %s", k, v.getClass()))); + loader.forEach((k, v) -> logger.debug("Found test loader '{}' as {}", k, v.getClass())); } return loader; } @@ -102,7 +102,7 @@ static Optional lookup(String loader) { try { return Optional.of(TYPE_RESOLVER.resolve(loader)); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve test loader from resource '%s/%s'", RESOURCE_PATH, loader)); + logger.warn("Failed to resolve test loader from resource '{}/{}'", RESOURCE_PATH, loader); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/config/annotation/AnnotationConfigParser.java b/core/citrus-api/src/main/java/org/citrusframework/config/annotation/AnnotationConfigParser.java index f497441f8b..1f3f612397 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/config/annotation/AnnotationConfigParser.java +++ b/core/citrus-api/src/main/java/org/citrusframework/config/annotation/AnnotationConfigParser.java @@ -16,11 +16,6 @@ package org.citrusframework.config.annotation; -import java.lang.annotation.Annotation; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.endpoint.Endpoint; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ReferenceResolver; @@ -29,6 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + /** * @since 2.5 */ @@ -63,7 +63,7 @@ static Map lookup() { parsers.putAll(TYPE_RESOLVER.resolveAll("", TypeResolver.TYPE_PROPERTY_WILDCARD)); if (logger.isDebugEnabled()) { - parsers.forEach((k, v) -> logger.debug(String.format("Found annotation config parser '%s' as %s", k, v.getClass()))); + parsers.forEach((k, v) -> logger.debug("Found annotation config parser '{}' as {}", k, v.getClass())); } } return parsers; @@ -73,7 +73,7 @@ static Map lookup() { * Resolves annotation config parser from resource path lookup with given resource name. Scans classpath for annotation config parser meta information * with given name and returns instance of the parser. Returns optional instead of throwing exception when no annotation config parser * could be found. - * + *

      * Given parser name is a combination of resource file name and type property separated by '.' character. * @param parser * @return @@ -90,7 +90,7 @@ static Optional lookup(String parser) { return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve annotation config parser from resource '%s/%s'", RESOURCE_PATH, parser)); + logger.warn("Failed to resolve annotation config parser from resource '{}/{}'", RESOURCE_PATH, parser); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/context/TestContext.java b/core/citrus-api/src/main/java/org/citrusframework/context/TestContext.java index 0bf62b1b7d..5a872a0ed0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/context/TestContext.java +++ b/core/citrus-api/src/main/java/org/citrusframework/context/TestContext.java @@ -16,17 +16,6 @@ package org.citrusframework.context; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; - import org.citrusframework.CitrusSettings; import org.citrusframework.TestAction; import org.citrusframework.TestActionBuilder; @@ -69,6 +58,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + /** * Class holding and managing test variables. The test context also provides utility methods * for replacing dynamic content(variables and functions) in message payloads and headers. @@ -255,7 +255,7 @@ public void setVariable(final String variableName, Object value) { } if (logger.isDebugEnabled()) { - logger.debug(String.format("Setting variable: %s with value: '%s'", VariableUtils.cutOffVariablesPrefix(variableName), value)); + logger.debug("Setting variable: {} with value: '{}'", VariableUtils.cutOffVariablesPrefix(variableName), value); } variables.put(VariableUtils.cutOffVariablesPrefix(variableName), value); @@ -849,7 +849,7 @@ private void logMessage(String operation, Message message, MessageDirection dire messageListeners.onInboundMessage(message, this); } } else if (logger.isDebugEnabled()) { - logger.debug(String.format("%s message:%n%s", operation, Optional.ofNullable(message).map(Message::toString).orElse(""))); + logger.debug("{} message:%n{}", operation, Optional.ofNullable(message).map(Message::toString).orElse("")); } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/context/resolver/TypeAliasResolver.java b/core/citrus-api/src/main/java/org/citrusframework/context/resolver/TypeAliasResolver.java index 24ca0dc75d..2bec20ee41 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/context/resolver/TypeAliasResolver.java +++ b/core/citrus-api/src/main/java/org/citrusframework/context/resolver/TypeAliasResolver.java @@ -16,16 +16,16 @@ package org.citrusframework.context.resolver; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + /** * Type resolver able to adapt an alias type to a given source type. Used in {@link org.citrusframework.spi.ReferenceResolver} to * auto resolve types that can act as an alias interchangeably to a given type. @@ -54,7 +54,7 @@ public interface TypeAliasResolver { resolvers.putAll(TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name")); if (logger.isDebugEnabled()) { - resolvers.forEach((k, v) -> logger.debug(String.format("Found type alias resolver '%s' as %s", k, v.getClass()))); + resolvers.forEach((k, v) -> logger.debug("Found type alias resolver '{}' as {}", k, v.getClass())); } } return resolvers; @@ -71,7 +71,7 @@ public interface TypeAliasResolver { try { return Optional.of(TYPE_RESOLVER.resolve(resolver)); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve type alias resolver from resource '%s/%s'", RESOURCE_PATH, resolver)); + logger.warn("Failed to resolve type alias resolver from resource '{}/{}'", RESOURCE_PATH, resolver); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/endpoint/DefaultEndpointFactory.java b/core/citrus-api/src/main/java/org/citrusframework/endpoint/DefaultEndpointFactory.java index daedca5ba0..d4b6a4b388 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/endpoint/DefaultEndpointFactory.java +++ b/core/citrus-api/src/main/java/org/citrusframework/endpoint/DefaultEndpointFactory.java @@ -16,12 +16,6 @@ package org.citrusframework.endpoint; -import java.lang.annotation.Annotation; -import java.util.Map; -import java.util.Optional; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; - import org.citrusframework.annotations.CitrusEndpoint; import org.citrusframework.annotations.CitrusEndpointConfig; import org.citrusframework.config.annotation.AnnotationConfigParser; @@ -31,11 +25,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.annotation.Annotation; +import java.util.Map; +import java.util.Optional; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; + /** * Default endpoint factory implementation uses registered endpoint components in Spring application context to create endpoint * from given endpoint uri. If endpoint bean name is given factory directly creates from application context. If endpoint uri is given * factory tries to find proper endpoint component in application context and in default endpoint component configuration. - * + *

      * Default endpoint components are listed in property file reference where key is the component name and value is the fully qualified class name * of the implementing endpoint component class. * @@ -133,7 +133,7 @@ public Endpoint create(String uri, TestContext context) { synchronized (endpointCache) { if (endpointCache.containsKey(cachedEndpointName)) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Found cached endpoint for uri '%s'", cachedEndpointName)); + logger.debug("Found cached endpoint for uri '{}'", cachedEndpointName); } return endpointCache.get(cachedEndpointName); } else { diff --git a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointBuilder.java b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointBuilder.java index 18ce48691c..9b889f161f 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointBuilder.java +++ b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointBuilder.java @@ -16,12 +16,6 @@ package org.citrusframework.endpoint; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; - import org.citrusframework.annotations.CitrusEndpoint; import org.citrusframework.annotations.CitrusEndpointProperty; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -33,6 +27,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + /** * Endpoint builder interface. All endpoint builder implementations do implement this interface * in order to build endpoints using a fluent Java API. @@ -116,7 +116,7 @@ static Map> lookup() { Map> builders = new HashMap<>(TYPE_RESOLVER.resolveAll("", TypeResolver.TYPE_PROPERTY_WILDCARD)); if (logger.isDebugEnabled()) { - builders.forEach((k, v) -> logger.debug(String.format("Found endpoint builder '%s' as %s", k, v.getClass()))); + builders.forEach((k, v) -> logger.debug("Found endpoint builder '{}' as {}", k, v.getClass())); } return builders; } @@ -125,7 +125,7 @@ static Map> lookup() { * Resolves endpoint builder from resource path lookup with given resource name. Scans classpath for endpoint builder meta information * with given name and returns instance of the builder. Returns optional instead of throwing exception when no endpoint builder * could be found. - * + *

      * Given builder name is a combination of resource file name and type property separated by '.' character. * @param builder * @return @@ -142,7 +142,7 @@ static Optional> lookup(String builder) { return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve endpoint builder from resource '%s/%s'", RESOURCE_PATH, builder)); + logger.warn("Failed to resolve endpoint builder from resource '{}/{}'", RESOURCE_PATH, builder); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointComponent.java b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointComponent.java index 7ea4e2c07a..1edb12b7e0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointComponent.java +++ b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointComponent.java @@ -16,15 +16,15 @@ package org.citrusframework.endpoint; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; + /** * Endpoint component registers with bean name in Spring application context and is then responsible to create proper endpoints dynamically from * endpoint uri values. Creates endpoint instance by parsing the dynamic endpoint uri with special properties and parameters. Creates proper endpoint @@ -75,7 +75,7 @@ static Map lookup() { Map components = TYPE_RESOLVER.resolveAll(); if (logger.isDebugEnabled()) { - components.forEach((k, v) -> logger.debug(String.format("Found endpoint component '%s' as %s", k, v.getClass()))); + components.forEach((k, v) -> logger.debug("Found endpoint component '{}' as {}", k, v.getClass())); } return components; } @@ -92,7 +92,7 @@ static Optional lookup(String component) { EndpointComponent instance = TYPE_RESOLVER.resolve(component); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve endpoint component from resource '%s/%s'", RESOURCE_PATH, component)); + logger.warn("Failed to resolve endpoint component from resource '{}/{}'", RESOURCE_PATH, component); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointFactory.java b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointFactory.java index 99f318f9c2..f003e05359 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointFactory.java +++ b/core/citrus-api/src/main/java/org/citrusframework/endpoint/EndpointFactory.java @@ -16,15 +16,15 @@ package org.citrusframework.endpoint; -import java.lang.annotation.Annotation; - import org.citrusframework.annotations.CitrusEndpoint; import org.citrusframework.context.TestContext; +import java.lang.annotation.Annotation; + /** * Endpoint factory tries to get endpoint instance by parsing an endpoint uri. Uri can have parameters * that get passed to the endpoint configuration. - * + *

      * If Spring application context is given searches for matching endpoint component bean and delegates to component for * endpoint creation. * diff --git a/core/citrus-api/src/main/java/org/citrusframework/functions/Function.java b/core/citrus-api/src/main/java/org/citrusframework/functions/Function.java index bba58d286c..d0c25caabd 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/functions/Function.java +++ b/core/citrus-api/src/main/java/org/citrusframework/functions/Function.java @@ -16,15 +16,15 @@ package org.citrusframework.functions; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * General function interface. * @@ -49,7 +49,7 @@ static Map lookup() { functions.putAll(new ResourcePathTypeResolver().resolveAll(RESOURCE_PATH)); if (logger.isDebugEnabled()) { - functions.forEach((k, v) -> logger.debug(String.format("Found function '%s' as %s", k, v.getClass()))); + functions.forEach((k, v) -> logger.debug("Found function '{}' as {}", k, v.getClass())); } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionRegistry.java index 923464c833..4cfbf452bd 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionRegistry.java @@ -16,12 +16,12 @@ package org.citrusframework.functions; -import java.util.ArrayList; -import java.util.List; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.NoSuchFunctionLibraryException; +import java.util.ArrayList; +import java.util.List; + /** * Function registry holding all available function libraries. * @@ -38,7 +38,7 @@ public class FunctionRegistry { * @return flag (true/false) */ public boolean isFunction(final String variableExpression) { - if (variableExpression == null || variableExpression.length() == 0) { + if (variableExpression == null || variableExpression.isEmpty()) { return false; } diff --git a/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionUtils.java b/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionUtils.java index 3b59c78980..fbfd138042 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionUtils.java +++ b/core/citrus-api/src/main/java/org/citrusframework/functions/FunctionUtils.java @@ -98,7 +98,7 @@ public static String replaceFunctionsInString(final String stringValue, TestCont strBuffer.append(newString, startIndex, searchIndex); if (enableQuoting) { - strBuffer.append("'" + value + "'"); + strBuffer.append("'").append(value).append("'"); } else { strBuffer.append(value); } diff --git a/core/citrus-api/src/main/java/org/citrusframework/main/TestEngine.java b/core/citrus-api/src/main/java/org/citrusframework/main/TestEngine.java index 0a65db111b..5c4abb8370 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/main/TestEngine.java +++ b/core/citrus-api/src/main/java/org/citrusframework/main/TestEngine.java @@ -49,7 +49,7 @@ public interface TestEngine { static TestEngine lookup(TestRunConfiguration configuration) { try { TestEngine testEngine = TYPE_RESOLVER.resolve(configuration.getEngine(), configuration); - logger.debug(String.format("Using Citrus engine '%s' as %s", configuration.getEngine(), testEngine)); + logger.debug("Using Citrus engine '{}' as {}", configuration.getEngine(), testEngine); return testEngine; } catch (CitrusRuntimeException e) { throw new CitrusRuntimeException(String.format("Failed to resolve Citrus engine from resource '%s/%s'", RESOURCE_PATH, configuration.getEngine()), e); diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/AbstractMessageProcessor.java b/core/citrus-api/src/main/java/org/citrusframework/message/AbstractMessageProcessor.java index 2370937d67..8f19623c0a 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/AbstractMessageProcessor.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/AbstractMessageProcessor.java @@ -38,7 +38,7 @@ public void process(Message message, TestContext context) { if (supportsMessageType(message.getType())) { processMessage(message, context); } else { - logger.debug(String.format("Message processor '%s' skipped for message type: %s", getName(), message.getType())); + logger.debug("Message processor '{}' skipped for message type: {}", getName(), message.getType()); } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/ErrorHandlingStrategy.java b/core/citrus-api/src/main/java/org/citrusframework/message/ErrorHandlingStrategy.java index c87eef7f89..df2fc30842 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/ErrorHandlingStrategy.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/ErrorHandlingStrategy.java @@ -27,7 +27,7 @@ public enum ErrorHandlingStrategy { PROPAGATE("propagateError"); /** Name representation */ - private String name; + private final String name; /** * Default constructor using String name representation field. diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderType.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderType.java index db6f87ce80..33ecadd825 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderType.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderType.java @@ -38,15 +38,15 @@ public enum MessageHeaderType { public static final String TYPE_SUFFIX = "}:"; /** Properties */ - private String name; - private Class clazz; + private final String name; + private final Class clazz; /** * Default constructor using fields. * @param name * @param clazz */ - private MessageHeaderType(String name, Class clazz) { + MessageHeaderType(String name, Class clazz) { this.name = name; this.clazz = clazz; } diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderUtils.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderUtils.java index 46e4121d03..436cafc8d0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderUtils.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessageHeaderUtils.java @@ -35,7 +35,7 @@ private MessageHeaderUtils() { /** * Check if given header name belongs to Spring Integration internal headers. - * + *

      * This is given if header name starts with internal header prefix or * matches one of Spring's internal header names. * diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java index 4c2a8824c8..3d06776ff0 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessagePayloadUtils.java @@ -105,7 +105,7 @@ public static String prettyPrintXml(String payload) { if (nextStartElementPos > i + 1) { String textBetweenElements = s.substring(i + 1, nextStartElementPos); - if (textBetweenElements.replaceAll("\\s", "").length() == 0) { + if (textBetweenElements.replaceAll("\\s", "").isEmpty()) { sb.append(System.lineSeparator()); } else { sb.append(textBetweenElements.trim()); diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessageProcessor.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessageProcessor.java index 5b84a59161..ec8e0edcc8 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessageProcessor.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessageProcessor.java @@ -16,8 +16,6 @@ package org.citrusframework.message; -import java.util.Optional; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; @@ -25,6 +23,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + /** * Processor performs operations on the given message. The processor is able to change message content such as payload and headers. */ @@ -52,7 +52,7 @@ static > Optional instance = TYPE_RESOLVER.resolve(processor); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve message processor from resource '%s/%s'", RESOURCE_PATH, processor)); + logger.warn("Failed to resolve message processor from resource '{}/{}'", RESOURCE_PATH, processor); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/MessageSelector.java b/core/citrus-api/src/main/java/org/citrusframework/message/MessageSelector.java index 5a14220140..ed3ee99422 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/MessageSelector.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/MessageSelector.java @@ -16,15 +16,15 @@ package org.citrusframework.message; -import java.util.Map; - -import java.util.concurrent.ConcurrentHashMap; import org.citrusframework.context.TestContext; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + @FunctionalInterface public interface MessageSelector { @@ -50,7 +50,7 @@ static Map lookup() { factories.putAll(TYPE_RESOLVER.resolveAll()); if (logger.isDebugEnabled()) { - factories.forEach((k, v) -> logger.debug(String.format("Found message selector '%s' as %s", k, v.getClass()))); + factories.forEach((k, v) -> logger.debug("Found message selector '{}' as {}", k, v.getClass())); } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/message/ScriptPayloadBuilder.java b/core/citrus-api/src/main/java/org/citrusframework/message/ScriptPayloadBuilder.java index a5601fa874..8f877e6d5c 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/message/ScriptPayloadBuilder.java +++ b/core/citrus-api/src/main/java/org/citrusframework/message/ScriptPayloadBuilder.java @@ -16,14 +16,14 @@ package org.citrusframework.message; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + public interface ScriptPayloadBuilder extends MessagePayloadBuilder { /** Logger */ @@ -47,7 +47,7 @@ static Optional lookup(String type) { T instance = TYPE_RESOLVER.resolve(type); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve script payload builder from resource '%s/%s'", RESOURCE_PATH, type)); + logger.warn("Failed to resolve script payload builder from resource '{}/{}'", RESOURCE_PATH, type); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/spi/BindToRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/spi/BindToRegistry.java index 7e274637b2..8d5cb77f29 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/spi/BindToRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/spi/BindToRegistry.java @@ -24,7 +24,7 @@ /** * Used to bind an object to the Citrus context reference registry for dependency injection reasons. - * + *

      * Object is bound with given name. In case no explicit name is given the registry will auto compute the name from given * Class name, method name or field name. * diff --git a/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java b/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java index aaaed98d12..d0ca407b16 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java +++ b/core/citrus-api/src/main/java/org/citrusframework/util/ReflectionHelper.java @@ -16,16 +16,16 @@ package org.citrusframework.util; -import static java.lang.String.format; - import jakarta.annotation.Nonnull; +import org.citrusframework.exceptions.CitrusRuntimeException; + import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; -import org.citrusframework.exceptions.CitrusRuntimeException; +import static java.lang.String.format; /** * Helper for working with reflection on classes. @@ -282,7 +282,5 @@ public static void copyFields(@Nonnull Class clazz, @Nonnull Object source, @ currentClass = currentClass.getSuperclass(); } - } - } diff --git a/core/citrus-api/src/main/java/org/citrusframework/util/TypeConverter.java b/core/citrus-api/src/main/java/org/citrusframework/util/TypeConverter.java index 3e25a57157..4e9b0d5617 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/util/TypeConverter.java +++ b/core/citrus-api/src/main/java/org/citrusframework/util/TypeConverter.java @@ -16,14 +16,14 @@ package org.citrusframework.util; -import java.util.HashMap; -import java.util.Map; - import org.citrusframework.CitrusSettings; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; + public interface TypeConverter { /** Logger */ @@ -48,12 +48,12 @@ static Map lookup() { if (converters.isEmpty()) { converters.putAll(new ResourcePathTypeResolver().resolveAll(RESOURCE_PATH)); - if (converters.size() == 0) { + if (converters.isEmpty()) { converters.put(DEFAULT, DefaultTypeConverter.INSTANCE); } if (logger.isDebugEnabled()) { - converters.forEach((k, v) -> logger.debug(String.format("Found type converter '%s' as %s", k, v.getClass()))); + converters.forEach((k, v) -> logger.debug("Found type converter '{}' as {}", k, v.getClass())); } } @@ -64,7 +64,7 @@ static Map lookup() { * Lookup default type converter specified by resource path lookup and/or environment settings. In case only a single type converter is loaded * via resource path lookup this converter is used regardless of any environment settings. If there are multiple converter implementations * on the classpath the environment settings must specify the default. - * + *

      * If no converter implementation is given via resource path lookup the default implementation is returned. * @return type converter to use by default. */ @@ -76,7 +76,7 @@ static TypeConverter lookupDefault() { * Lookup default type converter specified by resource path lookup and/or environment settings. In case only a single type converter is loaded * via resource path lookup this converter is used regardless of any environment settings. If there are multiple converter implementations * on the classpath the environment settings must specify the default. - * + *

      * If no converter implementation is given via resource path lookup the default implementation is returned. * * @param defaultTypeConverter the fallback default converter @@ -89,20 +89,20 @@ static TypeConverter lookupDefault(TypeConverter defaultTypeConverter) { if (converters.size() == 1) { Map.Entry converterEntry = converters.entrySet().iterator().next(); if (logger.isDebugEnabled()) { - logger.debug(String.format("Using type converter '%s'", converterEntry.getKey())); + logger.debug("Using type converter '{}'", converterEntry.getKey()); } return converterEntry.getValue(); } else if (converters.containsKey(name)) { if (logger.isDebugEnabled()) { - logger.debug(String.format("Using type converter '%s'", name)); + logger.debug("Using type converter '{}'", name); } return converters.get(name); } if (!CitrusSettings.TYPE_CONVERTER_DEFAULT.equals(name)) { - logger.warn(String.format("Missing type converter for name '%s' - using default type converter", name)); + logger.warn("Missing type converter for name '{}' - using default type converter", name); } return defaultTypeConverter; diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/HeaderValidator.java b/core/citrus-api/src/main/java/org/citrusframework/validation/HeaderValidator.java index 1adf884c9c..e5eb3fccab 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/HeaderValidator.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/HeaderValidator.java @@ -16,10 +16,6 @@ package org.citrusframework.validation; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; @@ -28,6 +24,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + /** * @since 2.7.6 */ @@ -54,7 +54,7 @@ static Map lookup() { validators.putAll(TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name")); if (logger.isDebugEnabled()) { - validators.forEach((k, v) -> logger.debug(String.format("Found header validator '%s' as %s", k, v.getClass()))); + validators.forEach((k, v) -> logger.debug("Found header validator '{}' as {}", k, v.getClass())); } } return validators; @@ -72,7 +72,7 @@ static Optional lookup(String validator) { HeaderValidator instance = TYPE_RESOLVER.resolve(validator); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve header validator from resource '%s/%s'", RESOURCE_PATH, validator)); + logger.warn("Failed to resolve header validator from resource '{}/{}'", RESOURCE_PATH, validator); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidator.java b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidator.java index ca436bda24..2fab5c3c9f 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidator.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidator.java @@ -16,10 +16,6 @@ package org.citrusframework.validation; -import java.util.List; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -31,6 +27,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; +import java.util.Map; +import java.util.Optional; + /** * Message validator interface. Message validation need specific information like * control messages or validation scripts. These validation specific information is @@ -57,7 +57,7 @@ static Map> lookup() { Map> validators = TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name"); if (logger.isDebugEnabled()) { - validators.forEach((k, v) -> logger.debug(String.format("Found message validator '%s' as %s", k, v.getClass()))); + validators.forEach((k, v) -> logger.debug("Found message validator '{}' as {}", k, v.getClass())); } return validators; @@ -75,7 +75,7 @@ static Optional> lookup(String val MessageValidator instance = TYPE_RESOLVER.resolve(validator); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve validator from resource '%s/%s'", RESOURCE_PATH, validator)); + logger.warn("Failed to resolve validator from resource '{}/{}'", RESOURCE_PATH, validator); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java index bbeecbcab6..d54c371799 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/MessageValidatorRegistry.java @@ -16,12 +16,6 @@ package org.citrusframework.validation; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.NoSuchMessageValidatorException; import org.citrusframework.message.Message; @@ -33,10 +27,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static java.lang.String.format; + /** * Simple registry holding all available message validator implementations. Test context can ask this registry for * matching validator implementation according to the message type (e.g. xml, json, csv, plaintext). - * + *

      * Registry tries to find a matching validator for the message. * */ @@ -105,18 +107,17 @@ public List> findMessageValidators } } - if (isEmptyOrDefault(matchingValidators) && - (message.getPayload(String.class) == null || message.getPayload(String.class).isBlank())) { + if (isEmptyOrDefault(matchingValidators) + && (message.getPayload(String.class) == null || message.getPayload(String.class).isBlank())) { matchingValidators.add(defaultEmptyMessageValidator); } if (isEmptyOrDefault(matchingValidators)) { if (mustFindValidator) { if (logger.isWarnEnabled()) { - logger.warn(String.format( - "Unable to find proper message validator. Message type is '%s' and message payload is '%s'", - messageType, message.getPayload(String.class))); + logger.warn("Unable to find proper message validator. Message type is '{}' and message payload is '{}'", messageType, message.getPayload(String.class)); } + throw new CitrusRuntimeException("Failed to find proper message validator for message"); } @@ -124,9 +125,7 @@ public List> findMessageValidators matchingValidators.add(defaultTextEqualsMessageValidator); } - if (logger.isDebugEnabled()) { - logger.debug(String.format("Found %s message validators for message", matchingValidators.size())); - } + logger.debug("Found {} message validators for message", matchingValidators.size()); return matchingValidators; } @@ -201,7 +200,7 @@ public MessageValidator getMessageValidator(String return this.messageValidators.get(name); } - throw new NoSuchMessageValidatorException(String.format("Unable to find message validator with name '%s'", name)); + throw new NoSuchMessageValidatorException(format("Unable to find message validator with name '%s'", name)); } /** @@ -211,7 +210,7 @@ public MessageValidator getMessageValidator(String */ public void addMessageValidator(String name, MessageValidator messageValidator) { if (this.messageValidators.containsKey(name) && logger.isDebugEnabled()) { - logger.debug(String.format("Overwriting message validator '%s' in registry", name)); + logger.debug("Overwriting message validator '{}' in registry", name); } this.messageValidators.put(name, messageValidator); @@ -224,7 +223,7 @@ public void addMessageValidator(String name, MessageValidator schemaValidator) { if (this.schemaValidators.containsKey(name) && logger.isDebugEnabled()) { - logger.debug(String.format("Overwriting message validator '%s' in registry", name)); + logger.debug("Overwriting message validator '{}' in registry", name); } this.schemaValidators.put(name, schemaValidator); @@ -234,8 +233,7 @@ public void addSchemaValidator(String name, SchemaValidator> messageValidators) { + public void setMessageValidators(Map> messageValidators) { this.messageValidators = messageValidators; } diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java b/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java index 3d6a8d11d0..99549bee6a 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/SchemaValidator.java @@ -32,7 +32,7 @@ public interface SchemaValidator { /** Logger */ - Logger logger = LoggerFactory.getLogger(MessageValidator.class); + Logger logger = LoggerFactory.getLogger(SchemaValidator.class); /** Schema validator resource lookup path */ String RESOURCE_PATH = "META-INF/citrus/message/schemaValidator"; @@ -49,7 +49,7 @@ static Map> lookup() Map> validators = TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name"); if (logger.isDebugEnabled()) { - validators.forEach((k, v) -> logger.debug(String.format("Found message validator '%s' as %s", k, v.getClass()))); + validators.forEach((k, v) -> logger.debug("Found message validator '{}' as {}", k, v.getClass())); } return validators; @@ -67,7 +67,7 @@ static Optional> lookup(Strin SchemaValidator instance = TYPE_RESOLVER.resolve(validator); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve validator from resource '%s/%s'", RESOURCE_PATH, validator)); + logger.warn("Failed to resolve validator from resource '{}/{}'", RESOURCE_PATH, validator); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/ValueMatcher.java b/core/citrus-api/src/main/java/org/citrusframework/validation/ValueMatcher.java index c95c793394..a186fa0d81 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/ValueMatcher.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/ValueMatcher.java @@ -16,10 +16,6 @@ package org.citrusframework.validation; -import java.util.Map; -import java.util.Optional; - -import java.util.concurrent.ConcurrentHashMap; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; @@ -27,10 +23,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + public interface ValueMatcher { /** Logger */ - Logger logger = LoggerFactory.getLogger(MessageValidator.class); + Logger logger = LoggerFactory.getLogger(ValueMatcher.class); /** Message validator resource lookup path */ String RESOURCE_PATH = "META-INF/citrus/value/matcher"; @@ -50,7 +50,7 @@ static Map lookup() { validators.putAll(TYPE_RESOLVER.resolveAll()); if (logger.isDebugEnabled()) { - validators.forEach((k, v) -> logger.debug(String.format("Found validator '%s' as %s", k, v.getClass()))); + validators.forEach((k, v) -> logger.debug("Found validator '{}' as {}", k, v.getClass())); } } return validators; @@ -68,7 +68,7 @@ static Optional lookup(String validator) { ValueMatcher instance = TYPE_RESOLVER.resolve(validator); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve value matcher from resource '%s/%s'", RESOURCE_PATH, validator)); + logger.warn("Failed to resolve value matcher from resource '{}/{}'", RESOURCE_PATH, validator); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/DefaultControlExpressionParser.java b/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/DefaultControlExpressionParser.java index a967eea9ae..6c99193476 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/DefaultControlExpressionParser.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/DefaultControlExpressionParser.java @@ -16,11 +16,11 @@ package org.citrusframework.validation.matcher; +import org.citrusframework.exceptions.CitrusRuntimeException; + import java.util.ArrayList; import java.util.List; -import org.citrusframework.exceptions.CitrusRuntimeException; - /** * Default implementation of control expression parser. * @since 2.5 @@ -34,7 +34,7 @@ public List extractControlValues(String controlExpression, Character del if (controlExpression != null && !controlExpression.isBlank()) { extractParameters(controlExpression, useDelimiter, extractedParameters, 0); - if (extractedParameters.size() == 0) { + if (extractedParameters.isEmpty()) { // if the controlExpression has text but no parameters were extracted, then assume that // the controlExpression itself is the only parameter extractedParameters.add(controlExpression); diff --git a/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/ValidationMatcher.java b/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/ValidationMatcher.java index 19dcaecd85..731f92d91e 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/ValidationMatcher.java +++ b/core/citrus-api/src/main/java/org/citrusframework/validation/matcher/ValidationMatcher.java @@ -16,16 +16,16 @@ package org.citrusframework.validation.matcher; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * General validation matcher interface. * @@ -51,7 +51,7 @@ static Map lookup() { matcher.putAll(new ResourcePathTypeResolver().resolveAll(RESOURCE_PATH)); if (logger.isDebugEnabled()) { - matcher.forEach((k, v) -> logger.debug(String.format("Found validation matcher '%s' as %s", k, v.getClass()))); + matcher.forEach((k, v) -> logger.debug("Found validation matcher '{}' as {}", k, v.getClass())); } } return matcher; diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java index 0f4b6c22c8..3bb7742ce2 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/SegmentVariableExtractorRegistry.java @@ -16,14 +16,6 @@ package org.citrusframework.variable; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; @@ -32,6 +24,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + /** * Simple registry holding all available segment variable extractor implementations. Test context can ask this registry for * the extractors managed by this registry in order to access variable content from the TestContext expressed by variable expressions. @@ -41,7 +41,7 @@ public class SegmentVariableExtractorRegistry { /** Logger */ - private static final Logger logger = LoggerFactory.getLogger(SegmentVariableExtractor.class); + private static final Logger logger = LoggerFactory.getLogger(SegmentVariableExtractorRegistry.class); /** Segment variable extractor resource lookup path */ private static final String RESOURCE_PATH = "META-INF/citrus/variable/extractor/segment"; @@ -60,7 +60,7 @@ static Collection lookup() { Map extractors = TYPE_RESOLVER.resolveAll(); return extractors.values(); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve segment variable extractor from resource '%s'", RESOURCE_PATH)); + logger.warn("Failed to resolve segment variable extractor from resource '{}'", RESOURCE_PATH); } return Collections.emptyList(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExtractor.java b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExtractor.java index 67c3c50a68..ef3792bfff 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExtractor.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableExtractor.java @@ -16,8 +16,6 @@ package org.citrusframework.variable; -import java.util.Optional; - import org.citrusframework.builder.WithExpressions; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -28,6 +26,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + /** * Class extracting variables form messages. Implementing classes may read * message contents and save those to test variables. @@ -56,7 +56,7 @@ static > Optional instance = TYPE_RESOLVER.resolve(extractor); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve variable extractor from resource '%s/%s'", RESOURCE_PATH, extractor)); + logger.warn("Failed to resolve variable extractor from resource '{}/{}'", RESOURCE_PATH, extractor); } return Optional.empty(); diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableUtils.java b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableUtils.java index 55a2cb329c..98fc6e8bb8 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/VariableUtils.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/VariableUtils.java @@ -16,15 +16,15 @@ package org.citrusframework.variable; -import javax.script.ScriptEngine; -import javax.script.ScriptEngineManager; -import javax.script.ScriptException; - import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.NoSuchVariableException; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; + /** * Utility class manipulating test variables. * @@ -118,15 +118,11 @@ public static String cutOffVariablesEscaping(String variable) { * @return flag true/false */ public static boolean isVariableName(final String expression) { - if (expression == null || expression.length() == 0) { + if (expression == null || expression.isEmpty()) { return false; } - if (expression.startsWith(CitrusSettings.VARIABLE_PREFIX) && expression.endsWith(CitrusSettings.VARIABLE_SUFFIX)) { - return true; - } - - return false; + return expression.startsWith(CitrusSettings.VARIABLE_PREFIX) && expression.endsWith(CitrusSettings.VARIABLE_SUFFIX); } /** @@ -176,7 +172,7 @@ public static String replaceVariablesInString(final String str, TestContext cont final String value = context.getVariable(variableNameBuf.toString()); if (value == null) { - throw new NoSuchVariableException("Variable: " + variableNameBuf.toString() + " could not be found"); + throw new NoSuchVariableException("Variable: " + variableNameBuf + " could not be found"); } newStr.append(str, startIndex, searchIndex); diff --git a/core/citrus-api/src/main/java/org/citrusframework/variable/dictionary/DataDictionary.java b/core/citrus-api/src/main/java/org/citrusframework/variable/dictionary/DataDictionary.java index 29093b6e1a..a96f52f935 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/variable/dictionary/DataDictionary.java +++ b/core/citrus-api/src/main/java/org/citrusframework/variable/dictionary/DataDictionary.java @@ -26,7 +26,7 @@ * Data dictionary interface describes a mechanism to modify message content (payload) with global dictionary elements. * Dictionary translates element values to those defined in dictionary. Message construction process is aware of dictionaries * in Spring application context so user just has to add dictionary implementation to application context. - * + *

      * Dictionary takes part in message construction for inbound and outbound messages in Citrus. * @since 1.4 */ @@ -59,6 +59,6 @@ public interface DataDictionary extends MessageProcessor, MessageDirectionAwa enum PathMappingStrategy { EXACT, ENDS_WITH, - STARTS_WITH; + STARTS_WITH } } diff --git a/core/citrus-api/src/main/java/org/citrusframework/xml/namespace/NamespaceContextBuilder.java b/core/citrus-api/src/main/java/org/citrusframework/xml/namespace/NamespaceContextBuilder.java index a4a7dae971..744023946a 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/xml/namespace/NamespaceContextBuilder.java +++ b/core/citrus-api/src/main/java/org/citrusframework/xml/namespace/NamespaceContextBuilder.java @@ -16,18 +16,18 @@ package org.citrusframework.xml.namespace; +import org.citrusframework.message.Message; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import javax.xml.XMLConstants; -import javax.xml.namespace.NamespaceContext; - -import org.citrusframework.message.Message; /** * Builds a namespace context for XPath expression evaluations. Builder supports default mappings * as well as dynamic mappings from received message. - * + *

      * Namespace mappings are defined as key value pairs where key is definded as namespace prefix and value is the * actual namespace uri. * @@ -50,7 +50,7 @@ public NamespaceContext buildContext(Message receivedMessage, Map 0) { + if (!namespaceMappings.isEmpty()) { defaultNamespaceContext.addNamespaces(namespaceMappings); } diff --git a/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java b/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java index d89f582038..e6b33b73a9 100644 --- a/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java +++ b/core/citrus-api/src/test/java/org/citrusframework/message/MessagePayloadUtilsTest.java @@ -16,12 +16,11 @@ package org.citrusframework.message; -import static org.testng.Assert.assertEquals; - -import org.testng.Assert; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + public class MessagePayloadUtilsTest { @Test From d05a76a7a5bf2e9bdb1577902a4259749e38ccef Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 10:34:52 +0200 Subject: [PATCH 21/47] chore(citrus-base): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 citrus-base` module. --- .../AbstractTestContainerBuilder.java | 8 +-- .../CitrusContextProvider.java | 8 +-- .../TestCaseRunnerFactory.java | 2 +- .../citrusframework/actions/AntRunAction.java | 31 ++++----- .../actions/CreateVariablesAction.java | 10 +-- .../citrusframework/actions/EchoAction.java | 6 +- .../citrusframework/actions/InputAction.java | 20 +++--- .../citrusframework/actions/JavaAction.java | 20 +++--- .../actions/LoadPropertiesAction.java | 23 +++---- .../actions/PurgeEndpointAction.java | 18 ++--- .../actions/ReceiveMessageAction.java | 42 +++++------- .../actions/ReceiveTimeoutAction.java | 12 ++-- .../actions/SendMessageAction.java | 25 +++---- .../citrusframework/actions/SleepAction.java | 27 ++++---- .../actions/StartServerAction.java | 12 ++-- .../actions/StopServerAction.java | 12 ++-- .../actions/StopTimeAction.java | 6 +- .../actions/StopTimerAction.java | 2 +- .../actions/TraceVariablesAction.java | 14 ++-- .../actions/TransformAction.java | 4 +- .../annotations/CitrusAnnotations.java | 20 +++--- .../condition/ActionCondition.java | 11 ++-- .../condition/FileCondition.java | 10 ++- .../condition/HttpCondition.java | 16 ++--- .../condition/MessageCondition.java | 2 +- .../container/AbstractActionContainer.java | 20 +++--- .../AbstractSuiteActionContainer.java | 31 ++++----- .../AbstractTestBoundaryActionContainer.java | 22 +++---- .../org/citrusframework/container/Assert.java | 4 +- .../org/citrusframework/container/Catch.java | 6 +- .../citrusframework/container/Iterate.java | 2 +- .../container/RepeatOnErrorUntilTrue.java | 3 - .../container/RepeatUntilTrue.java | 2 +- .../container/SequenceAfterSuite.java | 4 +- .../container/SequenceAfterTest.java | 2 +- .../container/SequenceBeforeSuite.java | 4 +- .../container/SequenceBeforeTest.java | 2 +- .../citrusframework/container/Template.java | 6 +- .../container/TemplateLoader.java | 12 ++-- .../org/citrusframework/container/Timer.java | 6 +- .../org/citrusframework/container/Wait.java | 4 +- .../endpoint/AbstractEndpointComponent.java | 27 ++++---- .../endpoint/direct/DirectConsumer.java | 8 +-- .../endpoint/direct/DirectSyncConsumer.java | 9 ++- .../endpoint/direct/DirectSyncProducer.java | 12 ++-- .../resolver/DynamicEndpointUriResolver.java | 10 +-- .../functions/DefaultFunctionLibrary.java | 8 +-- .../core/AdvancedRandomNumberFunction.java | 65 ++++++++----------- .../functions/core/DecodeBase64Function.java | 8 +-- .../functions/core/EncodeBase64Function.java | 8 +-- .../functions/core/RandomNumberFunction.java | 8 +-- .../functions/core/RandomPatternFunction.java | 15 ++--- .../functions/core/RandomStringFunction.java | 1 + .../core/ReadFileResourceFunction.java | 10 +-- .../functions/core/SubstringFunction.java | 6 +- .../functions/core/UrlDecodeFunction.java | 10 +-- .../functions/core/UrlEncodeFunction.java | 10 +-- .../log/DefaultLogModifier.java | 6 +- .../main/scan/ClassPathTestScanner.java | 18 ++--- .../message/DefaultMessage.java | 1 - .../message/DefaultMessageQueue.java | 15 ++--- .../citrusframework/message/ZipMessage.java | 18 ++--- .../DefaultCorrelationManager.java | 20 ++---- .../PollingCorrelationManager.java | 8 +-- .../report/AbstractOutputFileReporter.java | 10 +-- .../citrusframework/report/HtmlReporter.java | 22 +++---- .../report/MessageTracingTestListener.java | 24 +++---- .../server/AbstractServer.java | 18 ++--- .../sharding/ShardingConfiguration.java | 4 +- .../util/BooleanExpressionParser.java | 4 +- .../org/citrusframework/util/FileUtils.java | 33 ++++------ .../citrusframework/util/PropertyUtils.java | 8 +-- .../org/citrusframework/util/StringUtils.java | 11 ++-- .../org/citrusframework/util/TestUtils.java | 4 +- .../validation/DefaultHeaderValidator.java | 25 ++++--- .../DefaultMessageHeaderValidator.java | 20 +++--- .../DelegatingPayloadVariableExtractor.java | 4 +- .../validation/ValidationUtils.java | 14 ++-- .../json/JsonMessageValidationContext.java | 10 +-- .../DefaultValidationMatcherLibrary.java | 4 +- .../core/CreateVariableValidationMatcher.java | 6 +- .../core/DateRangeValidationMatcher.java | 5 +- .../matcher/core/IgnoreValidationMatcher.java | 4 +- .../core/WeekdayValidationMatcher.java | 2 +- .../script/TemplateBasedScriptBuilder.java | 12 ++-- .../sql/SqlResultSetScriptValidator.java | 8 +-- .../citrusframework/xml/Jaxb2Marshaller.java | 41 +++++------- .../org/citrusframework/TestCaseTest.java | 18 ++--- .../actions/PurgeEndpointActionTest.java | 8 +-- .../actions/ReceiveMessageBuilderTest.java | 25 ++++--- .../dsl/ReceiveMessageActionBuilderTest.java | 27 ++++---- .../dsl/SendMessageActionBuilderTest.java | 13 ++-- .../HeaderMappingKeyExtractorTest.java | 6 +- .../SoapActionMappingKeyExtractorTest.java | 4 +- .../direct/DirectEndpointComponentTest.java | 10 +-- .../functions/FunctionsTest.java | 40 +++++++----- .../AdvancedRandomNumberFunctionTest.java | 16 ++--- .../core/LoadMessageFunctionTest.java | 12 ++-- .../core/RandomPatternFunctionTest.java | 21 +++--- .../core/RandomStringFunctionTest.java | 13 ++-- .../message/DefaultMessageStoreTest.java | 4 +- .../PollingCorrelationManagerTest.java | 2 +- .../report/LoggingReporterTest.java | 6 +- .../MessageTracingTestListenerTest.java | 12 ++-- .../citrusframework/util/FileUtilsTest.java | 14 ++-- .../citrusframework/util/InvocationDummy.java | 44 +++++-------- .../citrusframework/util/StringUtilsTest.java | 52 +++++++-------- .../DefaultMessageHeaderValidatorTest.java | 16 ++--- ...DefaultTextEqualsMessageValidatorTest.java | 6 +- .../MessageValidatorRegistryTest.java | 22 +++---- .../validation/ValidationUtilsTest.java | 14 ++-- .../BinaryMessageProcessorTest.java | 7 +- .../interceptor/GzipMessageProcessorTest.java | 22 +++---- .../openapi/generator/CitrusJavaCodegen.java | 10 +-- 114 files changed, 709 insertions(+), 820 deletions(-) diff --git a/core/citrus-base/src/main/java/org/citrusframework/AbstractTestContainerBuilder.java b/core/citrus-base/src/main/java/org/citrusframework/AbstractTestContainerBuilder.java index 09f66d81e1..e0740fc7c1 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/AbstractTestContainerBuilder.java +++ b/core/citrus-base/src/main/java/org/citrusframework/AbstractTestContainerBuilder.java @@ -16,15 +16,15 @@ package org.citrusframework; +import org.citrusframework.container.TestActionContainer; +import org.citrusframework.spi.ReferenceResolver; +import org.citrusframework.spi.ReferenceResolverAware; + import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.citrusframework.container.TestActionContainer; -import org.citrusframework.spi.ReferenceResolver; -import org.citrusframework.spi.ReferenceResolverAware; - /** * Abstract container builder takes care on calling the container runner when actions are placed in the container. */ diff --git a/core/citrus-base/src/main/java/org/citrusframework/CitrusContextProvider.java b/core/citrus-base/src/main/java/org/citrusframework/CitrusContextProvider.java index 33c19afd8d..2a57de23b8 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/CitrusContextProvider.java +++ b/core/citrus-base/src/main/java/org/citrusframework/CitrusContextProvider.java @@ -16,15 +16,15 @@ package org.citrusframework; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; + @FunctionalInterface public interface CitrusContextProvider { @@ -85,7 +85,7 @@ static Optional lookup(String name) { CitrusContextProvider instance = TYPE_RESOLVER.resolve(name); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve Citrus context provider from resource '%s/%s'", RESOURCE_PATH, name)); + logger.warn("Failed to resolve Citrus context provider from resource '{}/{}'", RESOURCE_PATH, name); } return Optional.empty(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/TestCaseRunnerFactory.java b/core/citrus-base/src/main/java/org/citrusframework/TestCaseRunnerFactory.java index 4e9b1a9b9b..074a029f02 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/TestCaseRunnerFactory.java +++ b/core/citrus-base/src/main/java/org/citrusframework/TestCaseRunnerFactory.java @@ -25,7 +25,7 @@ * Citrus' built-in runner, but it also offers the flexibility to replace the default runner with a * custom implementation. To do this, it leverages the Citrus {@link ResourcePathTypeResolver} * mechanism. - * + *

      * To provide a custom runner, the following file needs to be added to the classpath: *

      * diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/AntRunAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/AntRunAction.java index de79a038c6..44aa241e4c 100755 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/AntRunAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/AntRunAction.java @@ -16,12 +16,6 @@ package org.citrusframework.actions; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Stack; - import org.apache.tools.ant.BuildException; import org.apache.tools.ant.BuildListener; import org.apache.tools.ant.DefaultLogger; @@ -38,10 +32,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Stack; + /** * Action calls Apache ANT with given build file and runs ANT targets * as separate build. User can set and overwrite properties for the build. - * + *

      * Build logging output is forwarded to test run logger. * * @since 1.3 @@ -95,7 +95,7 @@ public void doExecute(TestContext context) { for (Entry entry : properties.entrySet()) { String propertyValue = entry.getValue() != null ? context.replaceDynamicContentInString(entry.getValue().toString()) : ""; - logger.debug("Set build property: " + entry.getKey() + "=" + propertyValue); + logger.debug("Set build property: {}={}", entry.getKey(), propertyValue); project.setProperty(entry.getKey().toString(), propertyValue); } @@ -109,20 +109,20 @@ public void doExecute(TestContext context) { project.addBuildListener(consoleLogger); - logger.info("Executing ANT build: " + buildFileResource); + logger.info("Executing ANT build: {}", buildFileResource); if (StringUtils.hasText(targets)) { - logger.info("Executing ANT targets: " + targets); + logger.info("Executing ANT targets: {}", targets); project.executeTargets(parseTargets()); } else { - logger.info("Executing ANT target: " + target); + logger.info("Executing ANT target: {}", target); project.executeTarget(target); } } catch (BuildException e) { throw new CitrusRuntimeException("Failed to run ANT build file", e); } - logger.info("Executed ANT build: " + buildFileResource); + logger.info("Executed ANT build: {}", buildFileResource); } private static DefaultLogger getDefaultConsoleLogger() { @@ -166,7 +166,7 @@ private Stack parseTargets() { private void loadBuildPropertyFile(Project project, TestContext context) { if (StringUtils.hasText(propertyFilePath)) { String propertyFileResource = context.replaceDynamicContentInString(propertyFilePath); - logger.info("Reading build property file: " + propertyFileResource); + logger.info("Reading build property file: {}", propertyFileResource); Properties fileProperties = new Properties(); try { Resource propertyResource = Resources.fromClasspath(propertyFileResource); @@ -174,10 +174,7 @@ private void loadBuildPropertyFile(Project project, TestContext context) { for (Entry entry : fileProperties.entrySet()) { String propertyValue = entry.getValue() != null ? context.replaceDynamicContentInString(entry.getValue().toString()) : ""; - - if (logger.isDebugEnabled()) { - logger.debug("Set build property from file resource: " + entry.getKey() + "=" + propertyValue); - } + logger.debug("Set build property from file resource: {}={}", entry.getKey(), propertyValue); project.setProperty(entry.getKey().toString(), propertyValue); } } catch (IOException e) { diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/CreateVariablesAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/CreateVariablesAction.java index 2788d24009..8f87eefdd3 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/CreateVariablesAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/CreateVariablesAction.java @@ -16,16 +16,16 @@ package org.citrusframework.actions; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.variable.VariableUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + /** * Action creating new test variables during a test. Existing test variables are overwritten * by new values. @@ -64,7 +64,7 @@ public void doExecute(TestContext context) { //check if value is variable or function (and resolve it if yes) value = context.replaceDynamicContentInString(value); - logger.info("Setting variable: " + key + " to value: " + value); + logger.info("Setting variable: {} to value: {}", key, value); context.setVariable(key, value); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/EchoAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/EchoAction.java index 357b9ec178..930c7cab79 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/EchoAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/EchoAction.java @@ -16,13 +16,13 @@ package org.citrusframework.actions; -import java.util.Date; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Date; + /** * Prints messages to the console/logger during test execution. * @@ -49,7 +49,7 @@ private EchoAction(Builder builder) { @Override public void doExecute(TestContext context) { if (message == null) { - logger.info("Citrus test " + new Date(System.currentTimeMillis())); + logger.info("Citrus test {}", new Date(System.currentTimeMillis())); } else { logger.info(context.getLogModifier().mask(context.replaceDynamicContentInString(message))); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/InputAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/InputAction.java index 24e85d8661..34228e74c4 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/InputAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/InputAction.java @@ -16,6 +16,13 @@ package org.citrusframework.actions; +import org.citrusframework.AbstractTestActionBuilder; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -24,17 +31,10 @@ import java.util.StringTokenizer; import java.util.stream.Stream; -import org.citrusframework.AbstractTestActionBuilder; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.citrusframework.util.StringUtils; - /** * Test action prompts user data from standard input stream. The input data is then stored as new * test variable. Test workflow stops until user input is complete. - * + *

      * Action can declare a set of valid answers, so user will be prompted until a valid * answer was returned. * @@ -77,7 +77,7 @@ public void doExecute(TestContext context) { if (context.getVariables().containsKey(variable)) { input = context.getVariable(variable); - logger.info("Variable " + variable + " is already set (='" + input + "'). Skip waiting for user input"); + logger.info("Variable {} is already set (='{}'). Skip waiting for user input", variable, input); return; } @@ -123,7 +123,7 @@ private boolean checkAnswer(String input) { } } - logger.info("User input is not valid - must be one of " + validAnswers); + logger.info("User input is not valid - must be one of {}", validAnswers); return false; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/JavaAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/JavaAction.java index a8009c3fb9..39c6c22617 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/JavaAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/JavaAction.java @@ -16,14 +16,6 @@ package org.citrusframework.actions; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -32,6 +24,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + /** * Action to enable class invocation through java reflection * @@ -125,7 +125,7 @@ private void invokeMethod(Object instance, Class[] methodTypes, Object[] meth Arrays.stream(methodTypes).map(Class::getSimpleName).collect(Collectors.joining(",")) + ")' for class '" + instance.getClass() + "'"); } - logger.info("Invoking method '" + methodToRun.toString() + "' on instance '" + instance.getClass() + "'"); + logger.info("Invoking method '{}' on instance '{}'", methodToRun, instance.getClass()); methodToRun.invoke(instance, methodObjects); } @@ -152,7 +152,7 @@ private Object getObjectInstanceFromClass(TestContext context) throws ClassNotFo "is set for Java reflection call"); } - logger.info("Instantiating class for name '" + className + "'"); + logger.info("Instantiating class for name '{}'", className); Class classToRun = Class.forName(className); diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/LoadPropertiesAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/LoadPropertiesAction.java index 29f989a8d3..70f340e33b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/LoadPropertiesAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/LoadPropertiesAction.java @@ -16,11 +16,6 @@ package org.citrusframework.actions; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -29,6 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + /** * Action reads property files and creates test variables for every property entry. File * resource path can define a resource located on classpath or file system. @@ -55,9 +55,7 @@ public LoadPropertiesAction(Builder builder) { public void doExecute(TestContext context) { Resource resource = FileUtils.getFileResource(filePath, context); - if (logger.isDebugEnabled()) { - logger.debug("Reading property file " + FileUtils.getFileName(resource.getLocation())); - } + logger.debug("Reading property file {}", FileUtils.getFileName(resource.getLocation())); Properties props = FileUtils.loadAsProperties(resource); @@ -65,13 +63,10 @@ public void doExecute(TestContext context) { for (Entry entry : props.entrySet()) { String key = entry.getKey().toString(); - if (logger.isDebugEnabled()) { - logger.debug("Loading property: " + key + "=" + props.getProperty(key) + " into variables"); - } + logger.debug("Loading property: {}={} into variables", key, props.getProperty(key)); if (logger.isDebugEnabled() && context.getVariables().containsKey(key)) { - logger.debug("Overwriting property " + key + " old value:" + context.getVariable(key) - + " new value:" + props.getProperty(key)); + logger.debug("Overwriting property {} old value:{} new value:{}", key, context.getVariable(key), props.getProperty(key)); } try { @@ -83,7 +78,7 @@ public void doExecute(TestContext context) { context.resolveDynamicValuesInMap(unresolved).forEach(context::setVariable); - logger.info("Loaded property file " + FileUtils.getFileName(resource.getLocation())); + logger.info("Loaded property file {}", FileUtils.getFileName(resource.getLocation())); } /** diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/PurgeEndpointAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/PurgeEndpointAction.java index b01217db4f..bb7424e0eb 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/PurgeEndpointAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/PurgeEndpointAction.java @@ -85,9 +85,7 @@ public PurgeEndpointAction(Builder builder) { @Override public void doExecute(TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug("Purging message endpoints ..."); - } + logger.debug("Purging message endpoints ..."); for (Endpoint endpoint : endpoints) { purgeEndpoint(endpoint, context); @@ -108,9 +106,7 @@ public void doExecute(TestContext context) { * @param context */ private void purgeEndpoint(Endpoint endpoint, TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug("Try to purge message endpoint " + endpoint.getName()); - } + logger.debug("Try to purge message endpoint {}", endpoint.getName()); int messagesPurged = 0; Consumer messageConsumer = endpoint.createConsumer(); @@ -124,14 +120,12 @@ private void purgeEndpoint(Endpoint endpoint, TestContext context) { message = (receiveTimeout >= 0) ? messageConsumer.receive(context, receiveTimeout) : messageConsumer.receive(context); } } catch (ActionTimeoutException e) { - if (logger.isDebugEnabled()) { - logger.debug("Stop purging due to timeout - " + e.getMessage()); - } + logger.debug("Stop purging due to timeout - {}", e.getMessage()); break; } if (message != null) { - logger.debug("Removed message from endpoint " + endpoint.getName()); + logger.debug("Removed message from endpoint {}", endpoint.getName()); messagesPurged++; try { @@ -142,9 +136,7 @@ private void purgeEndpoint(Endpoint endpoint, TestContext context) { } } while (message != null); - if (logger.isDebugEnabled()) { - logger.debug("Purged " + messagesPurged + " messages from endpoint"); - } + logger.debug("Purged {} messages from endpoint", messagesPurged); } /** diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java index 5f064dc168..113c285c4a 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveMessageAction.java @@ -16,16 +16,6 @@ package org.citrusframework.actions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -62,10 +52,20 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * This action receives messages from a service destination. Action uses a {@link org.citrusframework.endpoint.Endpoint} * to receive the message, this means that this action is independent of any message transport. - * + *

      * The received message is validated using a {@link MessageValidator} supporting expected * control message payload and header templates. * @@ -184,9 +184,7 @@ private Message receive(TestContext context) { * @return */ private Message receiveSelected(TestContext context, String selectorString) { - if (logger.isDebugEnabled()) { - logger.debug("Setting message selector: '" + selectorString + "'"); - } + logger.debug("Setting message selector: '{}'", selectorString); Endpoint messageEndpoint = getOrCreateEndpoint(context); Consumer consumer = messageEndpoint.createConsumer(); @@ -201,7 +199,7 @@ private Message receiveSelected(TestContext context, String selectorString) { context, messageEndpoint.getEndpointConfiguration().getTimeout()); } } else { - logger.warn(String.format("Unable to receive selective with consumer implementation: '%s'", consumer.getClass())); + logger.warn("Unable to receive selective with consumer implementation: '{}'", consumer.getClass()); return receive(context); } } @@ -213,9 +211,7 @@ private Message receiveSelected(TestContext context, String selectorString) { protected void validateMessage(Message message, TestContext context) { messageProcessors.forEach(processor -> processor.process(message, context)); - if (logger.isDebugEnabled()) { - logger.debug("Received message:\n" + message.print(context)); - } + logger.debug("Received message:\n{}", message.print(context)); // extract variables from received message content for (VariableExtractor variableExtractor : variableExtractors) { @@ -232,9 +228,7 @@ protected void validateMessage(Message message, TestContext context) { if (validationProcessor != null) { validationProcessor.validate(message, context); } else { - if (logger.isDebugEnabled()) { - logger.debug("Control message:\n" + controlMessage.print(context)); - } + logger.debug("Control message:\n{}", controlMessage.print(context)); if (!validators.isEmpty()) { for (MessageValidator messageValidator : validators) { @@ -733,13 +727,13 @@ public HeaderValidationContext getHeaderValidationContext() { /** * Revisit configured validation context list and automatically add context based on message payload and path * expression contexts if any. - * + *

      * This method makes sure that validation contexts are configured. If no validation context has been set yet the method * automatically adds proper validation contexts for Json and XML message payloads. - * + *

      * In case a path expression (JsonPath, XPath) context is set but no proper message validation context (Json, Xml) the * method automatically adds the proper message validation context. - * + *

      * Only when validation contexts are set properly according to the message type and content the message validation * steps will execute later on. */ diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveTimeoutAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveTimeoutAction.java index 3a8da7ef60..6bc8431aee 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveTimeoutAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/ReceiveTimeoutAction.java @@ -16,9 +16,6 @@ package org.citrusframework.actions; -import java.util.HashMap; -import java.util.Map; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.Endpoint; @@ -28,9 +25,12 @@ import org.citrusframework.message.MessageSelectorBuilder; import org.citrusframework.messaging.Consumer; import org.citrusframework.messaging.SelectiveConsumer; +import org.citrusframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.citrusframework.util.StringUtils; + +import java.util.HashMap; +import java.util.Map; /** * Action expecting a timeout on a message destination, this means that no message @@ -85,9 +85,7 @@ public void doExecute(TestContext context) { } if (receivedMessage != null) { - if (logger.isDebugEnabled()) { - logger.debug("Received message:\n" + receivedMessage.print(context)); - } + logger.debug("Received message:\n{}", receivedMessage.print(context)); throw new CitrusRuntimeException("Message timeout validation failed! " + "Received message while waiting for timeout on destination"); diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java index 6283ea0ee7..bf449167d7 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SendMessageAction.java @@ -26,7 +26,6 @@ import org.citrusframework.message.MessageProcessor; import org.citrusframework.message.builder.MessageBuilderSupport; import org.citrusframework.message.builder.SendMessageBuilderSupport; -import org.citrusframework.util.StringUtils; import org.citrusframework.variable.VariableExtractor; import org.citrusframework.variable.dictionary.DataDictionary; import org.slf4j.Logger; @@ -37,6 +36,7 @@ import java.util.concurrent.CompletableFuture; import static java.util.concurrent.Executors.newSingleThreadExecutor; +import static org.citrusframework.util.StringUtils.hasText; /** * This action sends a messages to a specified message endpoint. The action holds a reference to @@ -120,10 +120,8 @@ public void doExecute(final TestContext context) { finished.whenComplete((ctx, ex) -> { if (ex != null) { - if (logger.isWarnEnabled()) { - logger.warn("Failure in forked send action: %s".formatted(ex.getMessage())); - } - } else { + logger.warn("Failure in forked send action", ex); + } else if (logger.isWarnEnabled()) { for (Exception ctxEx : ctx.getExceptions()) { logger.warn(ctxEx.getMessage()); } @@ -137,12 +135,11 @@ public void doExecute(final TestContext context) { final Endpoint messageEndpoint = getOrCreateEndpoint(context); - if (StringUtils.hasText(message.getName())) { + if (hasText(message.getName())) { context.getMessageStore().storeMessage(message.getName(), message); } else { context.getMessageStore() - .storeMessage(context.getMessageStore().constructMessageName(this, messageEndpoint), - message); + .storeMessage(context.getMessageStore().constructMessageName(this, messageEndpoint), message); } if (forkMode) { @@ -178,12 +175,11 @@ public void doExecute(final TestContext context) { * Validate the message against registered schema validators. */ protected void validateMessage(Message message, TestContext context) { - context.getMessageValidatorRegistry().getSchemaValidators().values().stream() - .filter(validator -> validator.canValidate(message, isSchemaValidation())).forEach(validator -> - validator.validate(message, context, this.schemaRepository, this.schema)); + context.getMessageValidatorRegistry().getSchemaValidators().values().stream() + .filter(validator -> validator.canValidate(message, isSchemaValidation())) + .forEach(validator -> validator.validate(message, context, this.schemaRepository, this.schema)); } - /** * {@inheritDoc} */ @@ -236,7 +232,7 @@ protected Message createMessage(TestContext context, String messageType) { public Endpoint getOrCreateEndpoint(TestContext context) { if (endpoint != null) { return endpoint; - } else if (StringUtils.hasText(endpointUri)) { + } else if (hasText(endpointUri)) { return context.getEndpointFactory().create(endpointUri, context); } else { throw new CitrusRuntimeException("Neither endpoint nor endpoint uri is set properly!"); @@ -434,8 +430,7 @@ public final T build() { if (referenceResolver != null) { if (messageBuilderSupport.getDataDictionaryName() != null) { this.messageBuilderSupport.dictionary( - referenceResolver.resolve(messageBuilderSupport.getDataDictionaryName(), - DataDictionary.class)); + referenceResolver.resolve(messageBuilderSupport.getDataDictionaryName(), DataDictionary.class)); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/SleepAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/SleepAction.java index f97c1c6f7e..00bb64555b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/SleepAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/SleepAction.java @@ -16,15 +16,15 @@ package org.citrusframework.actions; -import java.time.Duration; -import java.util.concurrent.TimeUnit; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.Duration; +import java.util.concurrent.TimeUnit; + /** * Stop the test execution for a given amount of time. * @@ -55,22 +55,23 @@ public void doExecute(TestContext context) { String duration = context.resolveDynamicValue(time); try { - Duration ms; + Duration parsedDuration; if (duration.indexOf(".") > 0) { - ms = switch (timeUnit) { + parsedDuration = switch (timeUnit) { case MILLISECONDS -> Duration.ofMillis(Math.round(Double.parseDouble(duration))); - case SECONDS -> Duration.ofMillis(Math.round(Double.parseDouble(duration) * 1000)); - case MINUTES -> Duration.ofMillis(Math.round(Double.parseDouble(duration) * 60 * 1000)); - default -> throw new CitrusRuntimeException("Unsupported time expression for sleep action - " + - "please use one of milliseconds, seconds, minutes"); + case SECONDS -> Duration.ofSeconds(Math.round(Double.parseDouble(duration))); + case MINUTES -> Duration.ofMinutes(Math.round(Double.parseDouble(duration))); + default -> throw new CitrusRuntimeException("Unsupported time expression for sleep action - please use one of milliseconds, seconds, minutes"); }; } else { - ms = Duration.ofMillis(TimeUnit.MILLISECONDS.convert(Long.parseLong(duration), timeUnit)); + parsedDuration = Duration.ofMillis(TimeUnit.MILLISECONDS.convert(Long.parseLong(duration), timeUnit)); } - logger.info(String.format("Sleeping %s ms", ms.toMillis())); - TimeUnit.MILLISECONDS.sleep(ms.toMillis()); - logger.info(String.format("Returning after %s ms", ms.toMillis())); + logger.info("Sleeping {} {}", duration, timeUnit); + + TimeUnit.MILLISECONDS.sleep(parsedDuration.toMillis()); + + logger.info("Returning after {} {}", duration, timeUnit); } catch (InterruptedException e) { throw new CitrusRuntimeException(e); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/StartServerAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/StartServerAction.java index 98bfb7ae9f..a1c40cd3dc 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/StartServerAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/StartServerAction.java @@ -16,11 +16,6 @@ package org.citrusframework.actions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.server.Server; @@ -29,6 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + /** * Action starting a {@link Server} instance. * @@ -54,7 +54,7 @@ public StartServerAction(Builder builder) { public void doExecute(TestContext context) { for (Server server : servers) { server.start(); - logger.info("Started server: " + server.getName()); + logger.info("Started server: {}", server.getName()); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/StopServerAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/StopServerAction.java index 12cf143651..5e2b439db2 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/StopServerAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/StopServerAction.java @@ -16,11 +16,6 @@ package org.citrusframework.actions; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Stream; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.citrusframework.server.Server; @@ -29,6 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + /** * Action stopping {@link Server} instances. * @@ -54,7 +54,7 @@ public StopServerAction(Builder builder) { public void doExecute(TestContext context) { for (Server server : servers) { server.stop(); - logger.info("Stopped server: " + server.getName()); + logger.info("Stopped server: {}", server.getName()); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimeAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimeAction.java index 0436a1bee1..b82d9f6a52 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimeAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimeAction.java @@ -61,12 +61,12 @@ public void doExecute(TestContext context) { context.setVariable(timeLineId + timeLineSuffix, time); if (description != null) { - logger.info("TimeWatcher " + timeLineId + " after " + time + " ms (" + description + ")"); + logger.info("TimeWatcher {} after {} ms ({})", timeLineId, time, description); } else { - logger.info("TimeWatcher " + timeLineId + " after " + time + " ms"); + logger.info("TimeWatcher {} after {} ms", timeLineId, time); } } else { - logger.info("Starting TimeWatcher: " + timeLineId); + logger.info("Starting TimeWatcher: {}", timeLineId); context.setVariable(timeLineId, System.currentTimeMillis()); context.setVariable(timeLineId + timeLineSuffix, 0L); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimerAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimerAction.java index 9c2e2a8b79..142324e29a 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimerAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/StopTimerAction.java @@ -47,7 +47,7 @@ public String getTimerId() { public void doExecute(TestContext context) { if (timerId != null) { boolean success = context.stopTimer(timerId); - logger.info(String.format("Stopping timer %s - stop successful: %s", timerId, success)); + logger.info("Stopping timer {} - stop successful: {}", timerId, success); } else { context.stopTimers(); logger.info("Stopping all timers"); diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/TraceVariablesAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/TraceVariablesAction.java index d387beb395..d3d24b9d1a 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/TraceVariablesAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/TraceVariablesAction.java @@ -16,16 +16,16 @@ package org.citrusframework.actions; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.stream.Stream; - import org.citrusframework.AbstractTestActionBuilder; import org.citrusframework.context.TestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + /** * Action that prints variable values to the console/logger. Action requires a list of variable * names. Tries to find the variables in the test context and print its values. @@ -53,7 +53,7 @@ public void doExecute(TestContext context) { logger.info("Trace variables"); Iterator it; - if (variableNames != null && variableNames.size() > 0) { + if (variableNames != null && !variableNames.isEmpty()) { it = variableNames.iterator(); } else { it = context.getVariables().keySet().iterator(); @@ -63,7 +63,7 @@ public void doExecute(TestContext context) { String key = it.next(); String value = context.getVariable(key); - logger.info("Variable " + context.getLogModifier().mask(key + " = " + value)); + logger.info("Variable {}", context.getLogModifier().mask(key + " = " + value)); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/actions/TransformAction.java b/core/citrus-base/src/main/java/org/citrusframework/actions/TransformAction.java index d32c8773d5..d9e5293399 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/actions/TransformAction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/actions/TransformAction.java @@ -85,9 +85,7 @@ public TransformAction(Builder builder) { @Override public void doExecute(TestContext context) { try { - if (logger.isDebugEnabled()) { - logger.debug("Starting XSLT transformation"); - } + logger.debug("Starting XSLT transformation"); //parse XML document and define XML source for transformation Source xmlSource; diff --git a/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java b/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java index 88fa8578b2..e6af3437ba 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java +++ b/core/citrus-base/src/main/java/org/citrusframework/annotations/CitrusAnnotations.java @@ -16,10 +16,6 @@ package org.citrusframework.annotations; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.util.Arrays; - import org.citrusframework.Citrus; import org.citrusframework.CitrusContext; import org.citrusframework.GherkinTestActionRunner; @@ -34,6 +30,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; +import java.util.Arrays; + /** * Dependency injection support for {@link CitrusFramework}, {@link CitrusResource} and {@link CitrusEndpoint} annotations. * @@ -105,7 +105,7 @@ public static void injectCitrusFramework(final Object testCase, final Citrus cit return; } - logger.trace(String.format("Injecting Citrus framework instance on test class field '%s'", field.getName())); + logger.trace("Injecting Citrus framework instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, testCase, citrusFramework); }); } @@ -121,7 +121,7 @@ public static void injectCitrusContext(final Object target, final CitrusContext return; } - logger.trace(String.format("Injecting Citrus context instance on test class field '%s'", field.getName())); + logger.trace("Injecting Citrus context instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, target, context); }); } @@ -139,7 +139,7 @@ public static void injectTestContext(final Object target, final TestContext cont Class type = field.getType(); if (TestContext.class.isAssignableFrom(type)) { - logger.trace(String.format("Injecting test context instance on test class field '%s'", field.getName())); + logger.trace("Injecting test context instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, target, context); } else { throw new CitrusRuntimeException("Not able to provide a Citrus resource injection for type " + type); @@ -160,7 +160,7 @@ public static void injectTestRunner(final Object target, final TestCaseRunner ru Class type = field.getType(); if (TestCaseRunner.class.isAssignableFrom(type)) { - logger.trace(String.format("Injecting test runner instance on test class field '%s'", field.getName())); + logger.trace("Injecting test runner instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, target, runner); } else { throw new CitrusRuntimeException("Not able to provide a Citrus resource injection for type " + type); @@ -184,7 +184,7 @@ private static void injectTestActionRunner(final Object target, final TestAction Class type = field.getType(); if (TestActionRunner.class.isAssignableFrom(type)) { - logger.trace(String.format("Injecting test action runner instance on test class field '%s'", field.getName())); + logger.trace("Injecting test action runner instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, target, runner); } else { throw new CitrusRuntimeException("Not able to provide a Citrus resource injection for type " + type); @@ -205,7 +205,7 @@ private static void injectGherkinTestActionRunner(final Object target, final Ghe Class type = field.getType(); if (GherkinTestActionRunner.class.isAssignableFrom(type)) { - logger.trace(String.format("Injecting test action runner instance on test class field '%s'", field.getName())); + logger.trace("Injecting test action runner instance on test class field '{}'", field.getName()); ReflectionHelper.setField(field, target, runner); } else { throw new CitrusRuntimeException("Not able to provide a Citrus resource injection for type " + type); diff --git a/core/citrus-base/src/main/java/org/citrusframework/condition/ActionCondition.java b/core/citrus-base/src/main/java/org/citrusframework/condition/ActionCondition.java index fee180ff40..6f7ceff1e5 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/condition/ActionCondition.java +++ b/core/citrus-base/src/main/java/org/citrusframework/condition/ActionCondition.java @@ -16,13 +16,13 @@ package org.citrusframework.condition; -import java.util.Optional; - import org.citrusframework.TestAction; import org.citrusframework.context.TestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; + /** * @since 2.7.6 */ @@ -62,9 +62,10 @@ public boolean isSatisfied(TestContext context) { action.execute(context); } catch (Exception e) { this.caughtException = e; - logger.warn(String.format("Nested action did not perform as expected - %s", Optional.ofNullable(e.getMessage()) - .map(msg -> e.getClass().getName() + ": " + msg) - .orElseGet(() -> e.getClass().getName()))); + logger.warn("Nested action did not perform as expected - {}", + Optional.ofNullable(e.getMessage()) + .map(msg -> e.getClass().getName() + ": " + msg) + .orElseGet(() -> e.getClass().getName())); return false; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/condition/FileCondition.java b/core/citrus-base/src/main/java/org/citrusframework/condition/FileCondition.java index ac2c844f11..65951b8549 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/condition/FileCondition.java +++ b/core/citrus-base/src/main/java/org/citrusframework/condition/FileCondition.java @@ -16,13 +16,13 @@ package org.citrusframework.condition; -import java.io.File; - import org.citrusframework.context.TestContext; import org.citrusframework.util.FileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; + /** * Tests for the presence of a file and returns true if the file exists * @@ -46,9 +46,7 @@ public FileCondition() { @Override public boolean isSatisfied(TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Checking file path '%s'", file != null ? file.getPath() : filePath)); - } + logger.debug("Checking file path '{}'", file != null ? file.getPath() : filePath); if (file != null) { return file.exists() && file.isFile(); @@ -56,7 +54,7 @@ public boolean isSatisfied(TestContext context) { try { return FileUtils.getFileResource(context.replaceDynamicContentInString(filePath), context).getFile().isFile(); } catch (Exception e) { - logger.warn(String.format("Failed to access file resource '%s'", e.getMessage())); + logger.warn("Failed to access file resource '{}'", e.getMessage()); return false; } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/condition/HttpCondition.java b/core/citrus-base/src/main/java/org/citrusframework/condition/HttpCondition.java index 95be6db182..a252af571b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/condition/HttpCondition.java +++ b/core/citrus-base/src/main/java/org/citrusframework/condition/HttpCondition.java @@ -16,16 +16,16 @@ package org.citrusframework.condition; -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; + /** * Tests if a HTTP Endpoint is reachable. The test is successful if the endpoint responds with the expected response * code. By default a HTTP 200 response code is expected. @@ -76,9 +76,7 @@ public String getErrorMessage(TestContext context) { */ private int invokeUrl(TestContext context) { URL contextUrl = getUrl(context); - if (logger.isDebugEnabled()) { - logger.debug(String.format("Probing Http request url '%s'", contextUrl.toExternalForm())); - } + logger.debug("Probing Http request url '{}'", contextUrl.toExternalForm()); int responseCode = -1; @@ -90,7 +88,7 @@ private int invokeUrl(TestContext context) { responseCode = httpURLConnection.getResponseCode(); } catch (IOException e) { - logger.warn(String.format("Could not access Http url '%s' - %s", contextUrl.toExternalForm(), e.getMessage())); + logger.warn("Could not access Http url '{}' - {}", contextUrl.toExternalForm(), e.getMessage()); } finally { if (httpURLConnection != null) { httpURLConnection.disconnect(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/condition/MessageCondition.java b/core/citrus-base/src/main/java/org/citrusframework/condition/MessageCondition.java index 986762dee5..f9e0d1e228 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/condition/MessageCondition.java +++ b/core/citrus-base/src/main/java/org/citrusframework/condition/MessageCondition.java @@ -22,7 +22,7 @@ * Condition checks whether a message is present in test context message store. Messages are automatically * stored in that store when sending and receiving messages with respective test actions. So this condition * can be used to wait for a message to arrive or being sent out. - * + *

      * Message to check is identified by its name in the message store. * * @since 2.6.2 diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractActionContainer.java b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractActionContainer.java index 860e7a71a0..61c049c863 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractActionContainer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractActionContainer.java @@ -16,13 +16,6 @@ package org.citrusframework.container; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import org.citrusframework.AbstractTestContainerBuilder; import org.citrusframework.Completable; import org.citrusframework.TestAction; @@ -32,6 +25,13 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * Abstract base class for all containers holding several embedded test actions. * @@ -106,10 +106,8 @@ public boolean isDone(TestContext context) { for (TestAction action : new ArrayList<>(executedActions)) { if (action instanceof Completable && !((Completable) action).isDone(context)) { - if (logger.isDebugEnabled()) { - logger.debug(Optional.ofNullable(action.getName()).filter(name -> !name.trim().isEmpty()) - .orElseGet(() -> action.getClass().getName()) + " not completed yet"); - } + logger.debug("{} not completed yet", Optional.ofNullable(action.getName()).filter(name -> !name.trim().isEmpty()) + .orElseGet(() -> action.getClass().getName())); return false; } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractSuiteActionContainer.java b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractSuiteActionContainer.java index a9478bcb7f..cd04735330 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractSuiteActionContainer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractSuiteActionContainer.java @@ -16,11 +16,6 @@ package org.citrusframework.container; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.citrusframework.AbstractTestContainerBuilder; import org.citrusframework.TestActionBuilder; import org.citrusframework.spi.ReferenceResolver; @@ -29,6 +24,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Abstract suit container actions executed before and after test suite run. Container decides * weather to execute according to given suite name and included test groups if any. @@ -65,29 +65,30 @@ public AbstractSuiteActionContainer(String name, AbstractTestContainerBuilder envEntry : env.entrySet()) { - if (!System.getenv().containsKey(envEntry.getKey()) || - (StringUtils.hasText(envEntry.getValue()) && !System.getenv().get(envEntry.getKey()).equals(envEntry.getValue()))) { - logger.warn(String.format(baseErrorMessage, "env properties", getName())); + if (!System.getenv().containsKey(envEntry.getKey()) + || (StringUtils.hasText(envEntry.getValue()) && !System.getenv().get(envEntry.getKey()).equals(envEntry.getValue()))) { + logger.warn("{} env properties {}", baseErrorMessage, getName()); return false; } } for (Map.Entry systemProperty : systemProperties.entrySet()) { - if (!System.getProperties().containsKey(systemProperty.getKey()) || - (StringUtils.hasText(systemProperty.getValue()) && !System.getProperties().get(systemProperty.getKey()).equals(systemProperty.getValue()))) { - logger.warn(String.format(baseErrorMessage, "system properties", getName())); + if (!System.getProperties().containsKey(systemProperty.getKey()) + || (StringUtils.hasText(systemProperty.getValue()) && !System.getProperties().get(systemProperty.getKey()).equals(systemProperty.getValue()))) { + logger.warn("{} system properties {}", baseErrorMessage, getName()); return false; } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractTestBoundaryActionContainer.java b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractTestBoundaryActionContainer.java index e20579d0a9..48e674e582 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/AbstractTestBoundaryActionContainer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/AbstractTestBoundaryActionContainer.java @@ -16,12 +16,6 @@ package org.citrusframework.container; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Pattern; - import org.citrusframework.AbstractTestContainerBuilder; import org.citrusframework.TestActionBuilder; import org.citrusframework.spi.ReferenceResolver; @@ -30,6 +24,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + /** * Abstract test action container describes methods to enable/disable container execution based on given test name, package * and test groups. This action container is typically used by before and after test action containers. @@ -72,27 +72,27 @@ public boolean shouldExecute(String testName, String packageName, String[] inclu if (StringUtils.hasText(packageNamePattern)) { if (!Pattern.compile(packageNamePattern).matcher(packageName).matches()) { - logger.warn(String.format(baseErrorMessage, "test package", getName())); + logger.warn("{} test package {}", baseErrorMessage, getName()); return false; } } if (StringUtils.hasText(namePattern)) { if (!Pattern.compile(sanitizePatten(namePattern)).matcher(testName).matches()) { - logger.warn(String.format(baseErrorMessage, "test name", getName())); + logger.warn("{} test name {}", baseErrorMessage, getName()); return false; } } if (!checkTestGroups(includedGroups)) { - logger.warn(String.format(baseErrorMessage, "test groups", getName())); + logger.warn("{} test groups {}", baseErrorMessage, getName()); return false; } for (Map.Entry envEntry : env.entrySet()) { if (!System.getenv().containsKey(envEntry.getKey()) || (StringUtils.hasText(envEntry.getValue()) && !System.getenv().get(envEntry.getKey()).equals(envEntry.getValue()))) { - logger.warn(String.format(baseErrorMessage, "env properties", getName())); + logger.warn("{} env properties {}", baseErrorMessage, getName()); return false; } } @@ -100,7 +100,7 @@ public boolean shouldExecute(String testName, String packageName, String[] inclu for (Map.Entry systemProperty : systemProperties.entrySet()) { if (!System.getProperties().containsKey(systemProperty.getKey()) || (StringUtils.hasText(systemProperty.getValue()) && !System.getProperties().get(systemProperty.getKey()).equals(systemProperty.getValue()))) { - logger.warn(String.format(baseErrorMessage, "system properties", getName())); + logger.warn("{} system properties {}", baseErrorMessage, getName()); return false; } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Assert.java b/core/citrus-base/src/main/java/org/citrusframework/container/Assert.java index 13e93aee68..a4b805ba9f 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Assert.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Assert.java @@ -72,9 +72,7 @@ public Assert(Builder builder) { @Override public void doExecute(TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug("Assert container asserting exceptions of type {}", exception.getSimpleName()); - } + logger.debug("Assert container asserting exceptions of type {}", exception.getSimpleName()); try { executeAction(this.action.build(), context); diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Catch.java b/core/citrus-base/src/main/java/org/citrusframework/container/Catch.java index 2730af0cee..30b7392f61 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Catch.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Catch.java @@ -45,16 +45,14 @@ public Catch(Builder builder) { @Override public void doExecute(TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug("Catch container catching exceptions of type " + exception); - } + logger.debug("Catch container catching exceptions of type {}", exception); for (TestActionBuilder actionBuilder: actions) { try { executeAction(actionBuilder.build(), context); } catch (Exception e) { if (exception != null && exception.equals(e.getClass().getName())) { - logger.info("Caught exception " + e.getClass() + ": " + e.getLocalizedMessage()); + logger.info("Caught exception {}: {}", e.getClass(), e.getLocalizedMessage()); continue; } throw new CitrusRuntimeException(e); diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Iterate.java b/core/citrus-base/src/main/java/org/citrusframework/container/Iterate.java index f70505ce47..c71d452244 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Iterate.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Iterate.java @@ -22,7 +22,7 @@ /** * Class executes nested test actions in loops. Iteration continues as long * as looping condition evaluates to true. - * + *

      * Each loop an index variable is incremented. The index variable is accessible inside the nested * test actions as normal test variable. Iteration starts with index=1 and increments with a * default step=1. diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/RepeatOnErrorUntilTrue.java b/core/citrus-base/src/main/java/org/citrusframework/container/RepeatOnErrorUntilTrue.java index dea167e97f..f9cb7cf22f 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/RepeatOnErrorUntilTrue.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/RepeatOnErrorUntilTrue.java @@ -16,11 +16,8 @@ package org.citrusframework.container; -import jakarta.annotation.Nullable; -import org.apache.commons.lang3.time.StopWatch; import org.citrusframework.AbstractIteratingContainerBuilder; import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.ActionTimeoutException; import org.citrusframework.exceptions.CitrusRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/RepeatUntilTrue.java b/core/citrus-base/src/main/java/org/citrusframework/container/RepeatUntilTrue.java index b28f7187d3..8ba4089a87 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/RepeatUntilTrue.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/RepeatUntilTrue.java @@ -22,7 +22,7 @@ /** * Typical implementation of repeat iteration loop. Nested test actions are executed until * aborting condition evaluates to true. - * + *

      * Index is incremented each iteration and stored as test variable accessible in the nested test actions * as normal variable. Index starts with 1 by default. * diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterSuite.java b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterSuite.java index 9a03c1dc63..8352608a37 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterSuite.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterSuite.java @@ -50,7 +50,7 @@ public void doExecute(TestContext context) { logger.info("Entering after suite block"); if (logger.isDebugEnabled()) { - logger.debug("Executing " + actions.size() + " actions after suite"); + logger.debug("Executing {} actions after suite", actions.size()); logger.debug(""); } @@ -60,7 +60,7 @@ public void doExecute(TestContext context) { /* Executing test action and validate its success */ action.execute(context); } catch (Exception e) { - logger.error("After suite action failed " + action.getName() + "Nested exception is: ", e); + logger.error("After suite action failed {}Nested exception is: ", action.getName(), e); logger.error("Continue after suite actions"); success = false; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterTest.java b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterTest.java index 2307d3a8a9..d5fc5ff458 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterTest.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceAfterTest.java @@ -51,7 +51,7 @@ public void doExecute(TestContext context) { logger.info("Entering after test block"); if (logger.isDebugEnabled()) { - logger.debug("Executing " + actions.size() + " actions after test"); + logger.debug("Executing {} actions after test", actions.size()); logger.debug(""); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeSuite.java b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeSuite.java index 00218d41fb..b63d320a48 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeSuite.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeSuite.java @@ -48,7 +48,7 @@ public void doExecute(TestContext context) { logger.info("Entering before suite block"); if (logger.isDebugEnabled()) { - logger.debug("Executing " + actions.size() + " actions before suite"); + logger.debug("Executing {} actions before suite", actions.size()); logger.debug(""); } @@ -58,7 +58,7 @@ public void doExecute(TestContext context) { /* Executing test action and validate its success */ action.execute(context); } catch (Exception e) { - logger.error("Task failed " + action.getName() + "Nested exception is: ", e); + logger.error("Task failed {}Nested exception is: ", action.getName(), e); throw new CitrusRuntimeException(e); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeTest.java b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeTest.java index c675859ce7..7bba10edb6 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeTest.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/SequenceBeforeTest.java @@ -51,7 +51,7 @@ public void doExecute(TestContext context) { logger.info("Entering before test block"); if (logger.isDebugEnabled()) { - logger.debug("Executing " + actions.size() + " actions before test"); + logger.debug("Executing {} actions before test", actions.size()); logger.debug(""); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Template.java b/core/citrus-base/src/main/java/org/citrusframework/container/Template.java index 72738ed515..20aef139da 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Template.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Template.java @@ -44,12 +44,12 @@ /** * This class represents a previously defined block of test actions. Test cases can call * templates and reuse their functionality. - * + *

      * Templates operate on test variables. While calling, the template caller can set these * variables as parameters. - * + *

      * Nested test actions are executed in sequence. - * + *

      * The template execution may affect existing variable values in the calling test case. So * variables may have different values in the test case after template execution. Therefore, * users can create a local test context by setting globalContext to false. Templates then will diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/TemplateLoader.java b/core/citrus-base/src/main/java/org/citrusframework/container/TemplateLoader.java index 0f0dc251e3..3add3c2a57 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/TemplateLoader.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/TemplateLoader.java @@ -16,10 +16,6 @@ package org.citrusframework.container; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.functions.Function; import org.citrusframework.spi.ReferenceResolverAware; @@ -28,10 +24,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + public interface TemplateLoader extends ReferenceResolverAware { /** Logger */ - Logger logger = LoggerFactory.getLogger(Function.class); + Logger logger = LoggerFactory.getLogger(TemplateLoader.class); /** Function resource lookup path */ String RESOURCE_PATH = "META-INF/citrus/template/loader"; @@ -53,7 +53,7 @@ static Optional lookup(String name) { TemplateLoader instance = TYPE_RESOLVER.resolve(name); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve template loader from resource '%s/%s'", RESOURCE_PATH, name)); + logger.warn("Failed to resolve template loader from resource '{}/{}'", RESOURCE_PATH, name); } return Optional.empty(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Timer.java b/core/citrus-base/src/main/java/org/citrusframework/container/Timer.java index 7cd9dfe843..3e47bed468 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Timer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Timer.java @@ -89,13 +89,13 @@ public void run() { try { indexCount++; updateIndexCountInTestContext(context); - logger.debug(String.format("Timer event fired #%s - executing nested actions", indexCount)); + logger.debug("Timer event fired #{} - executing nested actions", indexCount); for (TestActionBuilder actionBuilder : actions) { executeAction(actionBuilder.build(), context); } if (indexCount >= repeatCount) { - logger.debug(String.format("Timer complete: %s iterations reached", repeatCount)); + logger.debug("Timer complete: {} iterations reached", repeatCount); stopTimer(); } } catch (Exception e) { @@ -113,7 +113,7 @@ private void handleException(Exception e) { } else { timerException = new CitrusRuntimeException(e); } - logger.error(String.format("Timer stopped as a result of nested action error (%s)", e.getMessage())); + logger.error("Timer stopped as a result of nested action error ({})", e.getMessage()); stopTimer(); if (fork) { diff --git a/core/citrus-base/src/main/java/org/citrusframework/container/Wait.java b/core/citrus-base/src/main/java/org/citrusframework/container/Wait.java index b02056d8f9..c4b17baa0e 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/container/Wait.java +++ b/core/citrus-base/src/main/java/org/citrusframework/container/Wait.java @@ -83,9 +83,7 @@ public void doExecute(final TestContext context) { while (timeLeft > 0) { timeLeft -= intervalMs; - if (logger.isDebugEnabled()) { - logger.debug(String.format("Waiting for condition %s", condition.getName())); - } + logger.debug("Waiting for condition {}", condition.getName()); var executor = newSingleThreadExecutor(); long checkStartTime = System.currentTimeMillis(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/AbstractEndpointComponent.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/AbstractEndpointComponent.java index 29c4f398d1..477abd9a54 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/AbstractEndpointComponent.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/AbstractEndpointComponent.java @@ -16,6 +16,13 @@ package org.citrusframework.endpoint; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.ReferenceResolverAware; +import org.citrusframework.util.ReflectionHelper; +import org.citrusframework.util.StringUtils; +import org.citrusframework.util.TypeConversionUtils; + import java.lang.reflect.Field; import java.lang.reflect.Method; import java.net.URI; @@ -28,17 +35,10 @@ import java.util.Map; import java.util.StringTokenizer; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.ReferenceResolverAware; -import org.citrusframework.util.ReflectionHelper; -import org.citrusframework.util.StringUtils; -import org.citrusframework.util.TypeConversionUtils; - /** * Default endpoint component reads component name from endpoint uri and parses parameters from uri using * the HTTP uri pattern. - * + *

      * http://localhost:8080?param1=value1¶m2=value2¶m3=value3 * jms:queue.name?connectionFactory=specialConnectionFactory * soap:localhost:8080?soapAction=sayHello @@ -187,16 +187,13 @@ protected String getParameterString(Map parameters, Field field = ReflectionHelper.findField(endpointConfigurationType, parameterEntry.getKey()); if (field == null) { - if (paramString.length() == 0) { + if (paramString.isEmpty()) { paramString.append("?").append(parameterEntry.getKey()); - if (parameterEntry.getValue() != null) { - paramString.append("=").append(parameterEntry.getValue()); - } } else { paramString.append("&").append(parameterEntry.getKey()); - if (parameterEntry.getValue() != null) { - paramString.append("=").append(parameterEntry.getValue()); - } + } + if (parameterEntry.getValue() != null) { + paramString.append("=").append(parameterEntry.getValue()); } } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectConsumer.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectConsumer.java index 0f6ccd4468..78237afb6b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectConsumer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectConsumer.java @@ -24,9 +24,9 @@ import org.citrusframework.message.MessageSelector; import org.citrusframework.message.selector.DelegatingMessageSelector; import org.citrusframework.messaging.AbstractSelectiveMessageConsumer; +import org.citrusframework.util.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.citrusframework.util.StringUtils; public class DirectConsumer extends AbstractSelectiveMessageConsumer { @@ -57,9 +57,7 @@ public Message receive(String selector, TestContext context, long timeout) { destinationQueueName = getDestinationQueueName(); } - if (logger.isDebugEnabled()) { - logger.debug(String.format("Receiving message from queue: '%s'", destinationQueueName)); - } + logger.debug("Receiving message from queue: '{}'", destinationQueueName); Message message; if (StringUtils.hasText(selector)) { @@ -82,7 +80,7 @@ public Message receive(String selector, TestContext context, long timeout) { throw new MessageTimeoutException(timeout, destinationQueueName); } - logger.info(String.format("Received message from queue: '%s'", destinationQueueName)); + logger.info("Received message from queue: '{}'", destinationQueueName); return message; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncConsumer.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncConsumer.java index 5b25d7597a..26308b3850 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncConsumer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncConsumer.java @@ -67,12 +67,12 @@ public void send(Message message, TestContext context) { ObjectHelper.assertNotNull(replyQueue, "Failed to find reply channel for message correlation key: " + correlationKey); if (logger.isDebugEnabled()) { - logger.debug("Sending message to reply channel: '" + replyQueue + "'"); - logger.debug("Message to send is:\n" + message.toString()); + logger.debug("Sending message to reply channel: '{}'", replyQueue); + logger.debug("Message to send is:\n{}", message); } replyQueue.send(message); - logger.info("Message was sent to reply channel: '" + replyQueue + "'"); + logger.info("Message was sent to reply channel: '{}'", replyQueue); } /** @@ -94,8 +94,7 @@ public void saveReplyMessageQueue(Message receivedMessage, TestContext context) correlationManager.saveCorrelationKey(correlationKeyName, correlationKey, context); correlationManager.store(correlationKey, replyQueue); } else { - logger.warn("Unable to retrieve reply message channel for message \n" + - receivedMessage + "\n - no reply channel found in message headers!"); + logger.warn("Unable to retrieve reply message channel for message \n{}\n - no reply channel found in message headers!", receivedMessage); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncProducer.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncProducer.java index c5788fdb67..9dad1395e7 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncProducer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/direct/DirectSyncProducer.java @@ -16,8 +16,6 @@ package org.citrusframework.endpoint.direct; -import java.util.UUID; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.MessageTimeoutException; import org.citrusframework.exceptions.ReplyMessageTimeoutException; @@ -30,6 +28,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.UUID; + public class DirectSyncProducer extends DirectProducer implements ReplyConsumer { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(DirectSyncProducer.class); @@ -62,11 +62,11 @@ public void send(Message message, TestContext context) { String destinationQueueName = getDestinationQueueName(); if (logger.isDebugEnabled()) { - logger.debug("Sending message to queue: '" + destinationQueueName + "'"); - logger.debug("Message to send is:\n" + message.toString()); + logger.debug("Sending message to queue: '{}'", destinationQueueName); + logger.debug("Message to send is:\n{}", message.toString()); } - logger.info("Message was sent to queue: '" + destinationQueueName + "'"); + logger.info("Message was sent to queue: '{}'", destinationQueueName); MessageQueue replyQueue = getReplyQueue(message, context); getDestinationQueue(context).send(message); @@ -89,7 +89,7 @@ public void send(Message message, TestContext context) { */ private MessageQueue getReplyQueue(Message message, TestContext context) { if (message.getHeader(DirectMessageHeaders.REPLY_QUEUE) == null) { - MessageQueue temporaryQueue = new DefaultMessageQueue(getName() + "." + UUID.randomUUID().toString()); + MessageQueue temporaryQueue = new DefaultMessageQueue(getName() + "." + UUID.randomUUID()); message.setHeader(DirectMessageHeaders.REPLY_QUEUE, temporaryQueue); return temporaryQueue; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/endpoint/resolver/DynamicEndpointUriResolver.java b/core/citrus-base/src/main/java/org/citrusframework/endpoint/resolver/DynamicEndpointUriResolver.java index 6d2cb8d20c..0b1305590f 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/endpoint/resolver/DynamicEndpointUriResolver.java +++ b/core/citrus-base/src/main/java/org/citrusframework/endpoint/resolver/DynamicEndpointUriResolver.java @@ -16,13 +16,13 @@ package org.citrusframework.endpoint.resolver; -import java.util.Map; -import java.util.StringTokenizer; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.Message; import org.citrusframework.util.StringUtils; +import java.util.Map; +import java.util.StringTokenizer; + /** * Endpoint uri resolver working on message headers. Resolver is searching for a specific header entry which holds the actual * target endpoint uri. @@ -78,7 +78,7 @@ private String appendRequestPath(String uri, Map headers) { requestUri = requestUri.substring(0, requestUri.length() - 1); } - while (path.startsWith("/") && path.length() > 0) { + while (path.startsWith("/") && !path.isEmpty()) { path = path.length() == 1 ? "" : path.substring(1); } @@ -114,7 +114,7 @@ private String appendQueryParams(String uri, Map headers) { queryParamBuilder.append("&").append(tok.nextToken()); } - return requestUri + queryParamBuilder.toString(); + return requestUri + queryParamBuilder; } /** diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java index 8b30bfd3b9..4d3b211e9c 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/DefaultFunctionLibrary.java @@ -17,6 +17,7 @@ package org.citrusframework.functions; import org.citrusframework.functions.core.AbsoluteFunction; +import org.citrusframework.functions.core.AdvancedRandomNumberFunction; import org.citrusframework.functions.core.AvgFunction; import org.citrusframework.functions.core.CeilingFunction; import org.citrusframework.functions.core.ChangeDateFunction; @@ -32,7 +33,6 @@ import org.citrusframework.functions.core.LowerCaseFunction; import org.citrusframework.functions.core.MaxFunction; import org.citrusframework.functions.core.MinFunction; -import org.citrusframework.functions.core.AdvancedRandomNumberFunction; import org.citrusframework.functions.core.RandomEnumValueFunction; import org.citrusframework.functions.core.RandomNumberFunction; import org.citrusframework.functions.core.RandomPatternFunction; @@ -47,10 +47,10 @@ import org.citrusframework.functions.core.SumFunction; import org.citrusframework.functions.core.SystemPropertyFunction; import org.citrusframework.functions.core.TranslateFunction; +import org.citrusframework.functions.core.UnixTimestampFunction; import org.citrusframework.functions.core.UpperCaseFunction; import org.citrusframework.functions.core.UrlDecodeFunction; import org.citrusframework.functions.core.UrlEncodeFunction; -import org.citrusframework.functions.core.UnixTimestampFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -110,9 +110,7 @@ public DefaultFunctionLibrary() { private void lookupFunctions() { Function.lookup().forEach((k, m) -> { getMembers().put(k, m); - if (logger.isDebugEnabled()) { - logger.debug(String.format("Register function '%s' as %s", k, m.getClass())); - } + logger.debug("Register function '{}' as {}", k, m.getClass()); }); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java index 6cde8506c4..ccda1b982c 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/AdvancedRandomNumberFunction.java @@ -16,16 +16,17 @@ package org.citrusframework.functions.core; -import static java.lang.String.format; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.exceptions.InvalidFunctionUsageException; +import org.citrusframework.functions.Function; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.exceptions.InvalidFunctionUsageException; -import org.citrusframework.functions.Function; + +import static java.lang.String.format; /** * A function for generating random double values with specified decimal places and range. This @@ -64,20 +65,15 @@ public String execute(List parameterList, TestContext context) { "Decimal places must be a non-negative integer value."); } - BigDecimal minValue = getParameter(parameterList, 1, BigDecimal.class, BigDecimal::new, - DEFAULT_MIN_VALUE); - BigDecimal maxValue = getParameter(parameterList, 2, BigDecimal.class, BigDecimal::new, - DEFAULT_MAX_VALUE); + BigDecimal minValue = getParameter(parameterList, 1, BigDecimal.class, BigDecimal::new, DEFAULT_MIN_VALUE); + BigDecimal maxValue = getParameter(parameterList, 2, BigDecimal.class, BigDecimal::new, DEFAULT_MAX_VALUE); if (minValue.compareTo(maxValue) > 0) { throw new InvalidFunctionUsageException("Min value must be less than max value."); } - boolean excludeMin = getParameter(parameterList, 3, Boolean.class, Boolean::parseBoolean, - false); - boolean excludeMax = getParameter(parameterList, 4, Boolean.class, Boolean::parseBoolean, - false); - BigDecimal multiple = getParameter(parameterList, 5, BigDecimal.class, BigDecimal::new, - null); + boolean excludeMin = getParameter(parameterList, 3, Boolean.class, Boolean::parseBoolean, false); + boolean excludeMax = getParameter(parameterList, 4, Boolean.class, Boolean::parseBoolean, false); + BigDecimal multiple = getParameter(parameterList, 5, BigDecimal.class, BigDecimal::new, null); return getRandomNumber(decimalPlaces, minValue, maxValue, excludeMin, excludeMax, multiple); } @@ -96,27 +92,27 @@ private T parseParameter(int index, String text, Class type, java.util.function.Function parseFunction) { T value; try { - value = parseFunction.apply(text); if (value == null) { throw new CitrusRuntimeException( - "Text '%s' could not be parsed to '%s'. Resulting value is null".formatted(text, - type.getSimpleName())); + "Text '%s' could not be parsed to '%s'. Resulting value is null".formatted(text, type.getSimpleName())); } return value; } catch (Exception e) { throw new InvalidFunctionUsageException( - format("Invalid parameter at index %d. %s must be parsable to %s.", index, text, - type.getSimpleName())); + format("Invalid parameter at index %d. %s must be parsable to %s.", index, text, type.getSimpleName())); } } /** * Static number generator method. */ - private String getRandomNumber(int decimalPlaces, BigDecimal minValue, BigDecimal maxValue, - boolean excludeMin, boolean excludeMax, BigDecimal multiple) { - + private String getRandomNumber(int decimalPlaces, + BigDecimal minValue, + BigDecimal maxValue, + boolean excludeMin, + boolean excludeMax, + BigDecimal multiple) { minValue = excludeMin ? incrementToExclude(minValue) : minValue; maxValue = excludeMax ? decrementToExclude(maxValue) : maxValue; @@ -145,20 +141,18 @@ private String getRandomNumber(int decimalPlaces, BigDecimal minValue, BigDecima BigDecimal createRandomValue(BigDecimal minValue, BigDecimal range, double random) { BigDecimal offset = range.multiply(BigDecimal.valueOf(random)); BigDecimal value = minValue.add(offset); - return value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ? BigDecimal.valueOf( - Double.MAX_VALUE) : value; + return value.compareTo(BigDecimal.valueOf(Double.MAX_VALUE)) > 0 ? BigDecimal.valueOf(Double.MAX_VALUE) + : value; } private BigDecimal largestMultipleOf(BigDecimal highest, BigDecimal multipleOf) { - RoundingMode roundingMode = - highest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.UP : RoundingMode.DOWN; + RoundingMode roundingMode = highest.compareTo(BigDecimal.ZERO) < 0 ? RoundingMode.UP : RoundingMode.DOWN; BigDecimal factor = highest.divide(multipleOf, 0, roundingMode); return multipleOf.multiply(factor); } private BigDecimal lowestMultipleOf(BigDecimal lowest, BigDecimal multipleOf) { - RoundingMode roundingMode = - lowest.compareTo(java.math.BigDecimal.ZERO) < 0 ? RoundingMode.DOWN : RoundingMode.UP; + RoundingMode roundingMode = lowest.compareTo(java.math.BigDecimal.ZERO) < 0 ? RoundingMode.DOWN : RoundingMode.UP; BigDecimal factor = lowest.divide(multipleOf, 0, roundingMode); return multipleOf.multiply(factor); } @@ -174,8 +168,7 @@ private BigDecimal decrementToExclude(BigDecimal val) { } private BigDecimal determineIncrement(BigDecimal number) { - return java.math.BigDecimal.valueOf( - 1.0d / (Math.pow(10d, findLeastSignificantDecimalPlace(number)))); + return BigDecimal.valueOf(1.0d / (Math.pow(10d, findLeastSignificantDecimalPlace(number)))); } private int findLeastSignificantDecimalPlace(BigDecimal number) { @@ -190,12 +183,9 @@ private int findLeastSignificantDecimalPlace(BigDecimal number) { return parts[1].length(); } - private BigDecimal createMultipleOf( - BigDecimal minimum, + private BigDecimal createMultipleOf(BigDecimal minimum, BigDecimal maximum, - BigDecimal multipleOf - ) { - + BigDecimal multipleOf) { BigDecimal lowestMultiple = lowestMultipleOf(minimum, multipleOf); BigDecimal largestMultiple = largestMultipleOf(maximum, multipleOf); @@ -223,5 +213,4 @@ private BigDecimal createMultipleOf( return randomMultiple; } - -} \ No newline at end of file +} diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/DecodeBase64Function.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/DecodeBase64Function.java index 35fc0d6c96..2c7c074c7e 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/DecodeBase64Function.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/DecodeBase64Function.java @@ -16,15 +16,15 @@ package org.citrusframework.functions.core; -import java.io.UnsupportedEncodingException; -import java.util.List; - import org.apache.commons.codec.binary.Base64; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.io.UnsupportedEncodingException; +import java.util.List; + /** * Decodes base64 binary data to a character sequence. * @@ -33,7 +33,7 @@ public class DecodeBase64Function implements Function { @Override public String execute(List parameterList, TestContext context) { - if (parameterList == null || parameterList.size() < 1) { + if (parameterList == null || parameterList.isEmpty()) { throw new InvalidFunctionUsageException("Invalid function parameter usage! Missing parameters!"); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/EncodeBase64Function.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/EncodeBase64Function.java index 2465903570..494c4b7b64 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/EncodeBase64Function.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/EncodeBase64Function.java @@ -16,15 +16,15 @@ package org.citrusframework.functions.core; -import java.io.UnsupportedEncodingException; -import java.util.List; - import org.apache.commons.codec.binary.Base64; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.io.UnsupportedEncodingException; +import java.util.List; + /** * Encodes a character sequence to base64 binary using given charset. * @@ -33,7 +33,7 @@ public class EncodeBase64Function implements Function { @Override public String execute(List parameterList, TestContext context) { - if (parameterList == null || parameterList.size() < 1) { + if (parameterList == null || parameterList.isEmpty()) { throw new InvalidFunctionUsageException("Invalid function parameter usage! Missing parameters!"); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomNumberFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomNumberFunction.java index a3fa489e5a..aacd485b9d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomNumberFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomNumberFunction.java @@ -16,13 +16,13 @@ package org.citrusframework.functions.core; -import java.util.List; -import java.util.Random; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.util.List; +import java.util.Random; + import static java.lang.Boolean.parseBoolean; import static java.lang.Integer.parseInt; @@ -113,7 +113,7 @@ private static String removeLeadingZeros(String generated) { } } - if (builder.length() == 0) { + if (builder.isEmpty()) { // very unlikely to happen, ensures that empty string is not returned builder.append('0'); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java index 377b2d5fe7..7fd8ec7b94 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomPatternFunction.java @@ -16,14 +16,15 @@ package org.citrusframework.functions.core; -import static org.citrusframework.util.StringUtils.hasText; - import com.mifmif.common.regex.Generex; -import java.util.List; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.util.List; + +import static org.citrusframework.util.StringUtils.hasText; + /** * The RandomPatternFunction generates a random string based on a provided regular expression pattern. * It uses the Generex library to generate the random string. @@ -34,9 +35,7 @@ */ public class RandomPatternFunction implements Function { - public String execute(List parameterList, TestContext context) { - if (parameterList == null) { throw new InvalidFunctionUsageException("Function parameters must not be null."); } @@ -52,8 +51,6 @@ public String execute(List parameterList, TestContext context) { "Function called with a pattern, the algorithm is not able to create a string for."); } - Generex generex = new Generex(pattern); - return generex.random(); + return new Generex(pattern).random(); } - -} \ No newline at end of file +} diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java index 326471a2b5..75064ae56b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/RandomStringFunction.java @@ -33,6 +33,7 @@ * */ public class RandomStringFunction implements Function { + private static final Random generator = new Random(System.currentTimeMillis()); private static final char[] ALPHABET_UPPER = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/ReadFileResourceFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/ReadFileResourceFunction.java index 710600b8c1..2d6a554039 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/ReadFileResourceFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/ReadFileResourceFunction.java @@ -16,9 +16,6 @@ package org.citrusframework.functions.core; -import java.io.IOException; -import java.util.List; - import org.apache.commons.codec.binary.Base64; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -26,12 +23,15 @@ import org.citrusframework.functions.Function; import org.citrusframework.util.FileUtils; +import java.io.IOException; +import java.util.List; + /** * Function reads file from given file path and returns the complete file content as function result. * File content is automatically parsed for test variables. - * + *

      * File path can also have test variables as part of the file name or path. - * + *

      * The function accepts the following parameters: * *

        diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/SubstringFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/SubstringFunction.java index a5f23b5973..f6270f56cc 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/SubstringFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/SubstringFunction.java @@ -16,18 +16,18 @@ package org.citrusframework.functions.core; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.util.List; + import static java.lang.Integer.parseInt; import static org.citrusframework.util.StringUtils.hasText; /** * Function implements simple substring functionality. - * + *

        * Function requires at least a target string and a beginIndex as function parameters. A * optional endIndex may be given as function parameter, too. The parameter usage looks * like this: substring(targetString, beginIndex, [endIndex]). diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlDecodeFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlDecodeFunction.java index 0f3abd5c5c..13bb58756c 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlDecodeFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlDecodeFunction.java @@ -16,15 +16,15 @@ package org.citrusframework.functions.core; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.List; + /** * Decodes URL encoded string to a character sequence. * @@ -33,7 +33,7 @@ public class UrlDecodeFunction implements Function { @Override public String execute(List parameterList, TestContext context) { - if (parameterList == null || parameterList.size() < 1) { + if (parameterList == null || parameterList.isEmpty()) { throw new InvalidFunctionUsageException("Invalid function parameter usage! Missing parameters!"); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlEncodeFunction.java b/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlEncodeFunction.java index 293cebb0e6..aad80ba6b3 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlEncodeFunction.java +++ b/core/citrus-base/src/main/java/org/citrusframework/functions/core/UrlEncodeFunction.java @@ -16,15 +16,15 @@ package org.citrusframework.functions.core; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.citrusframework.functions.Function; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.List; + /** * Encodes a character sequence to URL encoded string using given charset. * @@ -33,7 +33,7 @@ public class UrlEncodeFunction implements Function { @Override public String execute(List parameterList, TestContext context) { - if (parameterList == null || parameterList.size() < 1) { + if (parameterList == null || parameterList.isEmpty()) { throw new InvalidFunctionUsageException("Invalid function parameter usage! Missing parameters!"); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/log/DefaultLogModifier.java b/core/citrus-base/src/main/java/org/citrusframework/log/DefaultLogModifier.java index d99d2fd5ca..d14fc2c58e 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/log/DefaultLogModifier.java +++ b/core/citrus-base/src/main/java/org/citrusframework/log/DefaultLogModifier.java @@ -16,12 +16,12 @@ package org.citrusframework.log; +import org.citrusframework.CitrusSettings; + import java.util.Set; import java.util.regex.Pattern; import java.util.stream.Collectors; -import org.citrusframework.CitrusSettings; - /** * Default modifier implementation uses regular expressions to mask logger output. * Regular expressions match on default keywords. @@ -44,7 +44,7 @@ public class DefaultLogModifier implements LogMessageModifier { @Override public String mask(String source) { - if (!CitrusSettings.isLogModifierEnabled() || source == null || source.length() == 0) { + if (!CitrusSettings.isLogModifierEnabled() || source == null || source.isEmpty()) { return source; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/main/scan/ClassPathTestScanner.java b/core/citrus-base/src/main/java/org/citrusframework/main/scan/ClassPathTestScanner.java index 2bccded319..f6bc7fc907 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/main/scan/ClassPathTestScanner.java +++ b/core/citrus-base/src/main/java/org/citrusframework/main/scan/ClassPathTestScanner.java @@ -16,6 +16,14 @@ package org.citrusframework.main.scan; +import org.citrusframework.TestClass; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.ClasspathResourceResolver; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.ReflectionHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import java.lang.annotation.Annotation; import java.nio.file.Path; @@ -25,14 +33,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; -import org.citrusframework.TestClass; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.ClasspathResourceResolver; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.ReflectionHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * @since 2.7.4 */ @@ -97,7 +97,7 @@ protected boolean isIncluded(String className) { }); return hasTestMethod.get(); } catch (NoClassDefFoundError | ClassNotFoundException e) { - logger.warn("Unable to access class: " + className); + logger.warn("Unable to access class: {}", className); return false; } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java index 0b56ce8c7c..cdb38f5ee0 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessage.java @@ -67,7 +67,6 @@ public DefaultMessage() { * @param message */ public DefaultMessage(Message message) { - this(message.getPayload(), message.getHeaders()); this.setName(message.getName()); diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessageQueue.java b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessageQueue.java index 607990f568..091d60ea13 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessageQueue.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/DefaultMessageQueue.java @@ -15,12 +15,12 @@ */ package org.citrusframework.message; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + /** * Default message queue implementation. Holds queued messages in memory and adds selective consumption of messages * according to a message selector implementation. @@ -76,8 +76,7 @@ public Message receive(MessageSelector selector, long timeout) { timeLeft -= pollingInterval; if (RETRY_LOG.isDebugEnabled()) { - RETRY_LOG.debug("No message received with message selector - retrying in " + - (timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft) + "ms"); + RETRY_LOG.debug("No message received with message selector - retrying in {}ms", timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft); } try { @@ -99,11 +98,9 @@ public void purge(MessageSelector selector) { Message message = (Message) o; if (selector.accept(message)) { if (this.queue.remove(message)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Purged message '%s' from in memory queue", message.getId())); - } + logger.debug("Purged message '{}' from in memory queue", message.getId()); } else { - logger.warn(String.format("Failed to purge message '%s' from in memory queue", message.getId())); + logger.warn("Failed to purge message '{}' from in memory queue", message.getId()); } } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/ZipMessage.java b/core/citrus-base/src/main/java/org/citrusframework/message/ZipMessage.java index f2a1ac6f31..f63361d4dc 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/ZipMessage.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/ZipMessage.java @@ -16,6 +16,13 @@ package org.citrusframework.message; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resource; +import org.citrusframework.util.FileUtils; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -26,13 +33,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resource; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * @since 2.7.5 */ @@ -139,7 +139,7 @@ public ZipMessage addEntry(Entry entry) { private void addToZip(String path, Entry entry, ZipOutputStream zos) throws IOException { String name = (path.endsWith("/") ? path : path + "/") + entry.getName(); if (entry.isDirectory()) { - logger.debug("Adding directory to zip: " + name); + logger.debug("Adding directory to zip: {}", name); zos.putNextEntry(new ZipEntry(name.endsWith("/") ? name : name + "/")); for (Entry child : entry.getEntries()) { @@ -151,7 +151,7 @@ private void addToZip(String path, Entry entry, ZipOutputStream zos) throws IOEx } zos.closeEntry(); } else { - logger.debug("Adding file to zip: " + name); + logger.debug("Adding file to zip: {}", name); zos.putNextEntry(new ZipEntry(name)); zos.write(entry.getContent()); diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/correlation/DefaultCorrelationManager.java b/core/citrus-base/src/main/java/org/citrusframework/message/correlation/DefaultCorrelationManager.java index ffea23f0a1..29773dc60d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/correlation/DefaultCorrelationManager.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/correlation/DefaultCorrelationManager.java @@ -37,18 +37,13 @@ public class DefaultCorrelationManager implements CorrelationManager { @Override public void saveCorrelationKey(String correlationKeyName, String correlationKey, TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Saving correlation key for '%s'", correlationKeyName)); - } - + logger.debug("Saving correlation key for '{}'", correlationKeyName); context.setVariable(correlationKeyName, correlationKey); } @Override public String getCorrelationKey(String correlationKeyName, TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Get correlation key for '%s'", correlationKeyName)); - } + logger.debug("Get correlation key for '{}'", correlationKeyName); if (context.getVariables().containsKey(correlationKeyName)) { return context.getVariable(correlationKeyName); @@ -60,23 +55,18 @@ public String getCorrelationKey(String correlationKeyName, TestContext context) @Override public void store(String correlationKey, T object) { if (object == null) { - logger.warn(String.format("Ignore correlated null object for '%s'", correlationKey)); + logger.warn("Ignore correlated null object for '{}'", correlationKey); return; } - if (logger.isDebugEnabled()) { - logger.debug(String.format("Saving correlated object for '%s'", correlationKey)); - } + logger.debug("Saving correlated object for '{}'", correlationKey); objectStore.add(correlationKey, object); } @Override public T find(String correlationKey, long timeout) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Finding correlated object for '%s'", correlationKey)); - } - + logger.debug("Finding correlated object for '{}'", correlationKey); return objectStore.remove(correlationKey); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/message/correlation/PollingCorrelationManager.java b/core/citrus-base/src/main/java/org/citrusframework/message/correlation/PollingCorrelationManager.java index 4c445b7c1d..991d9bf6c6 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/message/correlation/PollingCorrelationManager.java +++ b/core/citrus-base/src/main/java/org/citrusframework/message/correlation/PollingCorrelationManager.java @@ -62,9 +62,7 @@ public T find(String correlationKey) { @Override public String getCorrelationKey(String correlationKeyName, TestContext context) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Get correlation key for '%s'", correlationKeyName)); - } + logger.debug("Get correlation key for '{}'", correlationKeyName); String correlationKey = null; if (context.getVariables().containsKey(correlationKeyName)) { @@ -77,7 +75,7 @@ public String getCorrelationKey(String correlationKeyName, TestContext context) timeLeft -= pollingInterval; if (RETRY_LOG.isDebugEnabled()) { - RETRY_LOG.debug("Correlation key not available yet - retrying in " + (timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft) + "ms"); + RETRY_LOG.debug("Correlation key not available yet - retrying in {}ms", timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft); } try { @@ -109,7 +107,7 @@ public T find(String correlationKey, long timeout) { timeLeft -= pollingInterval; if (RETRY_LOG.isDebugEnabled()) { - RETRY_LOG.debug(retryLogMessage + " - retrying in " + (timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft) + "ms"); + RETRY_LOG.debug("{} - retrying in {}ms", retryLogMessage, timeLeft > 0 ? pollingInterval : pollingInterval + timeLeft); } try { diff --git a/core/citrus-base/src/main/java/org/citrusframework/report/AbstractOutputFileReporter.java b/core/citrus-base/src/main/java/org/citrusframework/report/AbstractOutputFileReporter.java index 72f3265347..4a056888ff 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/report/AbstractOutputFileReporter.java +++ b/core/citrus-base/src/main/java/org/citrusframework/report/AbstractOutputFileReporter.java @@ -16,15 +16,15 @@ package org.citrusframework.report; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.Writer; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * @since 2.7.4 */ @@ -64,7 +64,7 @@ private void createReportFile(String reportFileName, String content) { try (Writer fileWriter = new FileWriter(new File(targetDirectory, reportFileName))) { fileWriter.append(content); fileWriter.flush(); - logger.info("Generated test report: " + targetDirectory + File.separator + reportFileName); + logger.info("Generated test report: {}{}{}", targetDirectory, File.separator, reportFileName); } catch (IOException e) { logger.error("Failed to create test report", e); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/report/HtmlReporter.java b/core/citrus-base/src/main/java/org/citrusframework/report/HtmlReporter.java index e093ce1e96..84ae87edef 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/report/HtmlReporter.java +++ b/core/citrus-base/src/main/java/org/citrusframework/report/HtmlReporter.java @@ -16,16 +16,6 @@ package org.citrusframework.report; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.text.DateFormat; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; - import org.apache.commons.codec.binary.Base64; import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; @@ -37,6 +27,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.text.DateFormat; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + /** * Basic logging reporter generating a HTML report with detailed test results. * @@ -243,7 +243,7 @@ private String getStackTraceHtml(Throwable cause) { } return "" + - "

        " + stackTraceBuilder.toString() +
        +        		"
        " + stackTraceBuilder +
                 		"
        " + getCodeSnippetHtml(cause) + "
        "; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/report/MessageTracingTestListener.java b/core/citrus-base/src/main/java/org/citrusframework/report/MessageTracingTestListener.java index 771973daa4..65ab37fd2d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/report/MessageTracingTestListener.java +++ b/core/citrus-base/src/main/java/org/citrusframework/report/MessageTracingTestListener.java @@ -16,15 +16,6 @@ package org.citrusframework.report; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - import org.citrusframework.CitrusSettings; import org.citrusframework.TestCase; import org.citrusframework.context.TestContext; @@ -34,10 +25,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + /** * Test listener collects all messages sent and received by Citrus during test execution. Listener * writes a trace file with all message content per test case to a output directory. - * + *

        * Note: This class is not thread safe! Parallel test execution leads to behaviour that messages get mixed. * Proper correlation to test case is not possible here. * @@ -129,7 +129,7 @@ private String separator() { * @return */ private String newLine() { - return System.getProperty("line.separator"); + return System.lineSeparator(); } /** @@ -151,7 +151,7 @@ protected File getTraceFile(String testName) { File traceFile = new File(targetDirectory, filename); if (traceFile.exists()) { - logger.warn(String.format("Trace file '%s' already exists. Normally a new file is created on each test execution ", traceFile.getName())); + logger.warn("Trace file '{}' already exists. Normally a new file is created on each test execution ", traceFile.getName()); } return traceFile; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/server/AbstractServer.java b/core/citrus-base/src/main/java/org/citrusframework/server/AbstractServer.java index d9d1d14b3f..a5b7b8adff 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/server/AbstractServer.java +++ b/core/citrus-base/src/main/java/org/citrusframework/server/AbstractServer.java @@ -16,9 +16,6 @@ package org.citrusframework.server; -import java.util.ArrayList; -import java.util.List; - import org.citrusframework.common.InitializingPhase; import org.citrusframework.common.ShutdownPhase; import org.citrusframework.context.TestContextFactory; @@ -36,6 +33,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; + /** * Abstract base class for {@link Server} implementations. * @@ -85,9 +85,7 @@ public AbstractServer() { @Override public void start() { - if (logger.isDebugEnabled()) { - logger.debug("Starting server: " + getName() + " ..."); - } + logger.debug("Starting server: {} ...", getName()); startup(); @@ -99,15 +97,13 @@ public void start() { thread.setDaemon(false); thread.start(); - logger.info("Started server: " + getName()); + logger.info("Started server: {}", getName()); } @Override public void stop() { if (isRunning()) { - if (logger.isDebugEnabled()) { - logger.debug("Stopping server: " + getName() + " ..."); - } + logger.debug("Stopping server: {} ...", getName()); shutdown(); @@ -117,7 +113,7 @@ public void stop() { thread = null; - logger.info("Stopped server: " + getName()); + logger.info("Stopped server: {}", getName()); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/sharding/ShardingConfiguration.java b/core/citrus-base/src/main/java/org/citrusframework/sharding/ShardingConfiguration.java index b203f4e4c0..85ccd5963b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/sharding/ShardingConfiguration.java +++ b/core/citrus-base/src/main/java/org/citrusframework/sharding/ShardingConfiguration.java @@ -109,7 +109,7 @@ public ShardingConfiguration() { * * @param systemProvider a provider for system environment variables and properties. */ - protected ShardingConfiguration(SystemProvider systemProvider) { + ShardingConfiguration(SystemProvider systemProvider) { this(getTotalNumberOfShards(systemProvider), getShardNumber(systemProvider), systemProvider); } @@ -131,7 +131,7 @@ public ShardingConfiguration(int totalNumberOfShards, int shardNumber) { * @param shardNumber the shard number for this loader, zero-based. * @param systemProvider a provider for system environment variables and properties. */ - protected ShardingConfiguration(int totalNumberOfShards, int shardNumber, SystemProvider systemProvider) { + private ShardingConfiguration(int totalNumberOfShards, int shardNumber, SystemProvider systemProvider) { this.totalNumberOfShards = totalNumberOfShards; this.shardNumber = shardNumber; diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/BooleanExpressionParser.java b/core/citrus-base/src/main/java/org/citrusframework/util/BooleanExpressionParser.java index c33f14288f..09e91ef776 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/BooleanExpressionParser.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/BooleanExpressionParser.java @@ -127,9 +127,7 @@ public static boolean evaluate(final String expression) { result = parseBoolean(evaluateExpressionStack(operators, values)); - if (logger.isDebugEnabled()) { - logger.debug("Boolean expression {} evaluates to {}", expression, result); - } + logger.debug("Boolean expression {} evaluates to {}", expression, result); } catch (final NoSuchElementException e) { throw new CitrusRuntimeException("Unable to parse boolean expression '" + expression + "'. Maybe expression is incomplete!", e); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java index d17c2a805d..b70b2b4e7a 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/FileUtils.java @@ -16,6 +16,15 @@ package org.citrusframework.util; +import org.citrusframework.CitrusSettings; +import org.citrusframework.TestSource; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.spi.Resource; +import org.citrusframework.spi.Resources; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; @@ -32,15 +41,6 @@ import java.util.Set; import java.util.Stack; -import org.citrusframework.CitrusSettings; -import org.citrusframework.TestSource; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.spi.Resource; -import org.citrusframework.spi.Resources; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * Class to provide general file utilities, such as listing all XML files in a directory, * or finding certain tests in a directory. @@ -121,9 +121,8 @@ public static String readToString(Resource resource, Charset charset) throws IOE throw new CitrusRuntimeException("Failed to read resource %s - does not exist".formatted(resource.getLocation())); } - if (logger.isDebugEnabled()) { - logger.debug(String.format("Reading file resource: '%s' (encoding is '%s')", resource.getLocation(), charset.displayName())); - } + logger.debug("Reading file resource: '{}' (encoding is '{}')", resource.getLocation(), charset.displayName()); + return readToString(resource.getInputStream(), charset); } @@ -148,9 +147,7 @@ public static String readToString(InputStream inputStream, Charset charset) thro * @param file */ public static void writeToFile(InputStream inputStream, File file) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Writing file resource: '%s'", file.getName())); - } + logger.debug("Writing file resource: '{}'", file.getName()); if (!file.getParentFile().exists()) { if (!file.getParentFile().mkdirs()) { @@ -180,9 +177,7 @@ public static void writeToFile(String content, File file) { * @param file */ public static void writeToFile(String content, File file, Charset charset) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Writing file resource: '%s' (encoding is '%s')", file.getName(), charset.displayName())); - } + logger.debug("Writing file resource: '{}' (encoding is '{}')", file.getName(), charset.displayName()); if (!file.getParentFile().exists()) { if (!file.getParentFile().mkdirs()) { @@ -224,7 +219,7 @@ public static List findFiles(final String startDir, final Set file } /* walk through the directories */ - while (dirs.size() > 0) { + while (!dirs.isEmpty()) { final File file = dirs.pop(); File[] foundFiles = file.listFiles((dir, name) -> { File tmp = new File(dir.getPath() + File.separator + name); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/PropertyUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/PropertyUtils.java index 43788a1abf..588616bfb5 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/PropertyUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/PropertyUtils.java @@ -16,12 +16,12 @@ package org.citrusframework.util; -import java.io.IOException; -import java.util.Properties; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.Resource; +import java.io.IOException; +import java.util.Properties; + /** * Utility class supporting property replacement in template files. * For usage see doc generators and test case creator. @@ -99,7 +99,7 @@ public static String replacePropertiesInString(final String line, Properties pro if (!properties.containsKey(propertyName.toString())) { throw new CitrusRuntimeException("No such property '" - + PROPERTY_MARKER + propertyName.toString() + PROPERTY_MARKER + "'"); + + PROPERTY_MARKER + propertyName + PROPERTY_MARKER + "'"); } newStr.append(line, startIndex, searchIndex); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 7b68e39ddb..3cf0086ac4 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -62,7 +62,6 @@ public static boolean isNotEmpty(String str) { } public static String appendSegmentToUrlPath(String path, String segment) { - if (path == null) { return segment; } @@ -88,7 +87,7 @@ public static String quote(String text, boolean quote) { /** * Trims trailing whitespace characters and the first trailing comma from the end of the given StringBuilder. - * + *

        * This method removes all trailing whitespace characters (such as spaces, tabs, and newline characters) * and the first trailing comma found from the end of the content in the provided StringBuilder. * Any additional commas or whitespace characters after the first trailing comma are not removed. @@ -114,11 +113,11 @@ public static void trimTrailingComma(StringBuilder builder) { * the rest of the string unchanged. If the input string is empty or null, * an empty string is returned. * - * @param input The string to be converted to title case. It can be null or empty. - * @return the strnig in title case + * @param input The string to be converted. It can be null or empty. + * @return the string in with upper case first letter */ - public static String titleCase(String input) { - if (input != null && !"".equals(input)) { + public static String convertFirstChartToUpperCase(String input) { + if (input != null && !input.isEmpty()) { String firstLetter = input.substring(0, 1).toUpperCase(Locale.ROOT); return input.length() == 1 ? firstLetter : firstLetter + input.substring(1); } else { diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java index 67ba7afd8a..469d2963fe 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java @@ -93,7 +93,7 @@ public static void waitForCompletion(final ScheduledExecutorService scheduledExe if (logger.isDebugEnabled()) { logger.debug("Failed to wait for completion of nested test actions", e); } else { - logger.warn(String.format("Failed to wait for completion of nested test actions because of %s", e.getMessage())); + logger.warn("Failed to wait for completion of nested test actions because of {}", e.getMessage()); } } }, 100L, timeout / 10, TimeUnit.MILLISECONDS); @@ -110,7 +110,7 @@ public static void waitForCompletion(final ScheduledExecutorService scheduledExe scheduledExecutor.shutdown(); scheduledExecutor.awaitTermination((timeout / 10) / 2, TimeUnit.MICROSECONDS); } catch (InterruptedException e) { - logger.warn(String.format("Failed to await orderly termination of waiting tasks to complete, caused by %s", e.getMessage())); + logger.warn("Failed to await orderly termination of waiting tasks to complete, caused by {}", e.getMessage()); } if (!scheduledExecutor.isTerminated()) { diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java index d62bce85db..d0233cfec9 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultHeaderValidator.java @@ -16,13 +16,6 @@ package org.citrusframework.validation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Optional; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.util.StringUtils; @@ -31,6 +24,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Optional; + /** * @since 2.7.6 */ @@ -76,9 +77,7 @@ public void validateHeader(String headerName, Object receivedValue, Object contr + null + "'"); } - if (logger.isDebugEnabled()) { - logger.debug("Validating header element: %s='%s' : OK".formatted(headerName, expectedValue)); - } + logger.debug("Validating header element: {}='{}' : OK", headerName, expectedValue); } public void validateHeaderArray(String headerName, Object receivedValue, Object controlValue, TestContext context, HeaderValidationContext validationContext) { @@ -121,15 +120,12 @@ public void validateHeaderArray(String headerName, Object receivedValue, Object throw new ValidationException(String.format("Values not equal for header element '%s', expected '%s' but was '%s'", headerName, String.join(", ", expectedValues), String.join(", ", receivedValues))); } - } else if (!expectedValues.isEmpty()) { throw new ValidationException(String.format("Values not equal for header element '%s', expected '%s' but was 'null'", headerName, String.join(", ", expectedValues))); } - if (logger.isDebugEnabled()) { - logger.debug("Validating header element: %s='%s' : OK".formatted(headerName, String.join(", ", expectedValues))); - } + logger.debug("Validating header element: {}='{}' : OK", headerName, String.join(", ", expectedValues)); } private static boolean validateExpected(String headerName, TestContext context, @@ -156,6 +152,7 @@ private static boolean validateExpected(String headerName, TestContext context, } } } + return validated; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultMessageHeaderValidator.java b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultMessageHeaderValidator.java index f6bcc30068..fed3d9171b 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultMessageHeaderValidator.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/DefaultMessageHeaderValidator.java @@ -16,15 +16,6 @@ package org.citrusframework.validation; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.resolver.EndpointUriResolver; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -36,6 +27,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + /** * Basic header message validator provides message header validation. Subclasses only have to add * specific logic for message payload validation. This validator is based on a control message. @@ -112,7 +112,7 @@ public void validateMessage(Message receivedMessage, Message controlMessage, Tes /** * Combines header validators from multiple sources. First the manual added validators in this class are added. Then * validators coming from reference resolver and resource path lookup are added. - * + *

        * At the end a distinct combination of all validators is returned. * @param context * @return diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/DelegatingPayloadVariableExtractor.java b/core/citrus-base/src/main/java/org/citrusframework/validation/DelegatingPayloadVariableExtractor.java index a7d59ab176..d86d7d3b61 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/DelegatingPayloadVariableExtractor.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/DelegatingPayloadVariableExtractor.java @@ -60,9 +60,7 @@ public void extractVariables(Message message, TestContext context) { return; } - if (logger.isDebugEnabled()) { - logger.debug("Reading path elements."); - } + logger.debug("Reading path elements."); Map jsonPathExpressions = new LinkedHashMap<>(); Map xpathExpressions = new LinkedHashMap<>(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/ValidationUtils.java b/core/citrus-base/src/main/java/org/citrusframework/validation/ValidationUtils.java index d18083c144..600f8a29cd 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/ValidationUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/ValidationUtils.java @@ -16,18 +16,18 @@ package org.citrusframework.validation; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - import org.apache.commons.codec.binary.Base64; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.validation.matcher.ValidationMatcherUtils; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + /** * Utility class provides helper methods for validation work in Citrus. * @@ -155,7 +155,7 @@ public static void validateValues(Object actualValue, Object expectedValue, Stri /** * Combines value matchers from multiple sources. Includes validators coming from reference resolver * and resource path lookup are added. - * + *

        * Then pick matcher that explicitly supports the given expected value type. * @param expectedValue * @param context diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/json/JsonMessageValidationContext.java b/core/citrus-base/src/main/java/org/citrusframework/validation/json/JsonMessageValidationContext.java index 3c4faaaec0..39d1e09768 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/json/JsonMessageValidationContext.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/json/JsonMessageValidationContext.java @@ -16,14 +16,14 @@ package org.citrusframework.validation.json; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - import org.citrusframework.validation.context.DefaultValidationContext; import org.citrusframework.validation.context.SchemaValidationContext; import org.citrusframework.validation.context.ValidationContext; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** * Validation context holding JSON specific validation information. * @since 2.3 @@ -35,7 +35,7 @@ public class JsonMessageValidationContext extends DefaultValidationContext imple /** * Should message be validated with its schema definition - * + *

        * This is currently disabled by default, because old json tests would fail with a validation exception * as soon as a json schema repository is specified and the schema validation is activated. */ diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/DefaultValidationMatcherLibrary.java b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/DefaultValidationMatcherLibrary.java index 875a6f4733..124e30da38 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/DefaultValidationMatcherLibrary.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/DefaultValidationMatcherLibrary.java @@ -88,9 +88,7 @@ public DefaultValidationMatcherLibrary() { private void lookupValidationMatchers() { ValidationMatcher.lookup().forEach((k, m) -> { getMembers().put(k, m); - if (logger.isDebugEnabled()) { - logger.debug(String.format("Register message matcher '%s' as %s", k, m.getClass())); - } + logger.debug("Register message matcher '{}' as {}", k, m.getClass()); }); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/CreateVariableValidationMatcher.java b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/CreateVariableValidationMatcher.java index a55813f0b1..fe51f77e92 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/CreateVariableValidationMatcher.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/CreateVariableValidationMatcher.java @@ -16,14 +16,14 @@ package org.citrusframework.validation.matcher.core; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.validation.matcher.ValidationMatcher; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + /** * Creates new variables from given field. Either uses field name or control value as variable name. * @@ -42,7 +42,7 @@ public void validate(String fieldName, String value, List controlParamet name = controlParameters.get(0); } - logger.debug("Setting variable: " + name + " to value: " + value); + logger.debug("Setting variable: {} to value: {}", name, value); context.setVariable(name, value); } diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/DateRangeValidationMatcher.java b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/DateRangeValidationMatcher.java index 658fc84cfd..94e790ce12 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/DateRangeValidationMatcher.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/DateRangeValidationMatcher.java @@ -47,10 +47,7 @@ public class DateRangeValidationMatcher implements ValidationMatcher { @Override public void validate(String fieldName, String value, List params, TestContext context) throws ValidationException { - logger.debug(String.format( - "Validating date range for date '%s' using control data: %s", - value, - ValidationMatcherUtils.getParameterListAsString(params))); + logger.debug("Validating date range for date '{}' using control data: {}", value, ValidationMatcherUtils.getParameterListAsString(params)); try { String dateFromParam = params.get(0); diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/IgnoreValidationMatcher.java b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/IgnoreValidationMatcher.java index b5deaa66af..568892eca2 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/IgnoreValidationMatcher.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/IgnoreValidationMatcher.java @@ -34,8 +34,6 @@ public class IgnoreValidationMatcher implements ValidationMatcher { @Override public void validate(String fieldName, String value, List controlParameters, TestContext context) throws ValidationException { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Ignoring value for field '%s'", fieldName)); - } + logger.debug("Ignoring value for field '{}'", fieldName); } } diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/WeekdayValidationMatcher.java b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/WeekdayValidationMatcher.java index e896d42255..6f181c537c 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/WeekdayValidationMatcher.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/matcher/core/WeekdayValidationMatcher.java @@ -107,7 +107,7 @@ private enum Weekday { SATURDAY(Calendar.SATURDAY), SUNDAY(Calendar.SUNDAY); - private int constantValue; + private final int constantValue; Weekday(int constant) { this.constantValue = constant; diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/script/TemplateBasedScriptBuilder.java b/core/citrus-base/src/main/java/org/citrusframework/validation/script/TemplateBasedScriptBuilder.java index b9c7c1ba66..38fefeca30 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/script/TemplateBasedScriptBuilder.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/script/TemplateBasedScriptBuilder.java @@ -16,14 +16,14 @@ package org.citrusframework.validation.script; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.Resource; import org.citrusframework.util.FileUtils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; + /** * Script builder builds a script with custom code body. Script header and tail come from static * script template. @@ -71,7 +71,7 @@ public String build() { scriptBuilder.append(line); scriptBuilder.append("\n"); } else { - scriptBody.append((scriptBody.length() == 0 ? "" : "\n")); + scriptBody.append((scriptBody.isEmpty() ? "" : "\n")); scriptBody.append(line); } } @@ -83,7 +83,7 @@ public String build() { } scriptBuilder.append(scriptHead); - scriptBuilder.append(scriptBody.toString()); + scriptBuilder.append(scriptBody); scriptBuilder.append(scriptTail); return scriptBuilder.toString(); diff --git a/core/citrus-base/src/main/java/org/citrusframework/validation/script/sql/SqlResultSetScriptValidator.java b/core/citrus-base/src/main/java/org/citrusframework/validation/script/sql/SqlResultSetScriptValidator.java index 65ac950ec6..da62d2c682 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/validation/script/sql/SqlResultSetScriptValidator.java +++ b/core/citrus-base/src/main/java/org/citrusframework/validation/script/sql/SqlResultSetScriptValidator.java @@ -16,9 +16,6 @@ package org.citrusframework.validation.script.sql; -import java.util.List; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.spi.ResourcePathTypeResolver; @@ -27,6 +24,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; +import java.util.Map; + /** * Validator working on SQL result sets. Scripts get the actual test context * and a SQL result set representation for validation. @@ -52,7 +52,7 @@ static Map lookup() { Map validators = TYPE_RESOLVER.resolveAll("", TypeResolver.DEFAULT_TYPE_PROPERTY, "name"); if (logger.isDebugEnabled()) { - validators.forEach((k, v) -> logger.debug(String.format("Found SQL result set validator '%s' as %s", k, v.getClass()))); + validators.forEach((k, v) -> logger.debug("Found SQL result set validator '{}' as {}", k, v.getClass())); } return validators; } diff --git a/core/citrus-base/src/main/java/org/citrusframework/xml/Jaxb2Marshaller.java b/core/citrus-base/src/main/java/org/citrusframework/xml/Jaxb2Marshaller.java index 9baf24fa25..bbc8e9f76a 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/xml/Jaxb2Marshaller.java +++ b/core/citrus-base/src/main/java/org/citrusframework/xml/Jaxb2Marshaller.java @@ -16,21 +16,6 @@ package org.citrusframework.xml; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.xml.XMLConstants; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.sax.SAXSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; - import jakarta.xml.bind.JAXBContext; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.PropertyException; @@ -43,6 +28,21 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLReader; +import javax.xml.XMLConstants; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** * Marshaller uses Jaxb to marshal/unmarshal data. */ @@ -119,7 +119,7 @@ private jakarta.xml.bind.Marshaller createMarshaller() throws JAXBException { try { marshaller.setProperty(k, v); } catch (PropertyException e) { - logger.warn(String.format("Unable to set marshaller property %s=%s", k, v)); + logger.warn("Unable to set marshaller property {}={}", k, v); } }); @@ -139,9 +139,7 @@ private jakarta.xml.bind.Unmarshaller createUnmarshaller() throws JAXBException private JAXBContext getOrCreateContext() throws JAXBException { if (jaxbContext == null) { synchronized (this) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Creating JAXBContext with bound classes %s", Arrays.toString(classesToBeBound))); - } + logger.debug("Creating JAXBContext with bound classes {}", Arrays.toString(classesToBeBound)); if (classesToBeBound != null) { jaxbContext = JAXBContext.newInstance(classesToBeBound); @@ -161,10 +159,7 @@ public void setProperty(String key, Object value) { } private Schema loadSchema(Resource... schemas) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Using marshaller validation schemas '%s'", - Stream.of(schemas).map(Object::toString).collect(Collectors.joining(",")))); - } + logger.debug("Using marshaller validation schemas '{}'", Stream.of(schemas).map(Object::toString).collect(Collectors.joining(","))); try { List schemaSources = new ArrayList<>(); diff --git a/core/citrus-base/src/test/java/org/citrusframework/TestCaseTest.java b/core/citrus-base/src/test/java/org/citrusframework/TestCaseTest.java index 638474f31c..fcfec80b37 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/TestCaseTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/TestCaseTest.java @@ -16,13 +16,6 @@ package org.citrusframework; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.actions.AbstractAsyncTestAction; import org.citrusframework.actions.EchoAction; import org.citrusframework.container.Async; @@ -35,6 +28,13 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Optional; + import static org.citrusframework.DefaultTestActionBuilder.action; public class TestCaseTest extends UnitTestSupport { @@ -121,7 +121,7 @@ public void doExecuteAsync(final TestContext context) { .findAny(); waitingThread.ifPresent(thread -> LoggerFactory.getLogger("TestWaitForFinishAsync").warn(Arrays.toString(threads.get(thread)))); - waitingThread.ifPresent(thread -> Assert.fail(String.format("Waiting thread still alive: %s", thread.toString()))); + waitingThread.ifPresent(thread -> Assert.fail(String.format("Waiting thread still alive: %s", thread))); } @Test @@ -220,6 +220,6 @@ public void testThreadLeak() { .filter(Thread::isAlive) .findAny(); - waitingThread.ifPresent(thread -> Assert.fail(String.format("Waiting thread still alive: %s", thread.toString()))); + waitingThread.ifPresent(thread -> Assert.fail(String.format("Waiting thread still alive: %s", thread))); } } diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/PurgeEndpointActionTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/PurgeEndpointActionTest.java index b77472e1e5..24c7981518 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/PurgeEndpointActionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/PurgeEndpointActionTest.java @@ -16,8 +16,6 @@ package org.citrusframework.actions; -import java.util.Collections; - import org.citrusframework.UnitTestSupport; import org.citrusframework.context.TestContextFactory; import org.citrusframework.endpoint.Endpoint; @@ -28,6 +26,8 @@ import org.mockito.Mockito; import org.testng.annotations.Test; +import java.util.Collections; + import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.when; @@ -85,7 +85,7 @@ public void testPurgeWithEndpointObjects() { } @Test - public void testPurgeWithMessageSelector() throws Exception { + public void testPurgeWithMessageSelector() { reset(mockEndpoint, consumer, selectiveConsumer); when(mockEndpoint.getName()).thenReturn("mockEndpoint"); @@ -102,7 +102,7 @@ public void testPurgeWithMessageSelector() throws Exception { } @Test - public void testPurgeWithMessageSelectorMap() throws Exception { + public void testPurgeWithMessageSelectorMap() { reset(mockEndpoint, consumer, selectiveConsumer); when(mockEndpoint.getName()).thenReturn("mockEndpoint"); diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java index 9b19eeba19..60cc62070c 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/ReceiveMessageBuilderTest.java @@ -16,14 +16,6 @@ package org.citrusframework.actions; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; import org.citrusframework.endpoint.Endpoint; @@ -52,11 +44,24 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import static org.citrusframework.validation.json.JsonMessageValidationContext.Builder.json; import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; import static org.citrusframework.validation.xml.XmlMessageValidationContext.Builder.xml; import static org.citrusframework.validation.xml.XpathMessageValidationContext.Builder.xpath; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -206,7 +211,7 @@ void payload_asResourceWithCharset() { } @Test - void testSetPayloadWithResourceIoExceptionsIsWrapped() throws IOException { + void testSetPayloadWithResourceIoExceptionsIsWrapped() { //GIVEN final ReceiveMessageAction.Builder builder = new ReceiveMessageAction.Builder(); diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java index cdba297247..1888eff21f 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/ReceiveMessageActionBuilderTest.java @@ -16,12 +16,6 @@ package org.citrusframework.actions.dsl; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - import org.citrusframework.DefaultTestCaseRunner; import org.citrusframework.TestCase; import org.citrusframework.UnitTestSupport; @@ -59,11 +53,22 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import static org.citrusframework.actions.ReceiveMessageAction.Builder.receive; import static org.citrusframework.dsl.MessageSupport.MessageHeaderSupport.fromHeaders; import static org.citrusframework.dsl.MessageSupport.message; import static org.citrusframework.validation.xml.XmlMessageValidationContext.Builder.xml; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class ReceiveMessageActionBuilderTest extends UnitTestSupport { @@ -220,7 +225,7 @@ public void testReceiveBuilderWithPayloadString() { } @Test - public void testReceiveBuilderWithPayloadResource() throws IOException { + public void testReceiveBuilderWithPayloadResource() { reset(resource, messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); when(messageEndpoint.getEndpointConfiguration()).thenReturn(configuration); @@ -523,7 +528,7 @@ public void testReceiveBuilderWithHeaderDataBuilder() { } @Test - public void testReceiveBuilderWithHeaderResource() throws IOException { + public void testReceiveBuilderWithHeaderResource() { reset(resource, messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); when(messageEndpoint.getEndpointConfiguration()).thenReturn(configuration); @@ -581,7 +586,7 @@ public void testReceiveBuilderWithHeaderResource() throws IOException { } @Test - public void testReceiveBuilderWithMultipleHeaderResource() throws IOException { + public void testReceiveBuilderWithMultipleHeaderResource() { reset(resource, messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); when(messageEndpoint.getEndpointConfiguration()).thenReturn(configuration); @@ -1051,7 +1056,7 @@ public void testReceiveBuilderWithValidationProcessor() { } @Test - public void testDeactivateSchemaValidation() throws IOException { + public void testDeactivateSchemaValidation() { reset(messageEndpoint, messageConsumer, configuration); when(messageEndpoint.createConsumer()).thenReturn(messageConsumer); diff --git a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java index 7bfe51471f..d31b38669c 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/actions/dsl/SendMessageActionBuilderTest.java @@ -16,11 +16,6 @@ package org.citrusframework.actions.dsl; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; - import org.citrusframework.DefaultTestCaseRunner; import org.citrusframework.TestCase; import org.citrusframework.UnitTestSupport; @@ -52,6 +47,10 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.util.Collections; +import java.util.HashMap; + import static org.citrusframework.actions.SendMessageAction.Builder.send; import static org.citrusframework.dsl.MessageSupport.message; import static org.mockito.Mockito.any; @@ -273,7 +272,7 @@ public void testSendBuilderWithPayloadData() { } @Test - public void testSendBuilderWithPayloadResource() throws IOException { + public void testSendBuilderWithPayloadResource() { reset(resource, messageEndpoint, messageProducer); when(messageEndpoint.createProducer()).thenReturn(messageProducer); when(messageEndpoint.getActor()).thenReturn(null); @@ -497,7 +496,7 @@ public void testSendBuilderWithMultipleHeaderData() { } @Test - public void testSendBuilderWithHeaderDataResource() throws IOException { + public void testSendBuilderWithHeaderDataResource() { reset(resource, messageEndpoint, messageProducer); when(messageEndpoint.createProducer()).thenReturn(messageProducer); when(messageEndpoint.getActor()).thenReturn(null); diff --git a/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/HeaderMappingKeyExtractorTest.java b/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/HeaderMappingKeyExtractorTest.java index cf93cc2e75..806dda55fa 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/HeaderMappingKeyExtractorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/HeaderMappingKeyExtractorTest.java @@ -24,7 +24,7 @@ public class HeaderMappingKeyExtractorTest { @Test - public void testExtractMappingKey() throws Exception { + public void testExtractMappingKey() { HeaderMappingKeyExtractor extractor = new HeaderMappingKeyExtractor(); extractor.setHeaderName("Foo"); @@ -34,7 +34,7 @@ public void testExtractMappingKey() throws Exception { } @Test - public void testExtractMappingKeyWithoutHeaderNameSet() throws Exception { + public void testExtractMappingKeyWithoutHeaderNameSet() { HeaderMappingKeyExtractor extractor = new HeaderMappingKeyExtractor(); try { @@ -48,7 +48,7 @@ public void testExtractMappingKeyWithoutHeaderNameSet() throws Exception { } @Test - public void testExtractMappingKeyWithUnknownHeaderName() throws Exception { + public void testExtractMappingKeyWithUnknownHeaderName() { HeaderMappingKeyExtractor extractor = new HeaderMappingKeyExtractor("UNKNOWN"); try { diff --git a/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/SoapActionMappingKeyExtractorTest.java b/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/SoapActionMappingKeyExtractorTest.java index 2285c3c752..f7ef07644d 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/SoapActionMappingKeyExtractorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/endpoint/adapter/mapping/SoapActionMappingKeyExtractorTest.java @@ -24,7 +24,7 @@ public class SoapActionMappingKeyExtractorTest { @Test - public void testExtractMappingKey() throws Exception { + public void testExtractMappingKey() { SoapActionMappingKeyExtractor extractor = new SoapActionMappingKeyExtractor(); Assert.assertEquals(extractor.extractMappingKey(new DefaultMessage("Foo") @@ -33,7 +33,7 @@ public void testExtractMappingKey() throws Exception { } @Test - public void testExtractNoMappingFound() throws Exception { + public void testExtractNoMappingFound() { SoapActionMappingKeyExtractor extractor = new SoapActionMappingKeyExtractor(); try { diff --git a/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/DirectEndpointComponentTest.java b/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/DirectEndpointComponentTest.java index 04a94c6091..d28152e42b 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/DirectEndpointComponentTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/endpoint/direct/DirectEndpointComponentTest.java @@ -16,8 +16,6 @@ package org.citrusframework.endpoint.direct; -import java.util.Map; - import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; import org.citrusframework.endpoint.Endpoint; @@ -26,6 +24,8 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.util.Map; + public class DirectEndpointComponentTest { private TestContext context; @@ -36,7 +36,7 @@ public void setupMocks() { } @Test - public void testCreateDirectEndpoint() throws Exception { + public void testCreateDirectEndpoint() { DirectEndpointComponent component = new DirectEndpointComponent(); Assert.assertFalse(context.getReferenceResolver().isResolvable("queueName")); @@ -50,7 +50,7 @@ public void testCreateDirectEndpoint() throws Exception { } @Test - public void testCreateSyncDirectEndpoint() throws Exception { + public void testCreateSyncDirectEndpoint() { DirectEndpointComponent component = new DirectEndpointComponent(); Assert.assertFalse(context.getReferenceResolver().isResolvable("queueName")); @@ -63,7 +63,7 @@ public void testCreateSyncDirectEndpoint() throws Exception { } @Test - public void testCreateDirectEndpointWithParameters() throws Exception { + public void testCreateDirectEndpointWithParameters() { DirectEndpointComponent component = new DirectEndpointComponent(); Endpoint endpoint = component.createEndpoint("direct:queueName?timeout=10000", context); diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/FunctionsTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/FunctionsTest.java index 975946ca91..c4433e3ace 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/FunctionsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/FunctionsTest.java @@ -16,15 +16,23 @@ package org.citrusframework.functions; -import java.nio.charset.StandardCharsets; -import java.text.SimpleDateFormat; - import org.citrusframework.UnitTestSupport; import org.citrusframework.functions.core.RandomStringFunction; import org.testng.Assert; import org.testng.annotations.Test; -import static org.citrusframework.functions.Functions.*; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; + +import static org.citrusframework.functions.Functions.changeDate; +import static org.citrusframework.functions.Functions.currentDate; +import static org.citrusframework.functions.Functions.decodeBase64; +import static org.citrusframework.functions.Functions.digestAuthHeader; +import static org.citrusframework.functions.Functions.encodeBase64; +import static org.citrusframework.functions.Functions.randomNumber; +import static org.citrusframework.functions.Functions.randomString; +import static org.citrusframework.functions.Functions.randomUUID; +import static org.citrusframework.functions.Functions.unixTimestamp; public class FunctionsTest extends UnitTestSupport { @@ -39,65 +47,65 @@ public void testCurrentDateFormat() throws Exception { } @Test - public void testChangeDate() throws Exception { + public void testChangeDate() { Assert.assertEquals(changeDate("01.01.2014", "+1y", context), "01.01.2015"); Assert.assertEquals(changeDate("2014-01-01T12:00:00", "+1y", "yyyy-MM-dd'T'HH:mm:ss", context), "2015-01-01T12:00:00"); } @Test - public void testEncodeBase64() throws Exception { + public void testEncodeBase64() { Assert.assertEquals(encodeBase64("Foo", context), "Rm9v"); } @Test - public void testEncodeBase64WithCharset() throws Exception { + public void testEncodeBase64WithCharset() { Assert.assertEquals(encodeBase64("Foo", StandardCharsets.UTF_8, context), "Rm9v"); } @Test - public void testDecodeBase64() throws Exception { + public void testDecodeBase64() { Assert.assertEquals(decodeBase64("Rm9v", context), "Foo"); } @Test - public void testDecodeBase64WithCharset() throws Exception { + public void testDecodeBase64WithCharset() { Assert.assertEquals(decodeBase64("Rm9v", StandardCharsets.UTF_8, context), "Foo"); } @Test - public void testDigestAuthHeader() throws Exception { + public void testDigestAuthHeader() { digestAuthHeader("username", "password", "authRealm", "acegi", "POST", "http://localhost:8080", "citrus", "md5", context); } @Test - public void testRandomUUID() throws Exception { + public void testRandomUUID() { Assert.assertNotNull(randomUUID(context)); } @Test - public void testRandomNumber() throws Exception { + public void testRandomNumber() { Assert.assertTrue(randomNumber(10L, context).length() > 9); } @Test - public void testRandomNumberWithParams() throws Exception { + public void testRandomNumberWithParams() { Assert.assertTrue(randomNumber(10L, true, context).length() > 9); } @Test - public void testRandomString() throws Exception { + public void testRandomString() { Assert.assertEquals(randomString(10L, context).length(), 10); } @Test - public void testRandomStringWithParams() throws Exception { + public void testRandomStringWithParams() { Assert.assertEquals(randomString(10L, false, context).length(), 10); Assert.assertEquals(randomString(10L, RandomStringFunction.LOWERCASE, context).length(), 10); Assert.assertEquals(randomString(10L, RandomStringFunction.UPPERCASE, false, context).length(), 10); } @Test - public void testUnixTimestamp() throws Exception { + public void testUnixTimestamp() { Assert.assertEquals(String.valueOf(System.currentTimeMillis() / 1000L), unixTimestamp(context)); } } diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java index 82cf51cfa7..5e30fdcbca 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/AdvancedRandomNumberFunctionTest.java @@ -153,9 +153,6 @@ public void testRandomInteger32MinEqualsMaxEdgeCase() { } } - // randomDouble('0','3','3','true','true') - // randomDouble('0','3','3','true','true') - @Test public void testRandomDouble32MinEqualsMaxEdgeCase() { List params = List.of("2", "3.0", "3.0", "false", "false"); @@ -169,8 +166,7 @@ public void testRandomDouble32MinEqualsMaxEdgeCase() { @Test public void testRandomInteger64EdgeCase() { - List params = List.of("0", "-9223372036854775808", "9223372036854775807", "false", - "false"); + List params = List.of("0", "-9223372036854775808", "9223372036854775807", "false", "false"); String result = function.execute(params, context); assertNotNull(result); double randomValue = Double.parseDouble(result); @@ -188,8 +184,7 @@ public void testRandomNumberFloatEdgeCase() { @Test public void testRandomNumberDoubleEdgeCase() { - List params = List.of("0", "-1.7976931348623157E308", "1.7976931348623157E308", - "false", "false"); + List params = List.of("0", "-1.7976931348623157E308", "1.7976931348623157E308", "false", "false"); String result = function.execute(params, context); assertNotNull(result); double randomValue = Double.parseDouble(result); @@ -244,7 +239,6 @@ public void testInvalidMaxValueFormat() { @DataProvider(name = "testRandomNumber") public static Object[][] testRandomNumber() { return new Object[][]{ - {0, 12, null, null, false, false}, {0, null, 0, 2, true, true}, {0, null, null, null, false, false}, @@ -337,7 +331,6 @@ public static Object[][] testRandomNumber() { {5, 19.123d, -21, 0, true, true}, {5, 20.123d, 0, null, false, false}, {5, 21.123d, 21.122d, 21.124d, false, false}, - }; } @@ -397,8 +390,8 @@ private String toString(Object obj) { if (obj == null) { return "null"; } - return obj.toString(); + return obj.toString(); } private T expectThrows(Class exceptionClass, Runnable runnable) { @@ -411,6 +404,7 @@ private T expectThrows(Class exceptionClass, Runnable r throw new AssertionError("Unexpected exception type", throwable); } } + throw new AssertionError("Expected exception not thrown"); } -} \ No newline at end of file +} diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/LoadMessageFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/LoadMessageFunctionTest.java index 9f1d341c5b..47ad8a9db0 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/LoadMessageFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/LoadMessageFunctionTest.java @@ -16,8 +16,6 @@ package org.citrusframework.functions.core; -import java.util.Collections; - import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.DefaultMessage; @@ -25,6 +23,8 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.util.Collections; + /** * @since 2.6.2 */ @@ -36,27 +36,27 @@ public class LoadMessageFunctionTest extends UnitTestSupport { .setHeader("operation", "sampleOperation"); @Test - public void testLoadMessagePayload() throws Exception { + public void testLoadMessagePayload() { context.getMessageStore().storeMessage("request", message); Assert.assertEquals(function.execute(Collections.singletonList("request"), context), "This is a sample message"); Assert.assertEquals(function.execute(Collections.singletonList("request.body()"), context), "This is a sample message"); } @Test - public void testLoadMessageHeader() throws Exception { + public void testLoadMessageHeader() { context.getMessageStore().storeMessage("request", message); Assert.assertEquals(function.execute(Collections.singletonList("request.header(operation)"), context), "sampleOperation"); Assert.assertEquals(function.execute(Collections.singletonList("request.header('operation')"), context), "sampleOperation"); } @Test(expectedExceptions = CitrusRuntimeException.class, expectedExceptionsMessageRegExp = "Missing header name.*") - public void testLoadMessageHeaderEmpty() throws Exception { + public void testLoadMessageHeaderEmpty() { context.getMessageStore().storeMessage("request", message); function.execute(Collections.singletonList("request.header()"), context); } @Test(expectedExceptions = CitrusRuntimeException.class, expectedExceptionsMessageRegExp = "Failed to find header 'wrong'.*") - public void testLoadMessageHeaderUnknown() throws Exception { + public void testLoadMessageHeaderUnknown() { context.getMessageStore().storeMessage("request", message); function.execute(Collections.singletonList("request.header('wrong')"), context); } diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java index dccbb4b0fc..ce1c67c8ac 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomPatternFunctionTest.java @@ -16,14 +16,15 @@ package org.citrusframework.functions.core; -import static org.testng.Assert.assertTrue; - -import java.util.List; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.util.List; + +import static org.testng.Assert.assertTrue; + public class RandomPatternFunctionTest { private final RandomPatternFunction function = new RandomPatternFunction(); @@ -48,18 +49,18 @@ public void testExecuteWithValidPattern() { @Test(expectedExceptions = IllegalArgumentException.class) public void testExecuteWithInvalidPattern() { - String pattern = "[0-3]([a-c]|[e-g]{1"; // Invalid regex pattern with "Character range is out of order" + String pattern = "[0-3]([a-c]|[e-g]{1"; // Invalid regex pattern with "Character range is out of order" function.execute(List.of(pattern), context); } @DataProvider(name = "patternProvider") public Object[][] patternProvider() { return new Object[][]{ - {"testExecuteWithComplexPattern", "(foo|bar)[0-9]{2,4}"}, - {"testIpv6", "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"}, - {"testIpv4", "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}"}, - {"testEmail", "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}"}, - {"testUri", "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})"} + {"testExecuteWithComplexPattern", "(foo|bar)[0-9]{2,4}"}, + {"testIpv6", "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"}, + {"testIpv4", "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}"}, + {"testEmail", "[a-z]{5,15}\\.?[a-z]{5,15}\\@[a-z]{5,15}\\.[a-z]{2}"}, + {"testUri", "((http|https)://[a-zA-Z0-9-]+(\\.[a-zA-Z]{2,})+(/[a-zA-Z0-9-]+){1,6})|(file:///[a-zA-Z0-9-]+(/[a-zA-Z0-9-]+){1,6})"} }; } @@ -70,6 +71,4 @@ public void testPatterns(String description, String pattern) { assertTrue(result.matches(pattern), "Generated string does not match the pattern: " + description); } } - - } diff --git a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java index 381adc2825..042b54f42d 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/functions/core/RandomStringFunctionTest.java @@ -16,16 +16,16 @@ package org.citrusframework.functions.core; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -import java.util.Set; import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.InvalidFunctionUsageException; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; @@ -138,6 +138,5 @@ public void testRandomSize() { Assert.assertTrue(sizes.contains(8)); Assert.assertTrue(sizes.contains(9)); Assert.assertTrue(sizes.contains(10)); - } -} \ No newline at end of file +} diff --git a/core/citrus-base/src/test/java/org/citrusframework/message/DefaultMessageStoreTest.java b/core/citrus-base/src/test/java/org/citrusframework/message/DefaultMessageStoreTest.java index b0faa45f93..3ffee9bf36 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/message/DefaultMessageStoreTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/message/DefaultMessageStoreTest.java @@ -31,14 +31,14 @@ public class DefaultMessageStoreTest extends UnitTestSupport { private final MessageStore messageStore = new DefaultMessageStore(); @Test - public void testStoreAndGetMessage() throws Exception { + public void testStoreAndGetMessage() { messageStore.storeMessage("request", new DefaultMessage("RequestMessage")); Assert.assertEquals(messageStore.getMessage("request").getPayload(String.class), "RequestMessage"); Assert.assertNull(messageStore.getMessage("unknown")); } @Test - public void testConstructMessageName() throws Exception { + public void testConstructMessageName() { Endpoint endpoint = new DirectEndpoint(); endpoint.setName("testEndpoint"); Assert.assertEquals(messageStore.constructMessageName(new SendMessageAction.Builder().build(), endpoint), "send(testEndpoint)"); diff --git a/core/citrus-base/src/test/java/org/citrusframework/message/correlation/PollingCorrelationManagerTest.java b/core/citrus-base/src/test/java/org/citrusframework/message/correlation/PollingCorrelationManagerTest.java index f816e321e6..d0d10e2e0a 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/message/correlation/PollingCorrelationManagerTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/message/correlation/PollingCorrelationManagerTest.java @@ -29,7 +29,7 @@ public class PollingCorrelationManagerTest { private ObjectStore objectStore = Mockito.mock(ObjectStore.class); @Test - public void testFind() throws Exception { + public void testFind() { DirectSyncEndpointConfiguration pollableEndpointConfiguration = new DirectSyncEndpointConfiguration(); pollableEndpointConfiguration.setPollingInterval(100L); pollableEndpointConfiguration.setTimeout(500L); diff --git a/core/citrus-base/src/test/java/org/citrusframework/report/LoggingReporterTest.java b/core/citrus-base/src/test/java/org/citrusframework/report/LoggingReporterTest.java index 1813104117..a05471ac92 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/report/LoggingReporterTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/report/LoggingReporterTest.java @@ -16,9 +16,6 @@ package org.citrusframework.report; -import java.time.Duration; -import java.util.Locale; - import org.citrusframework.DefaultTestCase; import org.citrusframework.actions.EchoAction; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -29,6 +26,9 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.time.Duration; +import java.util.Locale; + import static java.lang.String.format; import static org.citrusframework.TestResult.failed; import static org.citrusframework.TestResult.skipped; diff --git a/core/citrus-base/src/test/java/org/citrusframework/report/MessageTracingTestListenerTest.java b/core/citrus-base/src/test/java/org/citrusframework/report/MessageTracingTestListenerTest.java index 9239cc659a..798aba387d 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/report/MessageTracingTestListenerTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/report/MessageTracingTestListenerTest.java @@ -16,10 +16,6 @@ package org.citrusframework.report; -import java.io.File; -import java.io.IOException; -import java.util.Scanner; - import org.citrusframework.TestCase; import org.citrusframework.UnitTestSupport; import org.citrusframework.message.RawMessage; @@ -27,6 +23,10 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.io.File; +import java.io.IOException; +import java.util.Scanner; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -43,13 +43,13 @@ public void setupTestling() { } @Test - public void shouldReturnTheSameTraceFile() throws Exception { + public void shouldReturnTheSameTraceFile() { String testname = "SomeDummyTest"; Assert.assertEquals(testling.getTraceFile(testname).getAbsolutePath(), testling.getTraceFile(testname).getAbsolutePath()); } @Test - public void shouldContainMessages() throws Exception { + public void shouldContainMessages() { String testname = "SomeDummyTest"; String inboundPayload = "Inbound Message"; String outboundPayload = "Outbound Message"; diff --git a/core/citrus-base/src/test/java/org/citrusframework/util/FileUtilsTest.java b/core/citrus-base/src/test/java/org/citrusframework/util/FileUtilsTest.java index 2b4da6f619..6c52d67422 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/util/FileUtilsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/util/FileUtilsTest.java @@ -16,20 +16,20 @@ package org.citrusframework.util; -import java.nio.charset.StandardCharsets; - import org.citrusframework.CitrusSettings; import org.citrusframework.UnitTestSupport; import org.citrusframework.spi.Resource; import org.testng.Assert; import org.testng.annotations.Test; +import java.nio.charset.StandardCharsets; + /** * @since 2.7 */ public class FileUtilsTest extends UnitTestSupport { @Test - public void testGetFileResource() throws Exception { + public void testGetFileResource() { Resource resource = FileUtils.getFileResource("classpath:citrus-context.xml", context); Assert.assertNotNull(resource); @@ -37,7 +37,7 @@ public void testGetFileResource() throws Exception { } @Test - public void testGetFileResourceExplicitCharset() throws Exception { + public void testGetFileResourceExplicitCharset() { Resource resource = FileUtils.getFileResource("classpath:citrus-context.xml" + FileUtils.FILE_PATH_CHARSET_PARAMETER + "ISO-8859-1", context); Assert.assertNotNull(resource); @@ -45,13 +45,13 @@ public void testGetFileResourceExplicitCharset() throws Exception { } @Test - public void testGetCharset() throws Exception { + public void testGetCharset() { Assert.assertEquals(FileUtils.getCharset("/path/to/some/file.txt").displayName(), CitrusSettings.CITRUS_FILE_ENCODING); Assert.assertEquals(FileUtils.getCharset("/path/to/some/file.txt" + FileUtils.FILE_PATH_CHARSET_PARAMETER + "ISO-8859-1"), StandardCharsets.ISO_8859_1); } @Test - public void testGetBaseName() throws Exception { + public void testGetBaseName() { Assert.assertNull(FileUtils.getBaseName(null)); Assert.assertEquals(FileUtils.getBaseName(""), ""); Assert.assertEquals(FileUtils.getBaseName("foo"), "foo"); @@ -61,7 +61,7 @@ public void testGetBaseName() throws Exception { } @Test - public void testGetFileName() throws Exception { + public void testGetFileName() { Assert.assertEquals(FileUtils.getFileName(null), ""); Assert.assertEquals(FileUtils.getFileName(""), ""); Assert.assertEquals(FileUtils.getFileName("foo"), "foo"); diff --git a/core/citrus-base/src/test/java/org/citrusframework/util/InvocationDummy.java b/core/citrus-base/src/test/java/org/citrusframework/util/InvocationDummy.java index 8cf2d5e467..be758c3205 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/util/InvocationDummy.java +++ b/core/citrus-base/src/test/java/org/citrusframework/util/InvocationDummy.java @@ -27,44 +27,34 @@ public class InvocationDummy { private static final Logger logger = LoggerFactory.getLogger(InvocationDummy.class); public InvocationDummy() { - if (logger.isDebugEnabled()) { - logger.debug("Constructor without argument"); - } + logger.debug("Constructor without argument"); } public InvocationDummy(String arg) { - if (logger.isDebugEnabled()) { - logger.debug("Constructor with argument: " + arg); - } + logger.debug("Constructor with argument: {}", arg); } public InvocationDummy(Integer arg1, String arg2, Boolean arg3) { if (logger.isDebugEnabled()) { - if (logger.isDebugEnabled()) { - logger.debug("Constructor with arguments:"); - logger.debug("arg1: " + arg1); - logger.debug("arg2: " + arg2); - logger.debug("arg3: " + arg3); - } + logger.debug("Constructor with arguments:"); + logger.debug("arg1: {}", arg1); + logger.debug("arg2: {}", arg2); + logger.debug("arg3: {}", arg3); } } public void invoke() { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke no arguments"); - } + logger.debug("Methode invoke no arguments"); } public void invoke(String text) { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke with string argument: '" + text + "'"); - } + logger.debug("Methode invoke with string argument: '{}'", text); } public void invoke(String[] args) { - for (var arg : args) { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke with argument: " + arg); + if (logger.isDebugEnabled()) { + for (var arg : args) { + logger.debug("Methode invoke with argument: {}", arg); } } } @@ -72,16 +62,16 @@ public void invoke(String[] args) { public void invoke(Integer arg1, String arg2, Boolean arg3) { if (logger.isDebugEnabled()) { logger.debug("Method invoke with arguments:"); - logger.debug("arg1: " + arg1); - logger.debug("arg2: " + arg2); - logger.debug("arg3: " + arg3); + logger.debug("arg1: {}", arg1); + logger.debug("arg2: {}", arg2); + logger.debug("arg3: {}", arg3); } } public static void main(String[] args) { - for (int i = 0; i < args.length; i++) { - if (logger.isDebugEnabled()) { - logger.debug("arg" + i + ": " + args[i]); + if (logger.isDebugEnabled()) { + for (String arg : args) { + logger.debug("arg{}: ", arg); } } } diff --git a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java index 4d0e99f494..a1cf7a9dda 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java @@ -1,5 +1,8 @@ package org.citrusframework.util; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + import static org.citrusframework.util.StringUtils.hasText; import static org.citrusframework.util.StringUtils.isEmpty; import static org.citrusframework.util.StringUtils.quote; @@ -9,9 +12,6 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - public class StringUtilsTest { @DataProvider @@ -38,6 +38,7 @@ public void hasText_returnsTrue(String str) { public void hasText_returnsFalse_forBlankText(String str) { assertFalse(hasText(str)); } + @Test(dataProvider = "emptyText") public void hasText_returnsFalse_forEmptyText(String str) { assertFalse(hasText(str)); @@ -124,13 +125,13 @@ public void testQuoteNullStringFalse() { @DataProvider(name = "trimTrailingCommaDataProvider") public Object[][] trimTrailingCommaDataProvider() { return new Object[][]{ - {new StringBuilder("Example text, "), "Example text"}, - {new StringBuilder("No trailing comma "), "No trailing comma"}, - {new StringBuilder("No trailing comma,\n\t\n "), "No trailing comma"}, - {new StringBuilder("Trailing comma,"), "Trailing comma"}, - {new StringBuilder("Multiple commas and spaces,,, "), "Multiple commas and spaces,,"}, - {new StringBuilder("No trim needed"), "No trim needed"}, - {new StringBuilder(), ""} + {new StringBuilder("Example text, "), "Example text"}, + {new StringBuilder("No trailing comma "), "No trailing comma"}, + {new StringBuilder("No trailing comma,\n\t\n "), "No trailing comma"}, + {new StringBuilder("Trailing comma,"), "Trailing comma"}, + {new StringBuilder("Multiple commas and spaces,,, "), "Multiple commas and spaces,,"}, + {new StringBuilder("No trim needed"), "No trim needed"}, + {new StringBuilder(), ""} }; } @@ -162,26 +163,25 @@ public void testTrimTrailingCommaWithNull() { assertEquals(builder.toString(), ""); } - @DataProvider(name = "titleCaseData") - public Object[][] titleCaseData() { + @DataProvider + public Object[][] convertFirstChartToUpperCaseData() { return new Object[][]{ - {"hello", "Hello"}, - {"h", "H"}, - {"Hello", "Hello"}, - {null, ""}, - {"", ""}, - {"hello world", "Hello world"}, - {" hello", " hello"}, - {"1test", "1test"}, - {"!special", "!special"} + {"hello", "Hello"}, + {"h", "H"}, + {"Hello", "Hello"}, + {null, ""}, + {"", ""}, + {"hello world", "Hello world"}, + {" hello", " hello"}, + {"1test", "1test"}, + {"!special", "!special"} }; } - @Test(dataProvider = "titleCaseData") - public void testTitleCase(String input, String expected) { - String actual = StringUtils.titleCase(input); + @Test(dataProvider = "convertFirstChartToUpperCaseData") + public void testConvertFirstChartToUpperCase(String input, String expected) { + String actual = StringUtils.convertFirstChartToUpperCase(input); assertEquals(actual, expected, - "The titleCase method did not return the expected result."); + "The titleCase method did not return the expected result."); } - } diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultMessageHeaderValidatorTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultMessageHeaderValidatorTest.java index a23f8f800c..234d9457a5 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultMessageHeaderValidatorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultMessageHeaderValidatorTest.java @@ -32,7 +32,7 @@ public class DefaultMessageHeaderValidatorTest extends UnitTestSupport { private HeaderValidationContext validationContext = new HeaderValidationContext(); @Test - public void testValidateNoMessageHeaders() throws Exception { + public void testValidateNoMessageHeaders() { Message receivedMessage = new DefaultMessage("Hello World!"); Message controlMessage = new DefaultMessage("Hello World!"); @@ -40,7 +40,7 @@ public void testValidateNoMessageHeaders() throws Exception { } @Test - public void testValidateMessageHeaders() throws Exception { + public void testValidateMessageHeaders() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("foo", "foo_test") .setHeader("additional", "additional") @@ -53,7 +53,7 @@ public void testValidateMessageHeaders() throws Exception { } @Test - public void testValidateMessageHeadersIgnoreCase() throws Exception { + public void testValidateMessageHeadersIgnoreCase() { try { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("X-Foo", "foo_test") @@ -71,7 +71,7 @@ public void testValidateMessageHeadersIgnoreCase() throws Exception { } @Test(expectedExceptions = ValidationException.class) - public void testValidateMessageHeadersIgnoreCaseError() throws Exception { + public void testValidateMessageHeadersIgnoreCaseError() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("X-Foo", "foo_test") .setHeader("X-Additional", "additional") @@ -84,7 +84,7 @@ public void testValidateMessageHeadersIgnoreCaseError() throws Exception { } @Test - public void testValidateMessageHeadersVariableSupport() throws Exception { + public void testValidateMessageHeadersVariableSupport() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("foo", "foo_test") .setHeader("additional", "additional") @@ -99,7 +99,7 @@ public void testValidateMessageHeadersVariableSupport() throws Exception { } @Test - public void testValidateMessageHeadersMatcherSupport() throws Exception { + public void testValidateMessageHeadersMatcherSupport() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("foo", "foo_test") .setHeader("additional", "additional") @@ -112,7 +112,7 @@ public void testValidateMessageHeadersMatcherSupport() throws Exception { } @Test(expectedExceptions = ValidationException.class) - public void testValidateError() throws Exception { + public void testValidateError() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("foo", "other_value") .setHeader("bar", "bar_test"); @@ -124,7 +124,7 @@ public void testValidateError() throws Exception { } @Test(expectedExceptions = ValidationException.class) - public void testValidateErrorMissingHeader() throws Exception { + public void testValidateErrorMissingHeader() { Message receivedMessage = new DefaultMessage("Hello World!") .setHeader("bar", "bar_test"); Message controlMessage = new DefaultMessage("Hello World!") diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java index 30b947de8b..2102b7998c 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/DefaultTextEqualsMessageValidatorTest.java @@ -16,8 +16,6 @@ package org.citrusframework.validation; -import java.nio.charset.StandardCharsets; - import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.message.DefaultMessage; @@ -27,6 +25,8 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.nio.charset.StandardCharsets; + public class DefaultTextEqualsMessageValidatorTest extends UnitTestSupport { private final DefaultTextEqualsMessageValidator validator = new DefaultTextEqualsMessageValidator(); @@ -41,7 +41,7 @@ public void testValidate(Object received, Object control) { } @Test(dataProvider = "errorTests", expectedExceptions = ValidationException.class) - public void testValidateError(Object received, Object control) throws Exception { + public void testValidateError(Object received, Object control) { Message receivedMessage = new DefaultMessage(received); Message controlMessage = new DefaultMessage(control); diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java index a3edb691a2..cd5803a860 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/MessageValidatorRegistryTest.java @@ -16,11 +16,6 @@ package org.citrusframework.validation; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; @@ -34,6 +29,11 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -118,7 +118,7 @@ public void setupMocks() { } @Test - public void testFindMessageValidators() throws Exception { + public void testFindMessageValidators() { MessageValidatorRegistry messageValidatorRegistry = new MessageValidatorRegistry(); Map> messageValidators = new HashMap<>(); @@ -161,7 +161,7 @@ public void testFindMessageValidators() throws Exception { } @Test - public void testMessageValidatorRegistryXmlConfig() throws Exception { + public void testMessageValidatorRegistryXmlConfig() { //non XML message type List> matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.PLAINTEXT.name(), new DefaultMessage("")); @@ -193,7 +193,7 @@ public void testMessageValidatorRegistryXmlConfig() throws Exception { } @Test - public void testMessageValidatorRegistryJsonConfig() throws Exception { + public void testMessageValidatorRegistryJsonConfig() { //JSON message type and empty payload List> matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.JSON.name(), new DefaultMessage("")); @@ -216,7 +216,7 @@ public void testMessageValidatorRegistryJsonConfig() throws Exception { } @Test - public void testMessageValidatorRegistryPlaintextConfig() throws Exception { + public void testMessageValidatorRegistryPlaintextConfig() { //Plaintext message type and empty payload List> matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.PLAINTEXT.name(), new DefaultMessage("")); @@ -237,7 +237,7 @@ public void testMessageValidatorRegistryPlaintextConfig() throws Exception { } @Test - public void testMessageValidatorRegistryFallback() throws Exception { + public void testMessageValidatorRegistryFallback() { List> matchingValidators = messageValidatorRegistry.findMessageValidators(MessageType.XML.name(), new DefaultMessage("{ \"id\": 12345 }")); Assert.assertNotNull(matchingValidators); @@ -339,7 +339,7 @@ public void shouldAddDefaultEmptyMessagePayloadValidator() { } @Test - public void testSchemaValidators() throws Exception { + public void testSchemaValidators() { MessageValidatorRegistry messageValidatorRegistry = new MessageValidatorRegistry(); Map> schemaValidators = new HashMap<>(); diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/ValidationUtilsTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/ValidationUtilsTest.java index 2d8fe154fe..0160f1dade 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/ValidationUtilsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/ValidationUtilsTest.java @@ -16,10 +16,6 @@ package org.citrusframework.validation; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - import org.citrusframework.UnitTestSupport; import org.citrusframework.context.TestContext; import org.citrusframework.context.TestContextFactory; @@ -29,6 +25,10 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import static org.citrusframework.validation.ValidationUtils.buildValueToBeInCollectionErrorMessage; import static org.testng.Assert.assertEquals; @@ -45,17 +45,17 @@ protected TestContextFactory createTestContextFactory() { } @Test(dataProvider = "testData") - public void testValidateValues(Object actualValue, Object expectedValue, String path) throws Exception { + public void testValidateValues(Object actualValue, Object expectedValue, String path) { ValidationUtils.validateValues(actualValue, expectedValue, path, context); } @Test(dataProvider = "testDataFailed", expectedExceptions = ValidationException.class) - public void testValidateValuesFailure(Object actualValue, Object expectedValue, String path) throws Exception { + public void testValidateValuesFailure(Object actualValue, Object expectedValue, String path) { ValidationUtils.validateValues(actualValue, expectedValue, path, context); } @Test(dataProvider = "testDataTypeFailed", expectedExceptions = ValidationException.class) - public void testValidateValuesTypeFailure(String actualValue, Object expectedValue, String path) throws Exception { + public void testValidateValuesTypeFailure(String actualValue, Object expectedValue, String path) { ValidationUtils.validateValues(actualValue, expectedValue, path, context); } diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/BinaryMessageProcessorTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/BinaryMessageProcessorTest.java index 701b897f53..bf99d1fb68 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/BinaryMessageProcessorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/BinaryMessageProcessorTest.java @@ -16,9 +16,6 @@ package org.citrusframework.validation.interceptor; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.DefaultMessage; @@ -28,6 +25,8 @@ import org.citrusframework.util.FileUtils; import org.testng.annotations.Test; +import java.nio.charset.StandardCharsets; + import static org.testng.Assert.assertEquals; public class BinaryMessageProcessorTest extends UnitTestSupport { @@ -64,7 +63,7 @@ public void testTextMessageIsIntercepted(){ } @Test - public void testResourceMessageWithIsIntercepted() throws IOException { + public void testResourceMessageWithIsIntercepted() { //GIVEN final DefaultMessage message = new DefaultMessage(getTestFile()); diff --git a/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/GzipMessageProcessorTest.java b/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/GzipMessageProcessorTest.java index 0a9092bf0b..fa5fb4a058 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/GzipMessageProcessorTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/validation/interceptor/GzipMessageProcessorTest.java @@ -16,13 +16,6 @@ package org.citrusframework.validation.interceptor; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.zip.GZIPInputStream; -import java.util.zip.GZIPOutputStream; - import org.citrusframework.UnitTestSupport; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.message.DefaultMessage; @@ -33,6 +26,13 @@ import org.testng.Assert; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + import static org.testng.Assert.assertEquals; public class GzipMessageProcessorTest extends UnitTestSupport { @@ -71,7 +71,7 @@ public void testTextMessageIsIntercepted() throws IOException { //THEN assertEquals(message.getType(), MessageType.GZIP.name()); try (ByteArrayOutputStream unzipped = new ByteArrayOutputStream(); - GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)));) { + GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)))) { unzipped.write(gzipInputStream.readAllBytes()); Assert.assertEquals(unzipped.toByteArray(), "foo".getBytes(StandardCharsets.UTF_8)); } @@ -90,7 +90,7 @@ public void testBinaryMessageIsIntercepted() throws IOException { //THEN assertEquals(message.getType(), MessageType.GZIP.name()); try (ByteArrayOutputStream unzipped = new ByteArrayOutputStream(); - GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)));) { + GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)))) { unzipped.write(gzipInputStream.readAllBytes()); Assert.assertEquals(unzipped.toByteArray(), "foo".getBytes(StandardCharsets.UTF_8)); } @@ -109,7 +109,7 @@ public void testInputStreamMessageIsIntercepted() throws IOException { //THEN assertEquals(message.getType(), MessageType.GZIP.name()); try (ByteArrayOutputStream unzipped = new ByteArrayOutputStream(); - GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)));) { + GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)))) { unzipped.write(gzipInputStream.readAllBytes()); Assert.assertEquals(unzipped.toByteArray(), "foo".getBytes(StandardCharsets.UTF_8)); } @@ -128,7 +128,7 @@ public void testResourceMessageIsIntercepted() throws IOException { //THEN assertEquals(message.getType(), MessageType.GZIP.name()); try (ByteArrayOutputStream unzipped = new ByteArrayOutputStream(); - GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)));) { + GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(message.getPayload(byte[].class)))) { unzipped.write(gzipInputStream.readAllBytes()); Assert.assertEquals(unzipped.toByteArray(), FileUtils.copyToByteArray(getTestFile().getInputStream())); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java index f3f685ca46..024ac58f44 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java @@ -59,7 +59,7 @@ import static java.util.stream.Collectors.toMap; import static org.citrusframework.util.ReflectionHelper.copyFields; import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; -import static org.citrusframework.util.StringUtils.titleCase; +import static org.citrusframework.util.StringUtils.convertFirstChartToUpperCase; import static org.openapitools.codegen.CliOption.newString; import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; import static org.openapitools.codegen.utils.StringUtils.camelize; @@ -377,7 +377,7 @@ private void addRestSupportingFiles(String springFolder, String schemaFolder) { supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder, - titleCase(apiPrefix) + "NamespaceHandler.java")); + convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); } @@ -388,16 +388,16 @@ private void addSoapSupportingFiles(String springFolder, String schemaFolder) { apiTemplateFiles().put("api_soap.mustache", ".java"); supportingFiles.add(new SupportingFile("namespace_handler_soap.mustache", springFolder, - titleCase(apiPrefix) + "NamespaceHandler.java")); + convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd")); } private void addDefaultSupportingFiles() { supportingFiles.add(new SupportingFile("api_locator.mustache", invokerFolder, - titleCase(apiPrefix) + ".java")); + convertFirstChartToUpperCase(apiPrefix) + ".java")); supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, - titleCase(apiPrefix) + "BeanConfiguration.java")); + convertFirstChartToUpperCase(apiPrefix) + "BeanConfiguration.java")); } @Override From 04ef7cf82d1bb80e7944c7a5b9f90ca92bda8a96 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 13:32:12 +0200 Subject: [PATCH 22/47] chore(citrus-spring): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-spring` module. --- .../config/ComponentLifecycleProcessor.java | 8 +-- .../config/TestCaseFactory.java | 8 +-- .../handler/CitrusConfigNamespaceHandler.java | 8 +-- .../util/VariableExtractorParserUtil.java | 10 +-- .../xml/AbstractMessageActionParser.java | 59 ++++++++++++++-- .../config/xml/ActionContainerParser.java | 6 +- .../xml/ReceiveMessageActionParser.java | 68 +++++-------------- .../config/xml/SchemaParser.java | 8 +-- .../config/xml/SchemaRepositoryParser.java | 12 ++-- .../config/xml/SendMessageActionParser.java | 44 ++---------- .../config/xml/StartServerActionParser.java | 6 +- .../config/xml/StopServerActionParser.java | 6 +- .../xml/parser/CitrusXmlConfigParser.java | 10 +-- .../context/SpringBeanReferenceResolver.java | 18 ++--- .../util/SpringBeanTypeConverter.java | 22 +++--- .../GlobalVariablesPropertyLoader.java | 25 +++---- .../citrusframework/util/InvocationDummy.java | 44 +++++------- 17 files changed, 161 insertions(+), 201 deletions(-) diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/ComponentLifecycleProcessor.java b/core/citrus-spring/src/main/java/org/citrusframework/config/ComponentLifecycleProcessor.java index 2badf88110..c0cd1ca250 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/ComponentLifecycleProcessor.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/ComponentLifecycleProcessor.java @@ -47,9 +47,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro } if (bean instanceof InitializingPhase) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Initializing component '%s'", beanName)); - } + logger.debug("Initializing component '{}'", beanName); ((InitializingPhase) bean).initialize(); } @@ -59,9 +57,7 @@ public Object postProcessBeforeInitialization(Object bean, String beanName) thro @Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { if (requiresDestruction(bean)) { - if (logger.isDebugEnabled()) { - logger.debug(String.format("Destroying component '%s'", beanName)); - } + logger.debug("Destroying component '{}'", beanName); ((ShutdownPhase) bean).destroy(); } } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/TestCaseFactory.java b/core/citrus-spring/src/main/java/org/citrusframework/config/TestCaseFactory.java index f6c06dc486..008496584c 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/TestCaseFactory.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/TestCaseFactory.java @@ -16,12 +16,12 @@ package org.citrusframework.config; -import java.util.List; - import org.citrusframework.TestAction; import org.citrusframework.TestCase; import org.springframework.beans.factory.FactoryBean; +import java.util.List; + /** * Test case factory bean constructs test cases with test actions and test finally block. * @@ -37,13 +37,13 @@ public class TestCaseFactory implements FactoryBean { @Override public TestCase getObject() throws Exception { - if (this.testActions != null && this.testActions.size() > 0) { + if (this.testActions != null && !this.testActions.isEmpty()) { for (TestAction action : testActions) { testCase.addTestAction(action); } } - if (this.finalActions != null && this.finalActions.size() > 0) { + if (this.finalActions != null && !this.finalActions.isEmpty()) { for (TestAction action : finalActions) { testCase.addFinalAction(action); } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusConfigNamespaceHandler.java b/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusConfigNamespaceHandler.java index be4bb210a6..561add9bc1 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusConfigNamespaceHandler.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/handler/CitrusConfigNamespaceHandler.java @@ -16,8 +16,6 @@ package org.citrusframework.config.handler; -import java.util.Map; - import org.citrusframework.config.xml.DefaultMessageQueueParser; import org.citrusframework.config.xml.DirectEndpointAdapterParser; import org.citrusframework.config.xml.DirectEndpointParser; @@ -44,6 +42,8 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; +import java.util.Map; + /** * Namespace handler for components in Citrus configuration. * @@ -88,9 +88,7 @@ private void lookupBeanDefinitionParser() { actionParserMap.forEach((k, p) -> { registerBeanDefinitionParser(k, p); - if (logger.isDebugEnabled()) { - logger.debug(String.format("Register bean definition parser %s from resource %s", p.getClass(), k)); - } + logger.debug("Register bean definition parser {} from resource {}", p.getClass(), k); }); } } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/util/VariableExtractorParserUtil.java b/core/citrus-spring/src/main/java/org/citrusframework/config/util/VariableExtractorParserUtil.java index dae8b76c38..4ca22c2675 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/util/VariableExtractorParserUtil.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/util/VariableExtractorParserUtil.java @@ -16,15 +16,15 @@ package org.citrusframework.config.util; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import org.citrusframework.validation.DelegatingPayloadVariableExtractor; import org.citrusframework.variable.VariableExtractor; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Helper for parsing 'extract' elements containing nested xpath or json variable-extractors. * @@ -52,7 +52,7 @@ public static void addPayloadVariableExtractors(Element element, List namespaceElements = DomUtils.getChildElementsByTagName(messageElement, "namespace"); - if (namespaceElements.size() > 0) { + if (!namespaceElements.isEmpty()) { for (Object namespaceElementObject : namespaceElements) { Element namespaceElement = (Element) namespaceElementObject; namespaces.put(namespaceElement.getAttribute("prefix"), namespaceElement.getAttribute("value")); diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/AbstractMessageActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/AbstractMessageActionParser.java index 1ac012104d..1409dd283e 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/AbstractMessageActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/AbstractMessageActionParser.java @@ -16,14 +16,9 @@ package org.citrusframework.config.xml; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; - +import org.citrusframework.CitrusSettings; import org.citrusframework.common.Named; +import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.config.xml.parser.CitrusXmlConfigParser; import org.citrusframework.config.xml.parser.ScriptMessageBuilderParser; import org.citrusframework.message.DelegatingPathExpressionProcessor; @@ -47,16 +42,66 @@ import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.BeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.CollectionUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.citrusframework.util.StringUtils.hasText; + /** * Parser providing basic message element configurations used in send and receive actions. * */ public abstract class AbstractMessageActionParser implements BeanDefinitionParser { + protected BeanDefinitionBuilder getBeanDefinitionBuilder(Element element, ParserContext parserContext) { + String endpointUri = parseEndpoint(element); + + BeanDefinitionBuilder builder = parseComponent(element, parserContext); + builder.addPropertyValue("name", element.getLocalName()); + + if (endpointUri.contains(":") || (endpointUri.contains(CitrusSettings.VARIABLE_PREFIX) && endpointUri.contains(CitrusSettings.VARIABLE_SUFFIX))) { + builder.addPropertyValue("endpointUri", endpointUri); + } else { + builder.addPropertyReference("endpoint", endpointUri); + } + + DescriptionElementParser.doParse(element, builder); + + BeanDefinitionParserUtils.setPropertyReference(builder, element.getAttribute("actor"), "actor"); + return builder; + } + + protected String parseEndpoint(Element element) { + String endpointUri = element.getAttribute("endpoint"); + + if (!hasText(endpointUri)) { + throw new BeanCreationException("Endpoint reference must not be empty"); + } + + return endpointUri; + } + + /** + * Parse component returning generic bean definition. + * @param element + * @param parserContext + * @return + */ + protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { + return BeanDefinitionBuilder.genericBeanDefinition(getMessageFactoryClass()); + } + + protected abstract Class getMessageFactoryClass(); + /** * Static parse method taking care of basic message element parsing. * diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ActionContainerParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ActionContainerParser.java index 159986694d..c62353b78b 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ActionContainerParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ActionContainerParser.java @@ -16,8 +16,6 @@ package org.citrusframework.config.xml; -import java.util.List; - import org.citrusframework.config.CitrusNamespaceParserRegistry; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -27,6 +25,8 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.List; + /** * Abstract parser implementation that is aware of several embedded test actions of a container. Bean definitions that use * this parser component must have an 'actions' property of type {@link List} in order to receive the list of embedded test actions. @@ -70,7 +70,7 @@ public static void doParse(Element element, ParserContext parserContext, BeanDef } } - if (actions.size() > 0) { + if (!actions.isEmpty()) { builder.addPropertyValue(propertyName, actions); } } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java index b07b732015..50c2460a1a 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/ReceiveMessageActionParser.java @@ -16,21 +16,9 @@ package org.citrusframework.config.xml; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; - -import org.citrusframework.CitrusSettings; import org.citrusframework.actions.ReceiveMessageAction; -import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.config.util.ValidateMessageParserUtil; import org.citrusframework.config.util.VariableExtractorParserUtil; -import org.citrusframework.util.StringUtils; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.context.SchemaValidationContext; @@ -51,6 +39,15 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; + import static java.lang.Boolean.parseBoolean; import static org.citrusframework.util.StringUtils.hasText; @@ -63,20 +60,7 @@ public class ReceiveMessageActionParser extends AbstractMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - String endpointUri = parseEndpoint(element); - - BeanDefinitionBuilder builder = parseComponent(element, parserContext); - builder.addPropertyValue("name", element.getLocalName()); - - if (endpointUri.contains(":") || (endpointUri.contains(CitrusSettings.VARIABLE_PREFIX) && endpointUri.contains(CitrusSettings.VARIABLE_SUFFIX))) { - builder.addPropertyValue("endpointUri", endpointUri); - } else { - builder.addPropertyReference("endpoint", endpointUri); - } - - DescriptionElementParser.doParse(element, builder); - - BeanDefinitionParserUtils.setPropertyReference(builder, element.getAttribute("actor"), "actor"); + BeanDefinitionBuilder builder = getBeanDefinitionBuilder(element, parserContext); String receiveTimeout = element.getAttribute("timeout"); if (hasText(receiveTimeout)) { @@ -98,15 +82,6 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { return builder.getBeanDefinition(); } - protected String parseEndpoint(Element element) { - String endpointUri = element.getAttribute("endpoint"); - - if (!StringUtils.hasText(endpointUri)) { - throw new BeanCreationException("Endpoint reference must not be empty"); - } - return endpointUri; - } - /** * Parse message validation contexts. * @param messageElement @@ -323,7 +298,7 @@ private JsonPathMessageValidationContext getJsonPathMessageValidationContext(Ele //for now we only handle jsonPath validation Map validateJsonPathExpressions = new HashMap<>(); List validateElements = DomUtils.getChildElementsByTagName(messageElement, "validate"); - if (validateElements.size() > 0) { + if (!validateElements.isEmpty()) { for (Element validateElement : validateElements) { extractJsonPathValidateExpressions(validateElement, validateJsonPathExpressions); } @@ -390,16 +365,17 @@ private void parseNamespaceValidationElements(Element messageElement, XmlMessage Map validateNamespaces = new HashMap<>(); List validateElements = DomUtils.getChildElementsByTagName(messageElement, "validate"); - if (validateElements.size() > 0) { + if (!validateElements.isEmpty()) { for (Element validateElement : validateElements) { //check for namespace validation elements List validateNamespaceElements = DomUtils.getChildElementsByTagName(validateElement, "namespace"); - if (validateNamespaceElements.size() > 0) { + if (!validateNamespaceElements.isEmpty()) { for (Element namespaceElement : validateNamespaceElements) { validateNamespaces.put(namespaceElement.getAttribute("prefix"), namespaceElement.getAttribute("value")); } } } + context.namespaces(validateNamespaces); } } @@ -416,7 +392,7 @@ private void parseXPathValidationElements(Element messageElement, XpathMessageVa Map validateXpathExpressions = new HashMap<>(); List validateElements = DomUtils.getChildElementsByTagName(messageElement, "validate"); - if (validateElements.size() > 0) { + if (!validateElements.isEmpty()) { for (Element validateElement : validateElements) { extractXPathValidateExpressions(validateElement, validateXpathExpressions); } @@ -466,8 +442,7 @@ private void extractXPathValidateExpressions( * @param validateElement * @param validateJsonPathExpressions */ - private void extractJsonPathValidateExpressions( - Element validateElement, Map validateJsonPathExpressions) { + private void extractJsonPathValidateExpressions(Element validateElement, Map validateJsonPathExpressions) { //check for jsonPath validation - old style with direct attribute String pathExpression = validateElement.getAttribute("path"); if (JsonPathMessageValidationContext.isJsonPathExpression(pathExpression)) { @@ -478,16 +453,7 @@ private void extractJsonPathValidateExpressions( ValidateMessageParserUtil.parseJsonPathElements(validateElement, validateJsonPathExpressions); } - /** - * Parse component returning generic bean definition. - * - * @param element - * @return - */ - protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { - return BeanDefinitionBuilder.genericBeanDefinition(getMessageFactoryClass()); - } - + @Override protected Class getMessageFactoryClass() { return ReceiveMessageActionFactoryBean.class; } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaParser.java index 461bbfbc73..fd5e7e8fad 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaParser.java @@ -16,9 +16,6 @@ package org.citrusframework.config.xml; -import java.util.HashMap; -import java.util.Map; - import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.util.FileUtils; import org.slf4j.Logger; @@ -28,6 +25,9 @@ import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; +import java.util.HashMap; +import java.util.Map; + /** * Bean definition parser for schema configuration. * @@ -68,7 +68,7 @@ private BeanDefinitionParser lookupSchemaParser(String location) { } BeanDefinitionParser parser = TYPE_RESOLVER.resolve(fileExtension); - logger.info(String.format("Found schema bean definition parser %s from resource %s", parser.getClass(), RESOURCE_PATH + "/" + fileExtension)); + logger.info("Found schema bean definition parser {} from resource {}", parser.getClass(), RESOURCE_PATH + "/" + fileExtension); SCHEMA_PARSER.put(fileExtension, parser); return parser; } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaRepositoryParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaRepositoryParser.java index 98c9e95cec..2a9a2fd41c 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaRepositoryParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SchemaRepositoryParser.java @@ -16,11 +16,6 @@ package org.citrusframework.config.xml; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.util.StringUtils; import org.slf4j.Logger; @@ -34,6 +29,11 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + /** * Bean definition parser for schema-repository configuration. * @@ -84,7 +84,7 @@ private BeanDefinitionParser lookupSchemaRepositoryParser(String type) { } BeanDefinitionParser parser = TYPE_RESOLVER.resolve(type); - logger.info(String.format("Found schema repository bean definition parser %s from resource %s", parser.getClass(), RESOURCE_PATH + "/" + type)); + logger.info("Found schema repository bean definition parser {} from resource {}", parser.getClass(), RESOURCE_PATH + "/" + type); SCHEMA_REPOSITORY_PARSER.put(type, parser); return parser; } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java index 6e05883f0f..470f57da33 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/SendMessageActionParser.java @@ -16,24 +16,22 @@ package org.citrusframework.config.xml; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.message.MessageBuilder; import org.citrusframework.util.StringUtils; import org.citrusframework.validation.builder.DefaultMessageBuilder; import org.citrusframework.variable.VariableExtractor; -import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + /** * Bean definition parser for send action in test case. * @@ -42,19 +40,7 @@ public class SendMessageActionParser extends AbstractMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - String endpointUri = parseEndpoint(element); - - BeanDefinitionBuilder builder = parseComponent(element, parserContext); - builder.addPropertyValue("name", element.getLocalName()); - - if (endpointUri.contains(":") || (endpointUri.contains(CitrusSettings.VARIABLE_PREFIX) && endpointUri.contains(CitrusSettings.VARIABLE_SUFFIX))) { - builder.addPropertyValue("endpointUri", endpointUri); - } else { - builder.addPropertyReference("endpoint", endpointUri); - } - - DescriptionElementParser.doParse(element, builder); - BeanDefinitionParserUtils.setPropertyReference(builder, element.getAttribute("actor"), "actor"); + BeanDefinitionBuilder builder = getBeanDefinitionBuilder(element, parserContext); BeanDefinitionParserUtils.setPropertyValue(builder, element.getAttribute("fork"), "forkMode"); Element messageElement = DomUtils.getChildElementByTagName(element, "message"); @@ -105,28 +91,10 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { return builder.getBeanDefinition(); } - protected String parseEndpoint(Element element) { - String endpointUri = element.getAttribute("endpoint"); - - if (!StringUtils.hasText(endpointUri)) { - throw new BeanCreationException("Endpoint reference must not be empty"); - } - return endpointUri; - } - - /** - * Parse component returning generic bean definition. - * @param element - * @param parserContext - * @return - */ - protected BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { - return BeanDefinitionBuilder.genericBeanDefinition(getMessageFactoryClass()); - } - /** * Gets the bean definition builder class. */ + @Override protected Class> getMessageFactoryClass() { return SendMessageActionFactoryBean.class; } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StartServerActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StartServerActionParser.java index 898c0b2cce..7d4c1db69e 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StartServerActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StartServerActionParser.java @@ -16,8 +16,6 @@ package org.citrusframework.config.xml; -import java.util.List; - import org.citrusframework.actions.StartServerAction; import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.server.Server; @@ -30,6 +28,8 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.List; + /** * @since 2.2 */ @@ -47,7 +47,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { Element serversElement = DomUtils.getChildElementByTagName(element, "servers"); if (serversElement != null) { List serverElements = DomUtils.getChildElementsByTagName(serversElement, "server"); - if (serverElements.size() > 0) { + if (!serverElements.isEmpty()) { for (Element serverElement : serverElements) { servers.add(new RuntimeBeanReference(serverElement.getAttribute("name"))); } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StopServerActionParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StopServerActionParser.java index 6310de499f..b2539b4d20 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StopServerActionParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/StopServerActionParser.java @@ -16,8 +16,6 @@ package org.citrusframework.config.xml; -import java.util.List; - import org.citrusframework.actions.StopServerAction; import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.server.Server; @@ -30,6 +28,8 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.List; + /** * @since 2.2 */ @@ -47,7 +47,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { Element serversElement = DomUtils.getChildElementByTagName(element, "servers"); if (serversElement != null) { List serverElements = DomUtils.getChildElementsByTagName(serversElement, "server"); - if (serverElements.size() > 0) { + if (!serverElements.isEmpty()) { for (Element serverElement : serverElements) { servers.add(new RuntimeBeanReference(serverElement.getAttribute("name"))); } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/parser/CitrusXmlConfigParser.java b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/parser/CitrusXmlConfigParser.java index 72fb4ef8ca..cc4301f812 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/config/xml/parser/CitrusXmlConfigParser.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/config/xml/parser/CitrusXmlConfigParser.java @@ -16,15 +16,15 @@ package org.citrusframework.config.xml.parser; -import java.util.Map; -import java.util.Optional; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ResourcePathTypeResolver; import org.citrusframework.spi.TypeResolver; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Map; +import java.util.Optional; + public interface CitrusXmlConfigParser { /** Logger */ @@ -45,7 +45,7 @@ static Map lookup(String category) { Map parser = TYPE_RESOLVER.resolveAll(category, TypeResolver.DEFAULT_TYPE_PROPERTY, null); if (logger.isDebugEnabled()) { - parser.forEach((k, v) -> logger.debug(String.format("Found XML config parser '%s/%s' as %s", category, k, v.getClass()))); + parser.forEach((k, v) -> logger.debug("Found XML config parser '{}/{}' as {}", category, k, v.getClass())); } return parser; @@ -64,7 +64,7 @@ static Optional lookup(String category, String name) { T instance = TYPE_RESOLVER.resolve(category + "/" + name); return Optional.of(instance); } catch (CitrusRuntimeException e) { - logger.warn(String.format("Failed to resolve XML config parser from resource '%s/%s/%s'", RESOURCE_PATH, category, name)); + logger.warn("Failed to resolve XML config parser from resource '{}/{}/{}'", RESOURCE_PATH, category, name); } return Optional.empty(); diff --git a/core/citrus-spring/src/main/java/org/citrusframework/context/SpringBeanReferenceResolver.java b/core/citrus-spring/src/main/java/org/citrusframework/context/SpringBeanReferenceResolver.java index 641716e76e..9b2f03f9e4 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/context/SpringBeanReferenceResolver.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/context/SpringBeanReferenceResolver.java @@ -16,13 +16,6 @@ package org.citrusframework.context; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; - import org.citrusframework.context.resolver.TypeAliasResolver; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ReferenceResolver; @@ -34,6 +27,13 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; + /** * Spring bean reference resolver operates on given application context to resolve bean references. * @@ -209,7 +209,7 @@ private Optional resolveAlias(Class source, Function, ?> supp try { return Optional.of(resolver.adapt(supplier.apply(resolver.getAliasType()))); } catch (Exception e) { - logger.warn(String.format("Unable to resolve alias type %s for required source %s", resolver.getAliasType(), source)); + logger.warn("Unable to resolve alias type {} for required source {}", resolver.getAliasType(), source); return Optional.empty(); } } @@ -238,7 +238,7 @@ private Optional> resolveAllAlias(Class source, Function resolver.adapt(v.getValue())))); } catch (Exception e) { - logger.warn(String.format("Unable to resolve alias type %s for required source %s", resolver.getAliasType(), source)); + logger.warn("Unable to resolve alias type {} for required source {}", resolver.getAliasType(), source); return Optional.empty(); } } diff --git a/core/citrus-spring/src/main/java/org/citrusframework/util/SpringBeanTypeConverter.java b/core/citrus-spring/src/main/java/org/citrusframework/util/SpringBeanTypeConverter.java index 67c32c0be1..5892c5da8f 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/util/SpringBeanTypeConverter.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/util/SpringBeanTypeConverter.java @@ -16,16 +16,6 @@ package org.citrusframework.util; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; -import java.util.Map; -import java.util.Optional; -import java.util.Properties; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - import org.citrusframework.exceptions.CitrusRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,10 +25,20 @@ import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringReader; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + public final class SpringBeanTypeConverter extends DefaultTypeConverter { /** Logger */ - private static final Logger logger = LoggerFactory.getLogger(DefaultTypeConverter.class); + private static final Logger logger = LoggerFactory.getLogger(SpringBeanTypeConverter.class); public static SpringBeanTypeConverter INSTANCE = new SpringBeanTypeConverter(); diff --git a/core/citrus-spring/src/main/java/org/citrusframework/variable/GlobalVariablesPropertyLoader.java b/core/citrus-spring/src/main/java/org/citrusframework/variable/GlobalVariablesPropertyLoader.java index ad70028756..03e5047314 100644 --- a/core/citrus-spring/src/main/java/org/citrusframework/variable/GlobalVariablesPropertyLoader.java +++ b/core/citrus-spring/src/main/java/org/citrusframework/variable/GlobalVariablesPropertyLoader.java @@ -16,12 +16,6 @@ package org.citrusframework.variable; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.functions.FunctionRegistry; @@ -33,6 +27,12 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + /** * Loads properties from an external property file and creates global test variables. * @@ -69,7 +69,7 @@ public void afterPropertiesSet() { throw new CitrusRuntimeException(String.format("Error while loading property file %s - does not exist", propertyFile.getLocation())); } - logger.debug("Reading property file " + propertyFile.getLocation()); + logger.debug("Reading property file {}", propertyFile.getLocation()); // Use input stream as this also allows to read from resources in a JAR file reader = new BufferedReader(new InputStreamReader(propertyFile.getInputStream())); @@ -98,13 +98,10 @@ public void afterPropertiesSet() { logger.debug("Property value replace dynamic content [ {} ]", value); value = context.replaceDynamicContentInString(value); - if (logger.isDebugEnabled()) { - logger.debug("Loading property: " + key + "=" + value + " into default variables"); - } + logger.debug("Loading property: {}={} into default variables", key, value); if (logger.isDebugEnabled() && globalVariables.getVariables().containsKey(key)) { - logger.debug("Overwriting property " + key + " old value:" + globalVariables.getVariables().get(key) - + " new value:" + value); + logger.debug("Overwriting property {} old value:{} new value:{}", key, globalVariables.getVariables().get(key), value); } globalVariables.getVariables().put(key, value); @@ -112,7 +109,7 @@ public void afterPropertiesSet() { context.setVariable(key, globalVariables.getVariables().get(key)); } - logger.info("Loaded property file " + propertyFile.getLocation()); + logger.info("Loaded property file {}", propertyFile.getLocation()); } } } catch (IOException e) { @@ -129,7 +126,7 @@ public void afterPropertiesSet() { } private boolean propertyFilesSet() { - return propertyFiles != null && propertyFiles.size() > 0; + return propertyFiles != null && !propertyFiles.isEmpty(); } private boolean isPropertyLine(String line) { diff --git a/core/citrus-spring/src/test/java/org/citrusframework/util/InvocationDummy.java b/core/citrus-spring/src/test/java/org/citrusframework/util/InvocationDummy.java index 8cf2d5e467..a352f894fd 100644 --- a/core/citrus-spring/src/test/java/org/citrusframework/util/InvocationDummy.java +++ b/core/citrus-spring/src/test/java/org/citrusframework/util/InvocationDummy.java @@ -27,44 +27,34 @@ public class InvocationDummy { private static final Logger logger = LoggerFactory.getLogger(InvocationDummy.class); public InvocationDummy() { - if (logger.isDebugEnabled()) { - logger.debug("Constructor without argument"); - } + logger.debug("Constructor without argument"); } public InvocationDummy(String arg) { - if (logger.isDebugEnabled()) { - logger.debug("Constructor with argument: " + arg); - } + logger.debug("Constructor with argument: {}", arg); } public InvocationDummy(Integer arg1, String arg2, Boolean arg3) { if (logger.isDebugEnabled()) { - if (logger.isDebugEnabled()) { - logger.debug("Constructor with arguments:"); - logger.debug("arg1: " + arg1); - logger.debug("arg2: " + arg2); - logger.debug("arg3: " + arg3); - } + logger.debug("Constructor with arguments:"); + logger.debug("arg1: {}", arg1); + logger.debug("arg2: {}", arg2); + logger.debug("arg3: {}", arg3); } } public void invoke() { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke no arguments"); - } + logger.debug("Methode invoke no arguments"); } public void invoke(String text) { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke with string argument: '" + text + "'"); - } + logger.debug("Methode invoke with string argument: '{}'", text); } public void invoke(String[] args) { - for (var arg : args) { - if (logger.isDebugEnabled()) { - logger.debug("Methode invoke with argument: " + arg); + if (logger.isDebugEnabled()) { + for (var arg : args) { + logger.debug("Methode invoke with argument: {}", arg); } } } @@ -72,16 +62,16 @@ public void invoke(String[] args) { public void invoke(Integer arg1, String arg2, Boolean arg3) { if (logger.isDebugEnabled()) { logger.debug("Method invoke with arguments:"); - logger.debug("arg1: " + arg1); - logger.debug("arg2: " + arg2); - logger.debug("arg3: " + arg3); + logger.debug("arg1: {}", arg1); + logger.debug("arg2: {}", arg2); + logger.debug("arg3: {}", arg3); } } public static void main(String[] args) { - for (int i = 0; i < args.length; i++) { - if (logger.isDebugEnabled()) { - logger.debug("arg" + i + ": " + args[i]); + if (logger.isDebugEnabled()) { + for (int i = 0; i < args.length; i++) { + logger.debug("arg{}: {}", i, args[i]); } } } From 93eb1499f0305add463514aa76af93fc563b52ab Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 14:35:58 +0200 Subject: [PATCH 23/47] chore(citrus-http): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-http` module. --- .../http/config/xml/CookieUtils.java | 42 +++++++++++++++++++ .../xml/HttpReceiveResponseActionParser.java | 29 ++----------- .../xml/HttpSendRequestActionParser.java | 20 ++++----- .../xml/HttpSendResponseActionParser.java | 27 +----------- .../interceptor/LoggingClientInterceptor.java | 8 +--- .../LoggingHandlerInterceptor.java | 14 +++---- .../http/message/HttpMessageUtils.java | 23 +++++----- .../HttpQueryParamHeaderValidator.java | 30 ++++++------- .../server/AbstractHttpServerBuilder.java | 2 +- .../http/server/HttpServer.java | 1 - .../CachingHttpServletRequestWrapper.java | 30 +++++-------- .../FormUrlEncodedMessageValidator.java | 26 ++++++------ .../integration/HttpMessageControllerIT.java | 1 + .../HttpServerStandaloneJavaIT.java | 8 ++-- .../http/message/HttpMessageUtilsTest.java | 27 ++++++------ .../HttpQueryParamHeaderValidatorTest.java | 5 +-- .../CachingHttpServletRequestWrapperTest.java | 20 ++++----- 17 files changed, 147 insertions(+), 166 deletions(-) create mode 100644 endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/CookieUtils.java diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/CookieUtils.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/CookieUtils.java new file mode 100644 index 0000000000..82a25f7acf --- /dev/null +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/CookieUtils.java @@ -0,0 +1,42 @@ +package org.citrusframework.http.config.xml; + +import jakarta.servlet.http.Cookie; +import org.citrusframework.http.message.HttpMessage; +import org.w3c.dom.Element; + +import java.util.List; + +import static java.lang.Boolean.parseBoolean; +import static java.lang.Integer.parseInt; + +final class CookieUtils { + + private CookieUtils() { + // Static utility class + } + + static void setCookieElement(HttpMessage httpMessage, List cookieElements) { + for (Object item : cookieElements) { + Element cookieElement = (Element) item; + Cookie cookie = new Cookie(cookieElement.getAttribute("name"), cookieElement.getAttribute("value")); + + if (cookieElement.hasAttribute("path")) { + cookie.setPath(cookieElement.getAttribute("path")); + } + + if (cookieElement.hasAttribute("domain")) { + cookie.setDomain(cookieElement.getAttribute("domain")); + } + + if (cookieElement.hasAttribute("max-age")) { + cookie.setMaxAge(parseInt(cookieElement.getAttribute("max-age"))); + } + + if (cookieElement.hasAttribute("secure")) { + cookie.setSecure(parseBoolean(cookieElement.getAttribute("secure"))); + } + + httpMessage.cookie(cookie); + } + } +} diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java index 830d55cde2..a5ed612497 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpReceiveResponseActionParser.java @@ -16,7 +16,6 @@ package org.citrusframework.http.config.xml; -import jakarta.servlet.http.Cookie; import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.config.xml.DescriptionElementParser; import org.citrusframework.config.xml.ReceiveMessageActionParser; @@ -36,8 +35,8 @@ import java.util.List; import static java.lang.Boolean.parseBoolean; -import static java.lang.Integer.parseInt; import static org.citrusframework.config.xml.MessageSelectorParser.doParse; +import static org.citrusframework.http.config.xml.CookieUtils.setCookieElement; import static org.springframework.util.xml.DomUtils.getChildElementByTagName; import static org.springframework.util.xml.DomUtils.getChildElementsByTagName; @@ -103,28 +102,7 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, } List cookieElements = getChildElementsByTagName(headers, "cookie"); - for (Object item : cookieElements) { - Element cookieElement = (Element) item; - Cookie cookie = new Cookie(cookieElement.getAttribute("name"), cookieElement.getAttribute("value")); - - if (cookieElement.hasAttribute("path")) { - cookie.setPath(cookieElement.getAttribute("path")); - } - - if (cookieElement.hasAttribute("domain")) { - cookie.setDomain(cookieElement.getAttribute("domain")); - } - - if (cookieElement.hasAttribute("max-age")) { - cookie.setMaxAge(parseInt(cookieElement.getAttribute("max-age"))); - } - - if (cookieElement.hasAttribute("secure")) { - cookie.setSecure(parseBoolean(cookieElement.getAttribute("secure"))); - } - - httpMessage.cookie(cookie); - } + setCookieElement(httpMessage, cookieElements); boolean ignoreCase = !headers.hasAttribute("ignore-case") || parseBoolean(headers.getAttribute("ignore-case")); validationContexts.stream() @@ -135,8 +113,7 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, doParse(element, builder); - HttpMessageBuilder httpMessageBuilder = createMessageBuilder( - httpMessage); + HttpMessageBuilder httpMessageBuilder = createMessageBuilder(httpMessage); DefaultMessageBuilder messageContentBuilder = constructMessageBuilder(body, builder); httpMessageBuilder.setName(messageContentBuilder.getName()); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java index 7e20f95750..4b886b437f 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendRequestActionParser.java @@ -16,9 +16,6 @@ package org.citrusframework.http.config.xml; -import java.util.ArrayList; -import java.util.List; - import jakarta.servlet.http.Cookie; import org.citrusframework.config.util.BeanDefinitionParserUtils; import org.citrusframework.config.xml.DescriptionElementParser; @@ -37,6 +34,9 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; +import java.util.ArrayList; +import java.util.List; + /** * @since 2.4 */ @@ -44,13 +44,11 @@ public class HttpSendRequestActionParser extends SendMessageActionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) { - BeanDefinitionBuilder builder = createBeanDefinitionBuilder( - element, parserContext); + BeanDefinitionBuilder builder = createBeanDefinitionBuilder(element, parserContext); return builder.getBeanDefinition(); } - protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, - ParserContext parserContext) { + protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, ParserContext parserContext) { BeanDefinitionBuilder builder = parseComponent(element, parserContext); builder.addPropertyValue("name", "http:" + element.getLocalName()); @@ -146,8 +144,7 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, } } - HttpMessageBuilder httpMessageBuilder = createMessageBuilder( - httpMessage); + HttpMessageBuilder httpMessageBuilder = createMessageBuilder(httpMessage); DefaultMessageBuilder messageContentBuilder = constructMessageBuilder(body, builder); httpMessageBuilder.setName(messageContentBuilder.getName()); @@ -162,6 +159,7 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, if (!variableExtractors.isEmpty()) { builder.addPropertyValue("variableExtractors", variableExtractors); } + return builder; } @@ -169,12 +167,12 @@ protected Element getRequestElement(Element element) { if (element.hasChildNodes()) { return DomUtils.getChildElements(element).get(0); } + throw new BeanCreationException("No request element specified for http send - invalid test action definition"); } protected Element getHeadersElement(Element requestElement) { - Element headers = DomUtils.getChildElementByTagName(requestElement, "headers"); - return headers; + return DomUtils.getChildElementByTagName(requestElement, "headers"); } /** diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendResponseActionParser.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendResponseActionParser.java index 809024d9a8..0a4a96df3b 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendResponseActionParser.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/config/xml/HttpSendResponseActionParser.java @@ -16,7 +16,6 @@ package org.citrusframework.http.config.xml; -import jakarta.servlet.http.Cookie; import org.citrusframework.config.xml.SendMessageActionParser; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; @@ -30,10 +29,9 @@ import java.util.List; -import static java.lang.Boolean.parseBoolean; -import static java.lang.Integer.parseInt; import static org.citrusframework.config.util.BeanDefinitionParserUtils.setPropertyReference; import static org.citrusframework.config.xml.DescriptionElementParser.doParse; +import static org.citrusframework.http.config.xml.CookieUtils.setCookieElement; import static org.citrusframework.util.StringUtils.hasText; /** @@ -78,28 +76,7 @@ public BeanDefinition parse(Element element, ParserContext parserContext) { } List cookieElements = DomUtils.getChildElementsByTagName(headers, "cookie"); - for (Object item : cookieElements) { - Element cookieElement = (Element) item; - Cookie cookie = new Cookie(cookieElement.getAttribute("name"), cookieElement.getAttribute("value")); - - if (cookieElement.hasAttribute("path")) { - cookie.setPath(cookieElement.getAttribute("path")); - } - - if (cookieElement.hasAttribute("domain")) { - cookie.setDomain(cookieElement.getAttribute("domain")); - } - - if (cookieElement.hasAttribute("max-age")) { - cookie.setMaxAge(parseInt(cookieElement.getAttribute("max-age"))); - } - - if (cookieElement.hasAttribute("secure")) { - cookie.setSecure(parseBoolean(cookieElement.getAttribute("secure"))); - } - - httpMessage.cookie(cookie); - } + setCookieElement(httpMessage, cookieElements); } Element body = DomUtils.getChildElementByTagName(element, "body"); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingClientInterceptor.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingClientInterceptor.java index 6d6f26554a..150530fb05 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingClientInterceptor.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingClientInterceptor.java @@ -82,9 +82,7 @@ public void handleRequest(String request) { logger.debug("Sending Http request message"); messageListener.onOutboundMessage(new RawMessage(request), contextFactory.getObject()); } else { - if (logger.isDebugEnabled()) { - logger.debug("Sending Http request message:" + NEWLINE + request); - } + logger.debug("Sending Http request message:{}{}", NEWLINE, request); } } @@ -98,9 +96,7 @@ public void handleResponse(String response) { logger.debug("Received Http response message"); messageListener.onInboundMessage(new RawMessage(response), contextFactory.getObject()); } else { - if (logger.isDebugEnabled()) { - logger.debug("Received Http response message:" + NEWLINE + response); - } + logger.debug("Received Http response message:{}{}", NEWLINE, response); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingHandlerInterceptor.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingHandlerInterceptor.java index d8288b6c39..f333335497 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingHandlerInterceptor.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/interceptor/LoggingHandlerInterceptor.java @@ -18,9 +18,6 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Enumeration; - import org.citrusframework.context.TestContextFactory; import org.citrusframework.http.controller.HttpMessageController; import org.citrusframework.message.RawMessage; @@ -33,6 +30,9 @@ import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; +import java.io.IOException; +import java.util.Enumeration; + import static java.lang.System.lineSeparator; /** @@ -80,9 +80,7 @@ public void handleRequest(String request) { logger.debug("Received Http request"); messageListener.onInboundMessage(new RawMessage(request), contextFactory.getObject()); } else { - if (logger.isDebugEnabled()) { - logger.debug("Received Http request:" + NEWLINE + request); - } + logger.debug("Received Http request:{}{}", NEWLINE, request); } } @@ -95,9 +93,7 @@ public void handleResponse(String response) { logger.debug("Sending Http response"); messageListener.onOutboundMessage(new RawMessage(response), contextFactory.getObject()); } else { - if (logger.isDebugEnabled()) { - logger.debug("Sending Http response:" + NEWLINE + response); - } + logger.debug("Sending Http response:{}{}", NEWLINE, response); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java index dc6269b8f4..de22dc95a1 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageUtils.java @@ -16,17 +16,20 @@ package org.citrusframework.http.message; -import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_QUERY_PARAMS; -import static org.citrusframework.util.StringUtils.hasText; +import org.apache.commons.lang3.tuple.Pair; +import org.citrusframework.message.Message; +import org.citrusframework.message.MessageHeaders; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; -import org.apache.commons.lang3.tuple.Pair; -import org.citrusframework.message.Message; -import org.citrusframework.message.MessageHeaders; + +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.groupingBy; +import static java.util.stream.Collectors.mapping; +import static java.util.stream.Collectors.toList; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_QUERY_PARAMS; +import static org.citrusframework.util.StringUtils.hasText; /** * @since 2.7.5 @@ -95,9 +98,9 @@ public static Map> getQueryParameterMap(HttpMessage httpMes String value = keyAndValue.length > 1 ? keyAndValue[1] : ""; return Pair.of(key, value); }) - .collect(Collectors.groupingBy( - Pair::getLeft, Collectors.mapping(Pair::getRight, Collectors.toList()))); + .collect(groupingBy(Pair::getLeft,mapping(Pair::getRight,toList()))); } - return Collections.emptyMap(); + + return emptyMap(); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java index 8b1545e5d5..2d32f076e9 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpQueryParamHeaderValidator.java @@ -16,19 +16,22 @@ package org.citrusframework.http.message; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.ValidationException; -import org.citrusframework.util.StringUtils; import org.citrusframework.validation.DefaultHeaderValidator; import org.citrusframework.validation.context.HeaderValidationContext; import org.citrusframework.validation.matcher.ValidationMatcherUtils; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.toMap; +import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_QUERY_PARAMS; +import static org.citrusframework.util.StringUtils.hasText; + /** * @since 2.7.6 */ @@ -39,7 +42,7 @@ public void validateHeader(String name, Object received, Object control, TestCon if (ValidationMatcherUtils.isValidationMatcherExpression(Optional.ofNullable(control) .map(Object::toString) .orElse(""))) { - super.validateHeader(HttpMessageHeaders.HTTP_QUERY_PARAMS, received, control, context, validationContext); + super.validateHeader(HTTP_QUERY_PARAMS, received, control, context, validationContext); return; } @@ -54,9 +57,8 @@ public void validateHeader(String name, Object received, Object control, TestCon throw new ValidationException("Validation failed: Query param '" + param.getKey() + "' is missing"); } - super.validateHeaderArray(HttpMessageHeaders.HTTP_QUERY_PARAMS + "(" + param.getKey() + ")", receiveParams.get(param.getKey()), param.getValue(), context, validationContext); + super.validateHeaderArray(HTTP_QUERY_PARAMS + "(" + param.getKey() + ")", receiveParams.get(param.getKey()), param.getValue(), context, validationContext); } - } /** @@ -64,7 +66,6 @@ public void validateHeader(String name, Object received, Object control, TestCon * encoded in the expression. */ private Map convertToMap(Object expression) { - if (expression instanceof Map) { return (Map) expression; } @@ -74,8 +75,8 @@ private Map convertToMap(Object expression) { .orElse("") .split(",")) .map(keyValue -> keyValue.split("=")) - .filter(keyValue -> StringUtils.hasText(keyValue[0])) - .collect(Collectors.toMap( + .filter(keyValue -> hasText(keyValue[0])) + .collect(toMap( keyValue -> keyValue[0], // Key function keyValue -> // Value function: if no value is present, use an empty string @@ -93,11 +94,10 @@ private Map convertToMap(Object expression) { } } )); - } @Override public boolean supports(String headerName, Class type) { - return headerName.equals(HttpMessageHeaders.HTTP_QUERY_PARAMS); + return headerName.equals(HTTP_QUERY_PARAMS); } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java index 0592b890e9..68fbc42d68 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/AbstractHttpServerBuilder.java @@ -251,7 +251,7 @@ public B handleCookies(boolean flag) { } /** - * Sets the handleCookies property. + * Sets the semicolon handling property. * * @param flag * @return diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java index 7f8edfdb4c..dd69a926bd 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/server/HttpServer.java @@ -668,7 +668,6 @@ public void setHandleSemicolonPathContent(boolean handleSemicolonPathContent) { this.handleSemicolonPathContent = handleSemicolonPathContent; } - /** * Gets the response cache size. * diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapper.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapper.java index 56ea78eaf8..805c329540 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapper.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapper.java @@ -16,16 +16,6 @@ package org.citrusframework.http.servlet; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.StringTokenizer; - import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; @@ -40,6 +30,15 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestMethod; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.StringTokenizer; + /** * Caching wrapper saves request body data to cache when read. */ @@ -129,15 +128,8 @@ private void fillParams(final Map params, final String querySt paramValue = ""; } - try { - params.put(URLDecoder.decode(paramName, charset.name()), - new String[] { URLDecoder.decode(paramValue, charset.name()) }); - } catch (final UnsupportedEncodingException e) { - throw new CitrusRuntimeException(String.format( - "Failed to decode query param value '%s=%s'", - paramName, - paramValue), e); - } + params.put(URLDecoder.decode(paramName, charset), + new String[] { URLDecoder.decode(paramValue, charset) }); } } } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/validation/FormUrlEncodedMessageValidator.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/validation/FormUrlEncodedMessageValidator.java index 1619c97b3b..ec59aed613 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/validation/FormUrlEncodedMessageValidator.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/validation/FormUrlEncodedMessageValidator.java @@ -16,16 +16,6 @@ package org.citrusframework.http.validation; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.StringTokenizer; -import java.util.stream.Collectors; - import org.citrusframework.CitrusSettings; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -46,6 +36,16 @@ import org.slf4j.LoggerFactory; import org.springframework.util.MultiValueMap; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.StringTokenizer; +import java.util.stream.Collectors; + /** * Validates x-www-form-urlencoded HTML form data content by marshalling form fields to Xml representation. * @@ -101,7 +101,7 @@ private List prepareValidationContexts(List enriched = new ArrayList<>(validationContexts); enriched.add(new XmlMessageValidationContext()); return enriched; @@ -124,12 +124,12 @@ private MessageValidator getXmlMessageValidator(Tes // try to find xml message validator in registry Optional> defaultMessageValidator = context.getMessageValidatorRegistry().findMessageValidator(DEFAULT_XML_MESSAGE_VALIDATOR); - if (!defaultMessageValidator.isPresent() + if (defaultMessageValidator.isEmpty() && context.getReferenceResolver().isResolvable(DEFAULT_XML_MESSAGE_VALIDATOR)) { defaultMessageValidator = Optional.of(context.getReferenceResolver().resolve(DEFAULT_XML_MESSAGE_VALIDATOR, MessageValidator.class)); } - if (!defaultMessageValidator.isPresent()) { + if (defaultMessageValidator.isEmpty()) { // try to find xml message validator via resource path lookup defaultMessageValidator = MessageValidator.lookup("xml"); } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpMessageControllerIT.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpMessageControllerIT.java index c08f68796e..e03888e2c5 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpMessageControllerIT.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpMessageControllerIT.java @@ -22,6 +22,7 @@ import org.testng.annotations.Test; public class HttpMessageControllerIT extends TestNGCitrusSpringSupport { + @Test @CitrusTestSource(type = TestLoader.SPRING) public void HttpMessageControllerIT() {} diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpServerStandaloneJavaIT.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpServerStandaloneJavaIT.java index 41e79ac3ce..bc3e734305 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpServerStandaloneJavaIT.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/integration/HttpServerStandaloneJavaIT.java @@ -27,6 +27,7 @@ import static org.citrusframework.actions.EchoAction.Builder.echo; import static org.citrusframework.container.Assert.Builder.assertException; import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.hamcrest.Matchers.oneOf; @Test public class HttpServerStandaloneJavaIT extends TestNGCitrusSpringSupport { @@ -102,9 +103,10 @@ public void httpServerStandalone() { .receive() .response() .message() - .header(HttpMessageHeaders.HTTP_STATUS_CODE, Matchers.isOneOf(HttpStatus.CREATED.value(), - HttpStatus.ACCEPTED.value(), - HttpStatus.OK.value()))); + .header(HttpMessageHeaders.HTTP_STATUS_CODE, Matchers.is( + oneOf(HttpStatus.CREATED.value(), + HttpStatus.ACCEPTED.value(), + HttpStatus.OK.value())))); run(echo("Test header validation error")); diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java index 9bce6d1042..80eb101492 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageUtilsTest.java @@ -16,6 +16,19 @@ package org.citrusframework.http.message; +import jakarta.servlet.http.Cookie; +import org.citrusframework.message.DefaultMessage; +import org.citrusframework.message.Message; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + import static org.citrusframework.http.message.HttpMessageHeaders.HTTP_COOKIE_PREFIX; import static org.citrusframework.http.message.HttpMessageUtils.getQueryParameterMap; import static org.citrusframework.message.MessageHeaders.ID; @@ -26,18 +39,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; -import jakarta.servlet.http.Cookie; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.citrusframework.message.DefaultMessage; -import org.citrusframework.message.Message; -import org.testng.Assert; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - /** * @since 2.7 */ @@ -146,7 +147,6 @@ public Object[][] queryParamStrings() { }; } - @Test public void testGetQueryParameterMapWithValues() { HttpMessage httpMessage = new HttpMessage(); @@ -195,5 +195,4 @@ public void testGetQueryParameterMapWithMissingValues() { List q3Values = queryParams.get("q3"); assertTrue(q3Values.contains("")); } - } diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java index 71dd7d6907..da3037ed6b 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpQueryParamHeaderValidatorTest.java @@ -16,15 +16,14 @@ package org.citrusframework.http.message; -import java.util.Collections; - -import org.citrusframework.context.TestContextFactory; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.testng.AbstractTestNGUnitTest; import org.citrusframework.validation.context.HeaderValidationContext; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.util.Collections; + import static org.hamcrest.Matchers.is; /** diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapperTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapperTest.java index 8e58a9c5d7..1a86de23a9 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapperTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/servlet/CachingHttpServletRequestWrapperTest.java @@ -16,13 +16,6 @@ package org.citrusframework.http.servlet; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.Collections; -import java.util.Map; - import jakarta.servlet.ReadListener; import jakarta.servlet.ServletInputStream; import jakarta.servlet.http.HttpServletRequest; @@ -34,6 +27,13 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.testng.Assert.assertEquals; @@ -164,7 +164,7 @@ public void testParseUrlEncodedBodyWithExtendedApplicationType(final RequestMeth wrapper.getInputStream(); when(serverRequestMock.getContentType()) - .thenReturn(ContentType.APPLICATION_FORM_URLENCODED.withCharset(Charset.forName("UTF-8")).toString()); + .thenReturn(ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.UTF_8).toString()); when(serverRequestMock.getMethod()).thenReturn(requestMethod.name()); @@ -187,11 +187,11 @@ public void testParseUrlEncodedBodyWithSpecialEncoding() throws Exception { when(serverRequestMock.getInputStream()) .thenReturn(new DelegatingServletInputStream( new ByteArrayInputStream( - (requestMethod.name() + "=ÄäÖöÜü").getBytes(Charset.forName("ISO-8859-1"))))); + (requestMethod.name() + "=ÄäÖöÜü").getBytes(StandardCharsets.ISO_8859_1)))); wrapper.getInputStream(); when(serverRequestMock.getContentType()) - .thenReturn(ContentType.APPLICATION_FORM_URLENCODED.withCharset(Charset.forName("ISO-8859-1")).toString()); + .thenReturn(ContentType.APPLICATION_FORM_URLENCODED.withCharset(StandardCharsets.ISO_8859_1).toString()); when(serverRequestMock.getMethod()).thenReturn(requestMethod.name()); From 539d894441236072cb91d01f6e723db376c951fb Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 14:51:59 +0200 Subject: [PATCH 24/47] chore(citrus-jms): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-jms` module. --- .../jms/actions/PurgeJmsQueuesAction.java | 6 +++--- .../citrusframework/jms/endpoint/JmsConsumer.java | 8 ++++---- .../citrusframework/jms/endpoint/JmsProducer.java | 8 ++++---- .../jms/endpoint/JmsSyncConsumer.java | 7 +++---- .../jms/endpoint/JmsSyncProducer.java | 14 ++++++-------- .../jms/endpoint/JmsTopicSubscriber.java | 8 ++++---- .../jms/message/SoapJmsMessageConverter.java | 2 +- .../integration/SyncJmsTopicCommunicationIT.java | 1 - .../integration/service/LoggingInterceptor.java | 2 +- 9 files changed, 26 insertions(+), 30 deletions(-) diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/actions/PurgeJmsQueuesAction.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/actions/PurgeJmsQueuesAction.java index ba6de91105..73dc9cf3b8 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/actions/PurgeJmsQueuesAction.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/actions/PurgeJmsQueuesAction.java @@ -144,7 +144,7 @@ private void purgeQueue(Queue queue, Session session) throws JMSException { */ private void purgeDestination(Destination destination, Session session, String destinationName) throws JMSException { if (logger.isDebugEnabled()) { - logger.debug("Try to purge destination " + destinationName); + logger.debug("Try to purge destination {}", destinationName); } int messagesPurged = 0; @@ -155,7 +155,7 @@ private void purgeDestination(Destination destination, Session session, String d message = (receiveTimeout >= 0) ? messageConsumer.receive(receiveTimeout) : messageConsumer.receive(); if (message != null) { - logger.debug("Removed message from destination " + destinationName); + logger.debug("Removed message from destination {}", destinationName); messagesPurged++; try { @@ -167,7 +167,7 @@ private void purgeDestination(Destination destination, Session session, String d } while (message != null); if (logger.isDebugEnabled()) { - logger.debug("Purged " + messagesPurged + " messages from destination"); + logger.debug("Purged {} messages from destination", messagesPurged); } } finally { JmsUtils.closeMessageConsumer(messageConsumer); diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsConsumer.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsConsumer.java index 77c9b281d5..2ff38d9e54 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsConsumer.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsConsumer.java @@ -80,7 +80,7 @@ private jakarta.jms.Message receive(String destinationName, String selector) { jakarta.jms.Message receivedJmsMessage; if (logger.isDebugEnabled()) { - logger.debug("Receiving JMS message on destination: '" + getDestinationNameWithSelector(destinationName, selector) + "'"); + logger.debug("Receiving JMS message on destination: '{}'", getDestinationNameWithSelector(destinationName, selector)); } if (StringUtils.hasText(selector)) { @@ -93,7 +93,7 @@ private jakarta.jms.Message receive(String destinationName, String selector) { throw new MessageTimeoutException(endpointConfiguration.getTimeout(), getDestinationNameWithSelector(destinationName, selector)); } - logger.info("Received JMS message on destination: '" + getDestinationNameWithSelector(destinationName, selector) + "'"); + logger.info("Received JMS message on destination: '{}'", getDestinationNameWithSelector(destinationName, selector)); return receivedJmsMessage; } @@ -108,7 +108,7 @@ private jakarta.jms.Message receive(Destination destination, String selector) { jakarta.jms.Message receivedJmsMessage; if (logger.isDebugEnabled()) { - logger.debug("Receiving JMS message on destination: '" + getDestinationNameWithSelector(endpointConfiguration.getDestinationName(destination), selector) + "'"); + logger.debug("Receiving JMS message on destination: '{}'", getDestinationNameWithSelector(endpointConfiguration.getDestinationName(destination), selector)); } if (StringUtils.hasText(selector)) { @@ -121,7 +121,7 @@ private jakarta.jms.Message receive(Destination destination, String selector) { throw new MessageTimeoutException(endpointConfiguration.getTimeout(), getDestinationNameWithSelector(endpointConfiguration.getDestinationName(destination), selector)); } - logger.info("Received JMS message on destination: '" + getDestinationNameWithSelector(endpointConfiguration.getDestinationName(destination), selector) + "'"); + logger.info("Received JMS message on destination: '{}'", getDestinationNameWithSelector(endpointConfiguration.getDestinationName(destination), selector)); return receivedJmsMessage; } diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsProducer.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsProducer.java index b490869ca5..73aa80d62a 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsProducer.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsProducer.java @@ -81,7 +81,7 @@ public void send(final Message message, final TestContext context) { */ private void send(Message message, String destinationName, TestContext context) { if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + destinationName + "'"); + logger.debug("Sending JMS message to destination: '{}'", destinationName); } endpointConfiguration.getJmsTemplate().send(destinationName, session -> { @@ -90,7 +90,7 @@ private void send(Message message, String destinationName, TestContext context) return jmsMessage; }); - logger.info("Message was sent to JMS destination: '" + destinationName + "'"); + logger.info("Message was sent to JMS destination: '{}'", destinationName); } /** @@ -101,7 +101,7 @@ private void send(Message message, String destinationName, TestContext context) */ private void send(Message message, Destination destination, TestContext context) { if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + endpointConfiguration.getDestinationName(destination) + "'"); + logger.debug("Sending JMS message to destination: '{}'", endpointConfiguration.getDestinationName(destination)); } endpointConfiguration.getJmsTemplate().send(destination, session -> { @@ -110,7 +110,7 @@ private void send(Message message, Destination destination, TestContext context) return jmsMessage; }); - logger.info("Message was sent to JMS destination: '" + endpointConfiguration.getDestinationName(destination) + "'"); + logger.info("Message was sent to JMS destination: '{}'", endpointConfiguration.getDestinationName(destination)); } @Override diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncConsumer.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncConsumer.java index 02edad0b3b..baf47a437a 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncConsumer.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncConsumer.java @@ -79,7 +79,7 @@ public void send(final Message message, final TestContext context) { ObjectHelper.assertNotNull(replyDestination, "Failed to find JMS reply destination for message correlation key: '" + correlationKey + "'"); if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + endpointConfiguration.getDestinationName(replyDestination) + "'"); + logger.debug("Sending JMS message to destination: '{}'", endpointConfiguration.getDestinationName(replyDestination)); } endpointConfiguration.getJmsTemplate().send(replyDestination, session -> { @@ -90,7 +90,7 @@ public void send(final Message message, final TestContext context) { context.onOutboundMessage(message); - logger.info("Message was sent to JMS destination: '" + endpointConfiguration.getDestinationName(replyDestination) + "'"); + logger.info("Message was sent to JMS destination: '{}'", endpointConfiguration.getDestinationName(replyDestination)); } /** @@ -107,8 +107,7 @@ public void saveReplyDestination(JmsMessage jmsMessage, TestContext context) { correlationManager.saveCorrelationKey(correlationKeyName, correlationKey, context); correlationManager.store(correlationKey, jmsMessage.getReplyTo()); } else { - logger.warn("Unable to retrieve reply to destination for message \n" + - jmsMessage + "\n - no reply to destination found in message headers!"); + logger.warn("Unable to retrieve reply to destination for message \n{}\n - no reply to destination found in message headers!", jmsMessage); } } diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncProducer.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncProducer.java index 8477409dc4..6b0793beca 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncProducer.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsSyncProducer.java @@ -91,7 +91,7 @@ public void send(Message message, TestContext context) { Destination destination; if (endpointConfiguration.getDestination() != null) { if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + endpointConfiguration.getDestinationName(endpointConfiguration.getDestination()) + "'"); + logger.debug("Sending JMS message to destination: '{}'", endpointConfiguration.getDestinationName(endpointConfiguration.getDestination())); } destination = endpointConfiguration.getDestination(); @@ -103,7 +103,7 @@ public void send(Message message, TestContext context) { } } else if (endpointConfiguration.getJmsTemplate().getDefaultDestination() != null) { if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + endpointConfiguration.getDestinationName(endpointConfiguration.getJmsTemplate().getDefaultDestination()) + "'"); + logger.debug("Sending JMS message to destination: '{}'", endpointConfiguration.getDestinationName(endpointConfiguration.getJmsTemplate().getDefaultDestination())); } destination = endpointConfiguration.getJmsTemplate().getDefaultDestination(); @@ -201,8 +201,7 @@ protected void createConnection() throws JMSException { connection = ((TopicConnectionFactory) endpointConfiguration.getConnectionFactory()).createTopicConnection(); connection.setClientID(getName()); } else { - logger.warn("Not able to create a connection with connection factory '" + endpointConfiguration.getConnectionFactory() + "'" + - " when using setting 'publish-subscribe-domain' (=" + endpointConfiguration.isPubSubDomain() + ")"); + logger.warn("Not able to create a connection with connection factory '{}' when using setting 'publish-subscribe-domain' (={})", endpointConfiguration.getConnectionFactory(), endpointConfiguration.isPubSubDomain()); connection = endpointConfiguration.getConnectionFactory().createConnection(); } @@ -224,8 +223,7 @@ protected void createSession(Connection connection) throws JMSException { } else if (endpointConfiguration.isPubSubDomain() && endpointConfiguration.getConnectionFactory() instanceof TopicConnectionFactory) { session = ((TopicConnection) connection).createTopicSession(false, Session.AUTO_ACKNOWLEDGE); } else { - logger.warn("Not able to create a session with connection factory '" + endpointConfiguration.getConnectionFactory() + "'" + - " when using setting 'publish-subscribe-domain' (=" + endpointConfiguration.isPubSubDomain() + ")"); + logger.warn("Not able to create a session with connection factory '{}' when using setting 'publish-subscribe-domain' (={})", endpointConfiguration.getConnectionFactory(), endpointConfiguration.isPubSubDomain()); session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); } @@ -269,7 +267,7 @@ private void deleteTemporaryDestination(Destination destination) { ((TemporaryTopic) destination).delete(); } } catch (JMSException e) { - logger.error("Error while deleting temporary destination '" + destination + "'", e); + logger.error("Error while deleting temporary destination '{}'", destination, e); } } @@ -310,7 +308,7 @@ private Destination getReplyDestination(Session session, Message message) throws */ private Destination resolveDestination(String destinationName) throws JMSException { if (logger.isDebugEnabled()) { - logger.debug("Sending JMS message to destination: '" + destinationName + "'"); + logger.debug("Sending JMS message to destination: '{}'", destinationName); } return resolveDestinationName(destinationName, session); diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsTopicSubscriber.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsTopicSubscriber.java index eab4550be3..43443cf707 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsTopicSubscriber.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/endpoint/JmsTopicSubscriber.java @@ -50,7 +50,7 @@ public class JmsTopicSubscriber extends JmsConsumer implements Runnable { /** Logger */ - private static final Logger logger = LoggerFactory.getLogger(JmsConsumer.class); + private static final Logger logger = LoggerFactory.getLogger(JmsTopicSubscriber.class); /** Boolean flag for continued message consumption, if false stop */ private boolean running = true; @@ -118,7 +118,7 @@ public void run() { TopicSubscriber subscriber; if (endpointConfiguration.isDurableSubscription()) { - logger.debug(String.format("Create JMS topic durable subscription '%s'", Optional.ofNullable(endpointConfiguration.getDurableSubscriberName()).orElseGet(this::getName))); + logger.debug("Create JMS topic durable subscription '{}'", Optional.ofNullable(endpointConfiguration.getDurableSubscriberName()).orElseGet(this::getName)); subscriber = session.createDurableSubscriber(topic, Optional.ofNullable(endpointConfiguration.getDurableSubscriberName()).orElseGet(this::getName)); } else { logger.debug("Create JMS topic subscription"); @@ -137,12 +137,12 @@ public void run() { Message message = endpointConfiguration.getMessageConverter().convertInbound(event, endpointConfiguration, context); if (logger.isDebugEnabled()) { - logger.debug(String.format("Received topic event '%s'", message.getId())); + logger.debug("Received topic event '{}'", message.getId()); } messageQueue.createProducer().send(message, context); } else { if (logger.isDebugEnabled()) { - logger.debug("Topic subscriber received null message - continue after " + endpointConfiguration.getPollingInterval() + " milliseconds"); + logger.debug("Topic subscriber received null message - continue after {} milliseconds", endpointConfiguration.getPollingInterval()); } try { diff --git a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/message/SoapJmsMessageConverter.java b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/message/SoapJmsMessageConverter.java index c0b84413d8..fbc4e280d8 100644 --- a/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/message/SoapJmsMessageConverter.java +++ b/endpoints/citrus-jms/src/main/java/org/citrusframework/jms/message/SoapJmsMessageConverter.java @@ -122,7 +122,7 @@ public org.citrusframework.message.Message convertInbound(Message jmsMessage, Jm public Message createJmsMessage(org.citrusframework.message.Message message, Session session, JmsEndpointConfiguration endpointConfiguration, TestContext context) { String payload = message.getPayload(String.class); - logger.debug("Creating SOAP message from payload: " + payload); + logger.debug("Creating SOAP message from payload: {}", payload); try { SoapMessage soapMessage = soapMessageFactory.createWebServiceMessage(); diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java index f1ae835e1c..ed19e85aec 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/SyncJmsTopicCommunicationIT.java @@ -18,7 +18,6 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; -import org.testng.annotations.Ignore; import org.testng.annotations.Test; import static org.citrusframework.common.TestLoader.SPRING; diff --git a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/service/LoggingInterceptor.java b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/service/LoggingInterceptor.java index 63f37626c8..96ed8f3d8c 100644 --- a/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/service/LoggingInterceptor.java +++ b/endpoints/citrus-jms/src/test/java/org/citrusframework/jms/integration/service/LoggingInterceptor.java @@ -28,7 +28,7 @@ public class LoggingInterceptor implements ChannelInterceptor { @Override public Message preSend(Message message, MessageChannel channel) { if (logger.isDebugEnabled()) { - logger.debug(channel.toString() + ": " + message.getPayload()); + logger.debug("{}: {}", channel.toString(), message.getPayload()); } if (message.getPayload() instanceof Throwable) { From 93bb411d059d834803d2c106f1d1bb15eb708c24 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 14:58:16 +0200 Subject: [PATCH 25/47] chore(citrus-rmi): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-rmi` module. --- .../citrusframework/rmi/client/RmiClient.java | 24 +++++----- .../citrusframework/rmi/server/RmiServer.java | 28 +++++------ .../rmi/integration/RmiDynamicEndpointIT.java | 2 +- .../rmi/integration/RmiEndpointIT.java | 1 - .../rmi/integration/RmiEndpointJavaIT.java | 1 - .../rmi/server/RmiServerTest.java | 46 +++++++++++-------- 6 files changed, 55 insertions(+), 47 deletions(-) diff --git a/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/client/RmiClient.java b/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/client/RmiClient.java index f58da3dcc8..1abc0c744a 100644 --- a/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/client/RmiClient.java +++ b/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/client/RmiClient.java @@ -16,14 +16,6 @@ package org.citrusframework.rmi.client; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.rmi.NotBoundException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.util.Arrays; - import org.citrusframework.context.TestContext; import org.citrusframework.endpoint.AbstractEndpoint; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -46,6 +38,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.Registry; +import java.util.Arrays; + /** * @since 2.5 */ @@ -112,8 +112,8 @@ public void send(final Message message, TestContext context) { } if (logger.isDebugEnabled()) { - logger.debug("Sending message to RMI server: '" + binding + "'"); - logger.debug("Message to send:\n" + message.getPayload(String.class)); + logger.debug("Sending message to RMI server: '{}'", binding); + logger.debug("Message to send:\n{}", message.getPayload(String.class)); } context.onOutboundMessage(message); @@ -132,7 +132,7 @@ public void send(final Message message, TestContext context) { Message response = new DefaultMessage(payload.toString()); correlationManager.store(correlationKey, response); - logger.info("Message was sent to RMI server: '" + binding + "'"); + logger.info("Message was sent to RMI server: '{}'", binding); if (result != null) { context.onInboundMessage(response); } @@ -146,7 +146,7 @@ public void send(final Message message, TestContext context) { throw new CitrusRuntimeException("Failed to invoke method on remote target, because remote method not accessible", e); } - logger.info("Message was sent to RMI server: '" + binding + "'"); + logger.info("Message was sent to RMI server: '{}'", binding); } @Override diff --git a/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/server/RmiServer.java b/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/server/RmiServer.java index 900eec01ed..80484d5cb5 100644 --- a/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/server/RmiServer.java +++ b/endpoints/citrus-rmi/src/main/java/org/citrusframework/rmi/server/RmiServer.java @@ -16,6 +16,17 @@ package org.citrusframework.rmi.server; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.message.Message; +import org.citrusframework.rmi.endpoint.RmiEndpointConfiguration; +import org.citrusframework.rmi.model.RmiServiceInvocation; +import org.citrusframework.rmi.model.RmiServiceResult; +import org.citrusframework.server.AbstractServer; +import org.citrusframework.util.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.transform.Source; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; @@ -26,17 +37,6 @@ import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import java.util.List; -import javax.xml.transform.Source; - -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.message.Message; -import org.citrusframework.rmi.endpoint.RmiEndpointConfiguration; -import org.citrusframework.rmi.model.RmiServiceInvocation; -import org.citrusframework.rmi.model.RmiServiceResult; -import org.citrusframework.server.AbstractServer; -import org.citrusframework.util.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * @since 2.5 @@ -78,7 +78,7 @@ public RmiServer(RmiEndpointConfiguration endpointConfiguration) { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (logger.isDebugEnabled()) { - logger.debug("Received message on RMI server: '" + endpointConfiguration.getBinding() + "'"); + logger.debug("Received message on RMI server: '{}'", endpointConfiguration.getBinding()); } Message response = getEndpointAdapter().handleMessage(endpointConfiguration.getMessageConverter() @@ -153,7 +153,7 @@ protected void shutdown() { try { registry.unbind(endpointConfiguration.getBinding()); } catch (Exception e) { - logger.warn("Failed to unbind from registry:" + e.getMessage()); + logger.warn("Failed to unbind from registry:{}", e.getMessage()); } } @@ -161,7 +161,7 @@ protected void shutdown() { try { UnicastRemoteObject.unexportObject(proxy, true); } catch (Exception e) { - logger.warn("Failed to unexport from remote object:" + e.getMessage()); + logger.warn("Failed to unexport from remote object:{}", e.getMessage()); } } diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java index cac94f67a8..72fde4cb7c 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiDynamicEndpointIT.java @@ -19,7 +19,6 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.common.TestLoader; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; -import org.testng.annotations.Ignore; import org.testng.annotations.Test; /** @@ -27,6 +26,7 @@ */ public class RmiDynamicEndpointIT extends TestNGCitrusSpringSupport { + @Test @CitrusTestSource(type = TestLoader.SPRING, name = "RmiDynamicEndpointIT") public void testDynamicEndpoint() {} } diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java index a7ae49082a..9175809993 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointIT.java @@ -19,7 +19,6 @@ import org.citrusframework.annotations.CitrusTestSource; import org.citrusframework.common.TestLoader; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; -import org.testng.annotations.Ignore; import org.testng.annotations.Test; /** diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java index 52b3e88b98..e4de083396 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/integration/RmiEndpointJavaIT.java @@ -25,7 +25,6 @@ import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.testng.annotations.Ignore; import org.testng.annotations.Test; import static org.citrusframework.actions.ReceiveMessageAction.Builder.receive; diff --git a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java index b673bada04..c234483b20 100644 --- a/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java +++ b/endpoints/citrus-rmi/src/test/java/org/citrusframework/rmi/server/RmiServerTest.java @@ -16,15 +16,6 @@ package org.citrusframework.rmi.server; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.reset; - -import java.io.IOException; -import java.rmi.Remote; -import java.rmi.registry.Registry; -import java.util.List; import org.citrusframework.endpoint.EndpointAdapter; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; @@ -38,9 +29,20 @@ import org.mockito.MockitoAnnotations; import org.mockito.stubbing.Answer; import org.testng.Assert; -import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; +import java.io.IOException; +import java.rmi.Remote; +import java.rmi.registry.Registry; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.reset; + /** * @since 2.5 */ @@ -48,12 +50,20 @@ public class RmiServerTest extends AbstractTestNGUnitTest { @Mock private Registry registry; + @Mock private EndpointAdapter endpointAdapter; - @BeforeClass + private AutoCloseable mockitoContext; + + @BeforeMethod public void setup() { - MockitoAnnotations.openMocks(this); + mockitoContext = MockitoAnnotations.openMocks(this); + } + + @AfterMethod + public void teardown() throws Exception { + mockitoContext.close(); } @Test @@ -82,8 +92,8 @@ public void testServiceInvocationWithArgument() throws Exception { try { Assert.assertEquals( - message.getPayload(String.class).replaceAll("\\s", ""), - FileUtils.readToString(Resources.create("service-invocation.xml", RmiServer.class)).replaceAll("\\s", "") + message.getPayload(String.class).replaceAll("\\s", ""), + FileUtils.readToString(Resources.create("service-invocation.xml", RmiServer.class)).replaceAll("\\s", "") ); } catch (IOException e) { Assert.fail(e.getMessage()); @@ -95,7 +105,7 @@ public void testServiceInvocationWithArgument() throws Exception { rmiServer.startup(); try { - ((HelloService)remote[0]).sayHello("Hello RMI this is cool!"); + ((HelloService) remote[0]).sayHello("Hello RMI this is cool!"); } catch (Throwable throwable) { Assert.fail("Failed to invoke remote service", throwable); } @@ -127,8 +137,8 @@ public void testServiceInvocationWithResult() throws Exception { try { Assert.assertEquals( - message.getPayload(String.class).replaceAll("\\s", ""), - FileUtils.readToString(Resources.create("service-invocation-2.xml", RmiServer.class)).replaceAll("\\s", "") + message.getPayload(String.class).replaceAll("\\s", ""), + FileUtils.readToString(Resources.create("service-invocation-2.xml", RmiServer.class)).replaceAll("\\s", "") ); } catch (IOException e) { Assert.fail(e.getMessage()); @@ -140,7 +150,7 @@ public void testServiceInvocationWithResult() throws Exception { rmiServer.startup(); try { - Assert.assertEquals(((HelloService)remote[0]).getHelloCount(), 10); + Assert.assertEquals(((HelloService) remote[0]).getHelloCount(), 10); } catch (Throwable throwable) { Assert.fail("Failed to invoke remote service", throwable); } From 1aeee3ea64efd219df391384002d31aff7e209b2 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 24 Oct 2024 22:26:46 +0200 Subject: [PATCH 26/47] docs(#1175): review --- .../spring/TestNGCitrusSpringSupport.java | 10 +--- src/manual/connector-openapi.adoc | 60 ++++++++++--------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java index fd7ab07395..a262bb4b40 100644 --- a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java +++ b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/spring/TestNGCitrusSpringSupport.java @@ -58,14 +58,11 @@ /** * Basic Citrus TestNG support base class with Spring support automatically handles test case runner creation. Also provides method parameter resolution * and resource injection. Users can just extend this class and make use of the action runner methods provided in {@link org.citrusframework.TestActionRunner} - * and {@link GherkinTestActionRunner}. Provides Spring test listener support and - * loads basic Spring application context for Citrus. - * + * and {@link GherkinTestActionRunner}. Provides Spring test listener support and loads basic Spring application context for Citrus. */ @Listeners( { TestNGCitrusSpringMethodInterceptor.class } ) @ContextConfiguration(classes = {CitrusSpringConfig.class}) -public class TestNGCitrusSpringSupport extends AbstractTestNGSpringContextTests - implements GherkinTestActionRunner { +public class TestNGCitrusSpringSupport extends AbstractTestNGSpringContextTests implements GherkinTestActionRunner { /** Citrus instance */ protected Citrus citrus; @@ -115,8 +112,7 @@ public void run(final IHookCallBack callBack, ITestResult testResult) { * @param methodTestLoaders * @param invocationCount */ - protected void run(ITestResult testResult, Method method, List methodTestLoaders, - int invocationCount) { + protected void run(ITestResult testResult, Method method, List methodTestLoaders, int invocationCount) { if (citrus == null) { citrus = Citrus.newInstance(new CitrusSpringContextProvider(applicationContext)); CitrusAnnotations.injectCitrusFramework(this, citrus); diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc index a67e97cc80..b2b1dded6a 100644 --- a/src/manual/connector-openapi.adoc +++ b/src/manual/connector-openapi.adoc @@ -322,28 +322,31 @@ The given HTTP status code defines the response that should be sent by the serve The server will generate a proper response according to the OpenAPI specification. This also includes a potential response message body (e.g. pet object). -[[openapi-server]] +[[openapi-test-api-generator]] === OpenAPI Test API Generator For an even deeper integration with a given OpenAPI, Citrus offers the possibility to generate a dedicated Test API which provides test actions tailored to the specific operations of the OpenAPI under evaluation. These actions can be used in XML or Java DSL. -This functionality is provided by the `Citrus OpenAPI Test API Generator` which leverages the link:https://github.com/swagger-api/swagger-codegen/tree/master[OpenAPI Code Generator] to generate code, but provides custom templates tailored for seamless integration within the Citrus framework. +The functionality is provided by the `Citrus OpenAPI Test API Generator` which leverages the link:https://github.com/swagger-api/swagger-codegen/tree/master[OpenAPI Code Generator] to generate code, but provides custom templates tailored for seamless integration within the Citrus framework. The generator provides the following features: -* generation of a Test API +* generation of a Test API ** from OpenAPI Specification -** [TODO #1163] from WSDL via an intermediate step that generates a "light" OpenApi specification from a WSDL -* integration into <> -** integration into XML editors via generated XSD -*** schema validation -*** auto completion -* integration into <> via Java DSL [TODO #1161] +** [TODO #1163] from WSDL via an intermediate step that generates a "light" OpenApi specification from a WSDL +* integration into <> +** integration into XML editors via generated XSD +*** schema validation +*** auto completion +* integration into <> via Java DSL [TODO #1161] The following directory structure/table specifies the files, which are generated by the generator. Note that the `Prefix` is a configuration parameter which should uniquely identify a generated API. It is specified in the build configuration for the Test API. -``` + +.Generated Folder Structure +[source] +---- target/ ├───generated-test-resources/ │ ├───META-INF/ @@ -369,7 +372,7 @@ target/ │ └───MyReqTypeB.java └───spring/ └───PrefixBeanConfiguration.java -``` +---- |=== | File | Content @@ -384,14 +387,15 @@ target/ | `PrefixBeanConfiguration.java` | A Spring @Configuration class, that registers all Test API actions as Spring beans. |=== -==== Configuration of Test API generation +==== Configuration of Test API Generation Code generation is typically performed during the build process. For the Citrus Test API Generator, it is carried out by a Maven or Gradle plugin. While the standard generator plugin, `org.openapitools:openapi-generator-maven-plugin`, can be employed for this purpose, configuring it can be cumbersome, especially when dealing with multiple APIs. -To address this challenge, Citrus offers its adaptation of this standard generator plugin. +To address this challenge, Citrus offers its own adaptation of this standard generator plugin. This `Citrus OpenAPI Generator Plugin` simplifies the configuration of test API generation by providing predefined defaults and supporting the generation of multiple APIs. -Additionally, it enhances support for generating Spring integration files (`spring.handlers` and `spring.schemas`), thereby facilitating the integration of generated APIs into Spring-based applications. +Additionally, it enhances support for generating Spring integration files (`spring.handlers` and `spring.schemas`), as described above. +It is thereby facilitating the integration of generated APIs into Spring-based applications. Consequently, utilizing the Citrus Generator Plugin is recommended in most scenarios. The following shows the configuration of test api generation for different scenarios: @@ -537,15 +541,15 @@ These are the primary elements you can configure in the `` sectio |=== | Configuration element | Maven Property | Description | Default Value -| `schemaFolder` | `citrus.test.api.generator.schema.folder` | Location for the generated XSD schemas | `schema/xsd/%VERSION%` -| `resourceFolder` | `citrus.test.api.generator.resource.folder` | Location to which resources are generated | `generated-resources` -| `sourceFolder` | `citrus.test.api.generator.source.folder` | Location to which sources are generated | `generated-sources` -| `metaInfFolder` | `citrus.test.api.generator.meta.inf.folder` | Location to which spring meta files are generated/updated | `target/generated-test-resources/META-INF` +| `schemaFolder` | `citrus.test.api.generator.schema.folder` | Location of the generated XSD schemas | `schema/xsd/%VERSION%` +| `resourceFolder` | `citrus.test.api.generator.resource.folder` | Location into which the resources are generated | `generated-resources` +| `sourceFolder` | `citrus.test.api.generator.source.folder` | Location into which the sources are generated | `generated-sources` +| `metaInfFolder` | `citrus.test.api.generator.meta.inf.folder` | Location into which spring meta files are generated/updated | `target/generated-test-resources/META-INF` | `generateSpringIntegrationFiles` | `citrus.test.api.generator.generate.spring.integration.files` | Specifies whether spring integration files should be generated | `true` | Nested `` element | | | -| `prefix` | `citrus.test.api.generator.prefix` | Specifies the prefix used for the test API, typically an acronym | (no default, required) -| `source` | `citrus.test.api.generator.source` | Specifies the source of the test API | (no default, required) -| `version` | `citrus.test.api.generator.version` | Specifies the version of the API, may be null | (none) +| `prefix` | `citrus.test.api.generator.prefix` | Specifies the prefix used for the test API, typically an acronym | (no default, **required**) +| `source` | `citrus.test.api.generator.source` | Specifies the source of the test API | (no default, **required**) +| `version` | `citrus.test.api.generator.version` | Specifies the version of the API, may be `null` | (none) | `endpoint` | `citrus.test.api.generator.endpoint` | Specifies the endpoint of the test API | `applicationServiceClient` | `type` | `citrus.test.api.generator.type` | Specifies the type of the test API | `REST`, other option is `SOAP` | `useTags` | `citrus.test.api.generator.use.tags` | Specifies whether tags should be used by the generator | `true` @@ -572,16 +576,13 @@ This command will generate the classes and XSD files as configured for your APIs ==== Spring meta file generation The `citrus-test-api-generator-maven-plugin` supports the generation of Spring integration files, specifically `spring.handlers` and `spring.schemas`. -These files are essential for Spring applications utilizing XML configuration, as they provide mapping information for custom XML namespaces. - -===== Purpose - +These files are essential for Spring applications utilizing XML configuration. The generated Spring integration files serve the purpose of mapping custom XML namespaces to their corresponding namespace handler and schema locations. This mapping allows Spring to properly parse and validate XML configuration files containing custom elements and attributes. ===== Configuration -The maven plugin generates these Spring integration files based on the provided configuration in the `citrus-test-api-generator-maven-plugin` section of the pom.xml file. +The maven plugin generates these Spring integration files based on the provided configuration in the `citrus-test-api-generator-maven-plugin` section of the `pom.xml` file. For each API specified, the plugin writes entries into the `spring.handlers` and `spring.schemas` files according to the configured XML namespaces and their corresponding handlers and schemas. ===== Important Consideration @@ -607,6 +608,7 @@ This automatically happens if one of the following folders is chosen: In case you choose to generate the API into `generated-test` folders, the maven build requires further configuration to add the `generated-test` folders to the classpath. The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-helper-maven-plugin] is used to accomplish this configuration step. +.Configuration of `build-helper-maven-plugin` [source,xml] ---- @@ -649,7 +651,8 @@ The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-hel ==== Sample usage -To utilize the test API in XML, it's necessary to import the respective namespace. Once imported, requests can be directly employed as actions, as illustrated in the sample below. +To utilize the test API in XML, it's necessary to import the respective namespace. +Once imported, requests can be directly employed as actions, as illustrated in the sample below. Further examples can be found here `org.citrusframework.openapi.generator.GeneratedApiIT`. .XML DSL @@ -682,7 +685,7 @@ Further examples can be found here `org.citrusframework.openapi.generator.Genera To utilize the test API in Java, it's necessary to import the API configuration, that provides the respective request actions. The request to test can then be configured and autowired, as illustrated in the sample below. -Further examples can be found here `org.citrusframework.openapi.generator.GetPetByIdIT`. +Further examples can be found here: `org.citrusframework.openapi.generator.GetPetByIdIT`. .Java DSL [source,java,indent=0,role="secondary"] @@ -715,5 +718,4 @@ class GetPetByIdTest { runner.$(getPetByIdRequest); } } - ---- From e5b17ad5c8b23d0a3bec25e2005bac4744907ac6 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Sat, 26 Oct 2024 10:01:36 +0200 Subject: [PATCH 27/47] chore(citrus-test-api-core): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-test-api-core` module. --- .../citrus-test-api-core/pom.xml | 9 +- .../testapi/ApiActionBuilderCustomizer.java | 1 - .../openapi/testapi/GeneratedApi.java | 4 +- .../testapi/OpenApiParameterFormatter.java | 38 +++--- .../RestApiReceiveMessageActionBuilder.java | 40 +++--- .../RestApiSendMessageActionBuilder.java | 122 +++++++----------- .../SoapApiReceiveMessageActionBuilder.java | 11 +- .../SoapApiSendMessageActionBuilder.java | 11 +- .../openapi/testapi/TestApiUtils.java | 15 +-- .../OpenApiParameterFormatterTest.java | 87 +++++++------ .../citrus-test-api-generator-core/pom.xml | 6 - .../pom.xml | 6 - test-api-generator/pom.xml | 1 - 13 files changed, 155 insertions(+), 196 deletions(-) diff --git a/test-api-generator/citrus-test-api-core/pom.xml b/test-api-generator/citrus-test-api-core/pom.xml index d0a8b248de..b620036e90 100644 --- a/test-api-generator/citrus-test-api-core/pom.xml +++ b/test-api-generator/citrus-test-api-core/pom.xml @@ -52,12 +52,6 @@ - - org.assertj - assertj-core - ${assertj.version} - test - org.citrusframework citrus-junit5 @@ -77,5 +71,4 @@ test - - \ No newline at end of file + diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java index c4359a4bdf..31b400d50c 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java @@ -30,5 +30,4 @@ public interface ApiActionBuilderCustomizer { default > void customizeResponseBuilder(GeneratedApi generatedApi, T builder) { } - } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java index 27a34d5cf1..65d68a9b0e 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApi.java @@ -55,7 +55,6 @@ public interface GeneratedApi { * Specification extensions, also known as vendor extensions, are custom key-value pairs used to describe extra * functionality not covered by the standard OpenAPI Specification. These properties start with "x-". * This method collects only the extensions defined in the "info" section of the API. - *

        * * @return a map containing the specification extensions defined in the "info" section of the API, * where keys are extension names and values are extension values @@ -68,5 +67,4 @@ public interface GeneratedApi { * Returns the endpoint of the generated api. */ Endpoint getEndpoint(); - -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java index e344a670a7..3eb1056d54 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java @@ -33,11 +33,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; -import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.joining; +import static org.citrusframework.openapi.testapi.ParameterStyle.DEEPOBJECT; class OpenApiParameterFormatter { @@ -54,25 +56,24 @@ private OpenApiParameterFormatter() { /** * Formats a list of values as a single String based on the separator and other settings. */ - static String formatArray(String parameterName, Object parameterValue, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - + static String formatArray(String parameterName, + Object parameterValue, + ParameterStyle parameterStyle, + boolean explode, + boolean isObject) { List values = toList(parameterValue, isObject); - if (parameterStyle == ParameterStyle.DEEPOBJECT) { + if (DEEPOBJECT.equals(parameterStyle)) { return formatDeepObject(parameterName, values); } - FormatParameters formatParameters = determineFormatParameters(parameterName, parameterStyle, explode, - isObject); - + FormatParameters formatParameters = determineFormatParameters(parameterName, parameterStyle, explode, isObject); if (isObject && explode) { return formatParameters.prefix + explode(values, formatParameters.separator); } else { return formatParameters.prefix + values.stream() - .collect(Collectors.joining(formatParameters.separator)); + .collect(joining(formatParameters.separator)); } - } private static String formatDeepObject(String parameterName, List values) { @@ -87,13 +88,14 @@ private static String formatDeepObject(String parameterName, List values if (!builder.isEmpty()) { builder.deleteCharAt(builder.length() - 1); } + return builder.toString(); } private static FormatParameters determineFormatParameters(String parameterName, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - + boolean explode, + boolean isObject) { return switch (parameterStyle) { case MATRIX -> matrixFormatParameters(parameterName, explode, isObject); case LABEL -> labelFormatParameters(explode); @@ -123,11 +125,10 @@ private static FormatParameters matrixFormatParameters(String parameterName, boo if (explode) { if (isObject) { prefix = ";"; - separator = prefix; } else { prefix = ";" + parameterName + "="; - separator = prefix; } + separator = prefix; } else { prefix = ";" + parameterName + "="; } @@ -138,11 +139,10 @@ private static FormatParameters matrixFormatParameters(String parameterName, boo private static String explode(List values, String delimiter) { return IntStream.range(0, values.size() / 2) .mapToObj(i -> values.get(2 * i) + "=" + values.get(2 * i + 1)) - .collect(Collectors.joining(delimiter)); + .collect(joining(delimiter)); } private static List toList(Object value, boolean isObject) { - if (value == null) { return emptyList(); } @@ -166,7 +166,7 @@ private static List toList(Object value, boolean isObject) { } else if (isObject) { return toList(convertBeanToMap(value), true); } else { - return List.of(value.toString()); + return singletonList(value.toString()); } } @@ -214,8 +214,7 @@ protected static Map convertBeanToMap(Object bean) { map.put(propertyName, propertyValue); } } - } catch (IntrospectionException | IllegalAccessException | - InvocationTargetException e) { + } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { throw new CitrusRuntimeException("Error converting bean to map: " + e.getMessage(), e); } return map; @@ -223,5 +222,4 @@ protected static Map convertBeanToMap(Object bean) { private record FormatParameters(String prefix, String separator) { } - } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java index e531aa3d55..3531eccf55 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiReceiveMessageActionBuilder.java @@ -18,49 +18,51 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; import org.citrusframework.openapi.actions.OpenApiSpecificationSource; -import org.citrusframework.openapi.util.OpenApiUtils; import java.util.List; -public class RestApiReceiveMessageActionBuilder extends - org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder { +import static java.lang.String.format; +import static org.citrusframework.openapi.util.OpenApiUtils.createFullPathOperationIdentifier; + +public class RestApiReceiveMessageActionBuilder extends OpenApiClientResponseActionBuilder { private final GeneratedApi generatedApi; private final List customizers; - - public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, - String method, String path, String operationName, String statusCode) { - - super(new OpenApiSpecificationSource(openApiSpec), - OpenApiUtils.createFullPathOperationIdentifier(method, path), statusCode); + public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, + OpenApiSpecification openApiSpec, + String method, + String path, + String operationName, + String statusCode) { + super(new OpenApiSpecificationSource(openApiSpec), createFullPathOperationIdentifier(method, path), statusCode); this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); - name(String.format("receive-%s", operationName)); + name(format("receive-%s", operationName)); endpoint(generatedApi.getEndpoint()); } public RestApiReceiveMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, - OpenApiClientResponseMessageBuilder messageBuilder, HttpMessage httpMessage, String method, - String path, String operationName) { - - super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, - OpenApiUtils.createFullPathOperationIdentifier(method, path)); - + OpenApiClientResponseMessageBuilder messageBuilder, + HttpMessage httpMessage, + String method, + String path, + String operationName) { + super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, createFullPathOperationIdentifier(method, path)); this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); - name(String.format("receive-%s", operationName)); + name(format("receive-%s", operationName)); endpoint(generatedApi.getEndpoint()); - } public GeneratedApi getGeneratedApi() { @@ -70,4 +72,4 @@ public GeneratedApi getGeneratedApi() { public List getCustomizers() { return customizers; } -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java index 24e5ab726c..9b1a8ae4ac 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java @@ -24,12 +24,10 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; import org.citrusframework.openapi.actions.OpenApiSpecificationSource; -import org.citrusframework.openapi.util.OpenApiUtils; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.StringUtils; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; @@ -43,9 +41,12 @@ import java.util.function.BiConsumer; import static java.lang.String.format; +import static org.citrusframework.openapi.util.OpenApiUtils.createFullPathOperationIdentifier; +import static org.citrusframework.util.FileUtils.copyToByteArray; +import static org.citrusframework.util.FileUtils.getDefaultCharset; +import static org.citrusframework.util.StringUtils.isEmpty; -public class RestApiSendMessageActionBuilder extends - org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder { +public class RestApiSendMessageActionBuilder extends OpenApiClientRequestActionBuilder { private final GeneratedApi generatedApi; @@ -55,7 +56,9 @@ public class RestApiSendMessageActionBuilder extends public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, - String method, String path, String operationName) { + String method, + String path, + String operationName) { this(generatedApi, openApiSpec, new HttpMessage(), method, path, operationName); } @@ -63,21 +66,24 @@ public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, HttpMessage httpMessage, String method, String path, String operationName) { - this(generatedApi, openApiSpec, new TestApiClientRequestMessageBuilder(httpMessage, new OpenApiSpecificationSource(openApiSpec), - OpenApiUtils.createFullPathOperationIdentifier(method, path)), httpMessage, method, path, + createFullPathOperationIdentifier(method, path)), + httpMessage, + method, + path, operationName); } public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, OpenApiSpecification openApiSpec, - TestApiClientRequestMessageBuilder messageBuilder, HttpMessage httpMessage, String method, - String path, String operationName) { - - super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, - OpenApiUtils.createFullPathOperationIdentifier(method, path)); + TestApiClientRequestMessageBuilder messageBuilder, + HttpMessage httpMessage, + String method, + String path, + String operationName) { + super(new OpenApiSpecificationSource(openApiSpec), messageBuilder, httpMessage, createFullPathOperationIdentifier(method, path)); this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); @@ -85,12 +91,12 @@ public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, endpoint(generatedApi.getEndpoint()); httpMessage.path(path); - name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - operationName)); + + name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), operationName)); + getMessageBuilderSupport().header("citrus_open_api_operation_name", operationName); getMessageBuilderSupport().header("citrus_open_api_method", method); getMessageBuilderSupport().header("citrus_open_api_path", path); - } public GeneratedApi getGeneratedApi() { @@ -106,12 +112,8 @@ public final HttpClientRequestActionBuilder name(String name) { return super.name(name); } - protected void pathParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - - ((TestApiClientRequestMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).pathParameter( - name, value, parameterStyle, explode, isObject); - + protected void pathParameter(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { + ((TestApiClientRequestMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).pathParameter(name, value, parameterStyle, explode, isObject); } protected void formParameter(String name, Object value) { @@ -119,8 +121,7 @@ protected void formParameter(String name, Object value) { } protected void setFormParameter(String name, Object value) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + if (value == null || isEmpty(value.toString())) { return; } @@ -128,19 +129,15 @@ protected void setFormParameter(String name, Object value) { } protected void queryParameter(final String name, Object value) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + if (value == null || isEmpty(value.toString())) { return; } - setParameter((paramName, paramValue) -> super.queryParam(paramName, - paramValue != null ? paramValue.toString() : null), name, value); + setParameter((paramName, paramValue) -> super.queryParam(paramName, paramValue != null ? paramValue.toString() : null), name, value); } - protected void queryParameter(final String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + protected void queryParameter(final String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { + if (value == null || isEmpty(value.toString())) { return; } @@ -153,20 +150,15 @@ protected void queryParameter(final String name, Object value, ParameterStyle pa } protected void headerParameter(String name, Object value) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + if (value == null || isEmpty(value.toString())) { return; } - setParameter( - (paramName, paramValue) -> getMessageBuilderSupport().header(paramName, paramValue), - name, value); + setParameter((paramName, paramValue) -> getMessageBuilderSupport().header(paramName, paramValue), name, value); } - protected void headerParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + protected void headerParameter(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { + if (value == null || isEmpty(value.toString())) { return; } @@ -174,20 +166,15 @@ protected void headerParameter(String name, Object value, ParameterStyle paramet } protected void cookieParameter(String name, Object value) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + if (value == null || isEmpty(value.toString())) { return; } - setParameter((paramName, paramValue) -> getMessageBuilderSupport().cookie( - (new Cookie(paramName, paramValue != null ? paramValue.toString() : null))), name, - value); + setParameter((paramName, paramValue) -> getMessageBuilderSupport().cookie((new Cookie(paramName, paramValue != null ? paramValue.toString() : null))), name, value); } - protected void cookieParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - - if (value == null || StringUtils.isEmpty(value.toString())) { + protected void cookieParameter(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { + if (value == null || isEmpty(value.toString())) { return; } @@ -199,8 +186,7 @@ protected void cookieParameter(String name, Object value, ParameterStyle paramet cookieParameter(keyValue[0], keyValue[1]); } - private void setParameter(BiConsumer parameterConsumer, - final String parameterName, Object parameterValue) { + private void setParameter(BiConsumer parameterConsumer, final String parameterName, Object parameterValue) { if (parameterValue != null) { if (byte[].class.isAssignableFrom(parameterValue.getClass())) { // Pass through byte array @@ -222,7 +208,6 @@ private void setParameter(BiConsumer parameterConsumer, @Override public SendMessageAction doBuild() { - if (!formParameters.isEmpty()) { getMessageBuilderSupport().body(formParameters); } @@ -234,7 +219,7 @@ protected byte[] toBinary(Object object) { if (object instanceof byte[] bytes) { return bytes; } else if (object instanceof Resource resource) { - return FileUtils.copyToByteArray(resource.getInputStream()); + return copyToByteArray(resource.getInputStream()); } else if (object instanceof String string) { Resource resource = Resources.create(string); @@ -247,7 +232,8 @@ protected byte[] toBinary(Object object) { } catch (IllegalArgumentException e) { // Ignore decoding failure and treat as regular string } - return string.getBytes(FileUtils.getDefaultCharset()); + + return string.getBytes(getDefaultCharset()); } throw new IllegalArgumentException( @@ -256,12 +242,11 @@ protected byte[] toBinary(Object object) { } protected String getOrDefault(String value, String defaultValue, boolean base64Encode) { - - if (StringUtils.isEmpty(value) && StringUtils.isEmpty(defaultValue)) { + if (isEmpty(value) && isEmpty(defaultValue)) { return null; } - if (StringUtils.isEmpty(value)) { + if (isEmpty(value)) { value = defaultValue; } @@ -272,8 +257,7 @@ protected String getOrDefault(String value, String defaultValue, boolean base64E return value; } - public static final class TestApiClientRequestMessageBuilder extends - OpenApiClientRequestMessageBuilder { + public static final class TestApiClientRequestMessageBuilder extends OpenApiClientRequestMessageBuilder { private final Map pathParameters = new HashMap<>(); @@ -287,22 +271,19 @@ private static void encodeArrayStyleCookies(HttpMessage message) { if (message.getCookies() != null && !message.getCookies().isEmpty()) { for (Cookie cookie : message.getCookies()) { if (cookie.getValue().contains(",")) { - cookie.setValue( - URLEncoder.encode(cookie.getValue(), FileUtils.getDefaultCharset())); + cookie.setValue(URLEncoder.encode(cookie.getValue(), getDefaultCharset())); } } } } - public void pathParameter(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - + public void pathParameter(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { if (value == null) { throw new CitrusRuntimeException( "Mandatory path parameter '%s' must not be null".formatted(name)); } - pathParameters.put(name, - new ParameterData(name, value, parameterStyle, explode, isObject)); + + pathParameters.put(name, new ParameterData(name, value, parameterStyle, explode, isObject)); } @Override @@ -325,9 +306,6 @@ public Message build(TestContext context, String messageType) { } } - public record ParameterData(String name, Object value, ParameterStyle parameterStyle, - boolean explode, boolean isObject) { - + public record ParameterData(String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { } - -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java index f3024a09fc..7215c19bc4 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java @@ -20,6 +20,8 @@ import java.util.List; +import static java.lang.String.format; + public class SoapApiReceiveMessageActionBuilder extends ReceiveSoapMessageAction.Builder { private final GeneratedApi generatedApi; @@ -27,15 +29,14 @@ public class SoapApiReceiveMessageActionBuilder extends ReceiveSoapMessageAction private final List customizers; public SoapApiReceiveMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { - super(); + this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); endpoint(generatedApi.getEndpoint()); - name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - soapAction)); + name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), soapAction)); } public GeneratedApi getGeneratedApi() { @@ -46,10 +47,8 @@ public List getCustomizers() { return customizers; } - @Override public ReceiveSoapMessageAction doBuild() { return new ReceiveSoapMessageAction(this); } - -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java index 97313fc0a4..bc231527ad 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java @@ -20,6 +20,8 @@ import java.util.List; +import static java.lang.String.format; + public class SoapApiSendMessageActionBuilder extends Builder { private final GeneratedApi generatedApi; @@ -27,15 +29,14 @@ public class SoapApiSendMessageActionBuilder extends Builder { private final List customizers; public SoapApiSendMessageActionBuilder(GeneratedApi generatedApi, String soapAction) { - super(); + this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); endpoint(generatedApi.getEndpoint()); - name(String.format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), - soapAction)); + name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(),soapAction)); } public GeneratedApi getGeneratedApi() { @@ -45,6 +46,4 @@ public GeneratedApi getGeneratedApi() { public List getCustomizers() { return customizers; } - - -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java index 9f2170d1e5..2a81248909 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/TestApiUtils.java @@ -17,24 +17,23 @@ package org.citrusframework.openapi.testapi; import org.citrusframework.http.actions.HttpClientRequestActionBuilder.HttpMessageBuilderSupport; -import org.citrusframework.util.StringUtils; -public class TestApiUtils { +import static org.citrusframework.util.StringUtils.isEmpty; + +public final class TestApiUtils { private TestApiUtils() { //prevent instantiation of utility class } public static void addBasicAuthHeader(String username, String password, HttpMessageBuilderSupport messageBuilderSupport) { - if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)) { - messageBuilderSupport.header("Authorization", - "Basic citrus:encodeBase64(" + username + ":" + password + ")"); + if (!isEmpty(username) && !isEmpty(password)) { + messageBuilderSupport.header("Authorization", "Basic citrus:encodeBase64(" + username + ":" + password + ")"); } } public static String mapXmlAttributeNameToJavaPropertyName(String attributeName) { - - if (StringUtils.isEmpty(attributeName)) { + if (isEmpty(attributeName)) { return attributeName; } @@ -45,7 +44,5 @@ public static String mapXmlAttributeNameToJavaPropertyName(String attributeName) } return attributeName; - } - } diff --git a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java index c8f08ff37f..59b3488330 100644 --- a/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java +++ b/test-api-generator/citrus-test-api-core/src/test/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatterTest.java @@ -1,9 +1,5 @@ package org.citrusframework.openapi.testapi; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Getter; -import lombok.Setter; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder.ParameterData; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -19,56 +15,69 @@ import static org.citrusframework.openapi.testapi.ParameterStyle.LABEL; import static org.citrusframework.openapi.testapi.ParameterStyle.MATRIX; import static org.citrusframework.openapi.testapi.ParameterStyle.SIMPLE; +import static org.junit.jupiter.params.provider.Arguments.arguments; class OpenApiParameterFormatterTest { - private static final User USER = User.user().role("admin").firstName("Alex").build(); + private static final User USER = new User("admin", "Alex"); private static final List LIST = List.of(3, 4, 5); private static final Integer SINGLE = 5; static Stream format() { return Stream.of( - Arguments.arguments("Simple/non exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, false, false), "5"), - Arguments.arguments("Simple/non exploded/non object/array", new ParameterData("id", LIST, SIMPLE, false, false), "3,4,5"), - Arguments.arguments("Simple/non exploded/Object/single", new ParameterData("id", USER, SIMPLE, false, true), "firstName,Alex,role,admin"), - Arguments.arguments("Simple/exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, true, false), "5"), - Arguments.arguments("Simple/exploded/non object/array", new ParameterData("id", LIST, SIMPLE, true, false), "3,4,5"), - Arguments.arguments("Simple/exploded/Object/single", new ParameterData("id", USER, SIMPLE, true, true), "firstName=Alex,role=admin"), - Arguments.arguments("Label/non exploded/non object/single", new ParameterData("id", SINGLE, LABEL, false, false), ".5"), - Arguments.arguments("Label/non exploded/non object/array", new ParameterData("id", LIST, LABEL, false, false), ".3,4,5"), - Arguments.arguments("Label/non exploded/Object/single", new ParameterData("id", USER, LABEL, false, true), ".firstName,Alex,role,admin"), - Arguments.arguments("Label/exploded/non object/single", new ParameterData("id", SINGLE, LABEL, true, false), ".5"), - Arguments.arguments("Label/exploded/non object/array", new ParameterData("id", LIST, LABEL, true, false), ".3.4.5"), - Arguments.arguments("Label/exploded/Object/single", new ParameterData("id", USER, LABEL, true, true), ".firstName=Alex.role=admin"), - Arguments.arguments("Matrix/non exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, false, false), ";id=5"), - Arguments.arguments("Matrix/non exploded/non object/array", new ParameterData("id", LIST, MATRIX, false, false), ";id=3,4,5"), - Arguments.arguments("Matrix/non exploded/Object/single", new ParameterData("id", USER, MATRIX, false, true), ";id=firstName,Alex,role,admin"), - Arguments.arguments("Matrix/exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, true, false), ";id=5"), - Arguments.arguments("Matrix/exploded/non object/array", new ParameterData("id", LIST, MATRIX, true, false), ";id=3;id=4;id=5"), - Arguments.arguments("Matrix/exploded/Object/single", new ParameterData("id", USER, MATRIX, true, true), ";firstName=Alex;role=admin"), - Arguments.arguments("Form/non exploded/non object/single", new ParameterData("id", SINGLE, FORM, false, false), "id=5"), - Arguments.arguments("Form/non exploded/non object/array", new ParameterData("id", LIST, FORM, false, false), "id=3,4,5"), - Arguments.arguments("Form/non exploded/object/single", new ParameterData("id", USER, FORM, false, true), "id=firstName,Alex,role,admin"), - Arguments.arguments("Form/exploded/non object/single", new ParameterData("id", SINGLE, FORM, true, false), "id=5"), - Arguments.arguments("Form/exploded/non object/array", new ParameterData("id", LIST, FORM, true, false), "id=3&id=4&id=5"), - Arguments.arguments("Form/exploded/object/single", new ParameterData("id", USER, FORM, true, true), "firstName=Alex&role=admin"), - Arguments.arguments("DeepObject/exploded/object/single", new ParameterData("id", USER, DEEPOBJECT, true, true), "id[firstName]=Alex&id[role]=admin") + arguments("Simple/non exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, false, false), "5"), + arguments("Simple/non exploded/non object/array", new ParameterData("id", LIST, SIMPLE, false, false), "3,4,5"), + arguments("Simple/non exploded/Object/single", new ParameterData("id", USER, SIMPLE, false, true), "firstName,Alex,role,admin"), + arguments("Simple/exploded/non object/single", new ParameterData("id", SINGLE, SIMPLE, true, false), "5"), + arguments("Simple/exploded/non object/array", new ParameterData("id", LIST, SIMPLE, true, false), "3,4,5"), + arguments("Simple/exploded/Object/single", new ParameterData("id", USER, SIMPLE, true, true), "firstName=Alex,role=admin"), + arguments("Label/non exploded/non object/single", new ParameterData("id", SINGLE, LABEL, false, false), ".5"), + arguments("Label/non exploded/non object/array", new ParameterData("id", LIST, LABEL, false, false), ".3,4,5"), + arguments("Label/non exploded/Object/single", new ParameterData("id", USER, LABEL, false, true), ".firstName,Alex,role,admin"), + arguments("Label/exploded/non object/single", new ParameterData("id", SINGLE, LABEL, true, false), ".5"), + arguments("Label/exploded/non object/array", new ParameterData("id", LIST, LABEL, true, false), ".3.4.5"), + arguments("Label/exploded/Object/single", new ParameterData("id", USER, LABEL, true, true), ".firstName=Alex.role=admin"), + arguments("Matrix/non exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, false, false), ";id=5"), + arguments("Matrix/non exploded/non object/array", new ParameterData("id", LIST, MATRIX, false, false), ";id=3,4,5"), + arguments("Matrix/non exploded/Object/single", new ParameterData("id", USER, MATRIX, false, true), ";id=firstName,Alex,role,admin"), + arguments("Matrix/exploded/non object/single", new ParameterData("id", SINGLE, MATRIX, true, false), ";id=5"), + arguments("Matrix/exploded/non object/array", new ParameterData("id", LIST, MATRIX, true, false), ";id=3;id=4;id=5"), + arguments("Matrix/exploded/Object/single", new ParameterData("id", USER, MATRIX, true, true), ";firstName=Alex;role=admin"), + arguments("Form/non exploded/non object/single", new ParameterData("id", SINGLE, FORM, false, false), "id=5"), + arguments("Form/non exploded/non object/array", new ParameterData("id", LIST, FORM, false, false), "id=3,4,5"), + arguments("Form/non exploded/object/single", new ParameterData("id", USER, FORM, false, true), "id=firstName,Alex,role,admin"), + arguments("Form/exploded/non object/single", new ParameterData("id", SINGLE, FORM, true, false), "id=5"), + arguments("Form/exploded/non object/array", new ParameterData("id", LIST, FORM, true, false), "id=3&id=4&id=5"), + arguments("Form/exploded/object/single", new ParameterData("id", USER, FORM, true, true), "firstName=Alex&role=admin"), + arguments("DeepObject/exploded/object/single", new ParameterData("id", USER, DEEPOBJECT, true, true), "id[firstName]=Alex&id[role]=admin") ); } @ParameterizedTest(name = "{0}") @MethodSource void format(String name, ParameterData parameterData, String expected) { - assertThat(formatArray(parameterData.name(), parameterData.value(), parameterData.parameterStyle(), parameterData.explode(), - parameterData.isObject())).isEqualTo(expected); + assertThat( + formatArray( + parameterData.name(), + parameterData.value(), + parameterData.parameterStyle(), + parameterData.explode(), + parameterData.isObject())) + .isEqualTo(expected); } - @Getter - @Setter - @AllArgsConstructor - @Builder(builderMethodName = "user") - private static class User { - String role; - String firstName; + private record User(String role, String firstName) { + + // Used for formatting + @SuppressWarnings({"unused"}) + public String getRole() { + return role; + } + + // Used for formatting + @SuppressWarnings({"unused"}) + public String getFirstName() { + return firstName; + } } } diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index bb9340ac74..ed2cca98aa 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -71,12 +71,6 @@ ${project.version} - - org.assertj - assertj-core - ${assertj.version} - test - com.fasterxml.jackson.dataformat jackson-dataformat-yaml diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index ce25d9119e..86d9e1eb94 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -101,12 +101,6 @@ ${maven.plugin.testing.harness.version} test - - org.assertj - assertj-core - ${assertj.version} - test - org.junit.jupiter junit-jupiter-params diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index 025be2115a..28b98ebc7d 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -40,7 +40,6 @@ ${junit.jupiter.version} test - From 8952a659a4158c6bd8185c4722195f3708575484 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Mon, 28 Oct 2024 14:10:17 +0100 Subject: [PATCH 28/47] chore(citrus-test-api-generator-core): review and code cleanup pr: https://github.com/citrusframework/citrus/pull/1224 `citrus-test-api-generator-core` module. --- .../citrus-test-api-generator-core/README.md | 2 +- .../citrus-test-api-generator-core/pom.xml | 27 +- .../openapi/generator/CitrusJavaCodegen.java | 178 ++- .../generator/WsdlToOpenApiTransformer.java | 31 +- .../main/resources/java-citrus/api.mustache | 4 +- .../java-citrus/api_locator.mustache | 1 - .../java-citrus/bean_configuration.mustache | 1 - .../java-citrus/namespace_handler.mustache | 1 - .../namespace_handler_soap.mustache | 1 - .../generator/CitrusJavaCodegenTest.java | 1 - .../openapi/generator/ExpectedCodeGenIT.java | 9 +- .../openapi/generator/GeneratedRestApiIT.java | 475 +++---- .../openapi/generator/GeneratedSoapApiIT.java | 9 +- .../GeneratedSpringBeanConfigurationIT.java | 3 +- .../generator/util/MultipartConverter.java | 25 +- .../rest/extpetstore/ExtPetStore.java | 1 - .../rest/extpetstore/model/Category.java | 177 +-- .../extpetstore/model/HistoricalData.java | 181 +-- .../rest/extpetstore/model/Pet.java | 411 +++--- .../rest/extpetstore/model/PetIdentifier.java | 119 ++ .../rest/extpetstore/model/Tag.java | 177 +-- .../model/VaccinationDocumentResult.java | 138 +- .../rest/extpetstore/request/ExtPetApi.java | 1234 +++++++++-------- .../spring/ExtPetStoreBeanConfiguration.java | 14 +- .../spring/ExtPetStoreNamespaceHandler.java | 235 ++-- .../expectedgen/rest/petstore/PetStore.java | 1 - .../rest/petstore/model/Address.java | 293 ++-- .../rest/petstore/model/Category.java | 177 +-- .../rest/petstore/model/Customer.java | 234 ++-- .../rest/petstore/model/ModelApiResponse.java | 216 +-- .../rest/petstore/model/Order.java | 382 ++--- .../expectedgen/rest/petstore/model/Pet.java | 411 +++--- .../expectedgen/rest/petstore/model/Tag.java | 177 +-- .../expectedgen/rest/petstore/model/User.java | 411 +++--- .../rest/petstore/request/PetApi.java | 240 ++-- .../rest/petstore/request/StoreApi.java | 143 +- .../rest/petstore/request/UserApi.java | 171 +-- .../spring/PetStoreBeanConfiguration.java | 18 +- .../spring/PetStoreNamespaceHandler.java | 151 +- .../soap/bookservice/BookService.java | 10 + .../request/BookServiceSoapApi.java | 37 +- .../spring/BookServiceBeanConfiguration.java | 32 + .../spring/BookServiceNamespaceHandler.java | 50 + .../GeneratedApiTest/withMultipartTest.xml | 2 +- .../BookService.wsdl | 1 - 45 files changed, 3380 insertions(+), 3232 deletions(-) create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/BookService.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java diff --git a/test-api-generator/citrus-test-api-generator-core/README.md b/test-api-generator/citrus-test-api-generator-core/README.md index a60957b2c7..5b98d26f1b 100644 --- a/test-api-generator/citrus-test-api-generator-core/README.md +++ b/test-api-generator/citrus-test-api-generator-core/README.md @@ -44,7 +44,7 @@ public class PetsApi { } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ public DeletePetRequestActionBuilder sendDeletePet$(String petIdExpression) { DeletePetRequestActionBuilder builder = new DeletePetRequestActionBuilder(petIdExpression, openApiSpecification); diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index ed2cca98aa..c6e251a2ab 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -1,7 +1,7 @@ 4.0.0 @@ -152,14 +152,16 @@ org.apache.maven.plugins maven-dependency-plugin - 3.7.1 + ${maven.dependency.plugin.version} org.openapitools openapi-generator ${org.openapitools.version} - Java/*Annotation*.mustache,Java/*Model*.mustache,Java/model*.mustache,Java/pojo*.mustache + + Java/*Annotation*.mustache,Java/*Model*.mustache,Java/model*.mustache,Java/pojo*.mustache + @@ -178,9 +180,9 @@ - org.apache.maven.plugins - maven-resources-plugin - 3.3.1 + org.apache.maven.plugins + maven-resources-plugin + ${maven.resource.plugin.version} prepare-java-templates @@ -258,7 +260,9 @@ org.citrusframework.openapi.generator.rest.extpetstore org.citrusframework.openapi.generator.rest.extpetstore.request - org.citrusframework.openapi.generator.rest.extpetstore.model + + org.citrusframework.openapi.generator.rest.extpetstore.model + ExtPetStore extpetstore.endpoint @@ -276,7 +280,9 @@ SOAP org.citrusframework.openapi.generator.soap.bookservice org.citrusframework.openapi.generator.soap.bookservice.request - org.citrusframework.openapi.generator.soap.bookservice.model + + org.citrusframework.openapi.generator.soap.bookservice.model + BookService bookstore.endpoint @@ -284,7 +290,6 @@ - diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java index 024ac58f44..4f53d5be41 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java @@ -24,8 +24,6 @@ import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.servers.Server; -import lombok.Getter; -import lombok.Setter; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; @@ -64,10 +62,10 @@ import static org.openapitools.codegen.utils.CamelizeOption.LOWERCASE_FIRST_LETTER; import static org.openapitools.codegen.utils.StringUtils.camelize; -@Getter -@Setter public class CitrusJavaCodegen extends AbstractJavaCodegen { + private static final Logger logger = LoggerFactory.getLogger(CitrusJavaCodegen.class); + public static final String CODEGEN_NAME = "java-citrus"; public static final String API_TYPE_REST = "REST"; public static final String API_TYPE_SOAP = "SOAP"; @@ -82,13 +80,12 @@ public class CitrusJavaCodegen extends AbstractJavaCodegen { public static final String RESPONSE_BUILDER_CLASS = "responseBuilderClass"; public static final String REQUEST_BUILDER_CLASS_NAME = "requestBuilderClassName"; public static final String RESPONSE_BUILDER_CLASS_NAME = "responseBuilderClassName"; - private static final Logger logger = LoggerFactory.getLogger(CitrusJavaCodegen.class); + protected String apiPrefix = "Api"; protected String httpClient = API_ENDPOINT; - protected String resourceFolder = - "src" + File.separator + "main" + File.separator + "resources"; + protected String resourceFolder = "src" + File.separator + "main" + File.separator + "resources"; protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; protected String targetXmlnsNamespace; @@ -108,31 +105,98 @@ public CitrusJavaCodegen() { configureTypeMappings(); } - private static void postProcessSecurityParameters( - CustomCodegenOperation customCodegenOperation) { + private static void postProcessSecurityParameters(CustomCodegenOperation customCodegenOperation) { customCodegenOperation.hasApiKeyAuth = customCodegenOperation.authMethods.stream() .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); customCodegenOperation.authWithParameters = customCodegenOperation.hasApiKeyAuth; for (CodegenSecurity codegenSecurity : customCodegenOperation.authMethods) { if (TRUE.equals(codegenSecurity.isBasicBasic)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthUsername"); - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthPassword"); + customCodegenOperation.optionalAndAuthParameterNames.add("basicAuthUsername"); + customCodegenOperation.optionalAndAuthParameterNames.add("basicAuthPassword"); customCodegenOperation.authWithParameters = true; } else if (TRUE.equals(codegenSecurity.isApiKey)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); + customCodegenOperation.optionalAndAuthParameterNames.add(camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); customCodegenOperation.authWithParameters = true; } else if (TRUE.equals(codegenSecurity.isBasicBearer)) { - customCodegenOperation.optionalAndAuthParameterNames.add( - "basicAuthBearer"); + customCodegenOperation.optionalAndAuthParameterNames.add("basicAuthBearer"); customCodegenOperation.authWithParameters = true; } } } + public String getApiPrefix() { + return apiPrefix; + } + + public void setApiPrefix(String apiPrefix) { + this.apiPrefix = apiPrefix; + } + + public String getHttpClient() { + return httpClient; + } + + public void setHttpClient(String httpClient) { + this.httpClient = httpClient; + } + + public String getResourceFolder() { + return resourceFolder; + } + + public void setResourceFolder(String resourceFolder) { + this.resourceFolder = resourceFolder; + } + + public String getGeneratedSchemaFolder() { + return generatedSchemaFolder; + } + + public void setGeneratedSchemaFolder(String generatedSchemaFolder) { + this.generatedSchemaFolder = generatedSchemaFolder; + } + + public String getTargetXmlnsNamespace() { + return targetXmlnsNamespace; + } + + public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { + this.targetXmlnsNamespace = targetXmlnsNamespace; + } + + public String getApiVersion() { + return apiVersion; + } + + public void setApiVersion(String apiVersion) { + this.apiVersion = apiVersion; + } + + public String getInvokerFolder() { + return invokerFolder; + } + + public void setInvokerFolder(String invokerFolder) { + this.invokerFolder = invokerFolder; + } + + public String getSpringFolder() { + return springFolder; + } + + public void setSpringFolder(String springFolder) { + this.springFolder = springFolder; + } + + public String getSchemaFolder() { + return schemaFolder; + } + + public void setSchemaFolder(String schemaFolder) { + this.schemaFolder = schemaFolder; + } + private void configureAdditionalProperties() { additionalProperties.put("apiVersion", apiVersion); additionalProperties.put(API_TYPE, API_TYPE_REST); @@ -207,10 +271,10 @@ public String getHelp() { } /** - * Configures a friendly name for the generator. This will be used by the generator to select + * Configures a human-friendly name for the generator. This will be used by the generator to select * the library with the -g flag. * - * @return the friendly name for the generator + * @return the human-friendly name for the generator */ @Override public String getName() { @@ -284,8 +348,7 @@ private void setupFolders() { } additionalProperties.put(RESOURCE_FOLDER, resourceFolder); - invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", - File.separator); + invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator); springFolder = invokerFolder + File.separator + "spring"; schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; } @@ -302,28 +365,20 @@ private void setupApiType() { } private void setupSoapApiType(String springFolder, String schemaFolder) { - additionalProperties.put(REQUEST_BUILDER_CLASS, - SoapApiSendMessageActionBuilder.class.getName()); - additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, - SoapApiSendMessageActionBuilder.class.getSimpleName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS, - SoapApiReceiveMessageActionBuilder.class.getName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, - SoapApiReceiveMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(REQUEST_BUILDER_CLASS, SoapApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, SoapApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, SoapApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, SoapApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", false); additionalProperties.put("isSoap", true); addSoapSupportingFiles(springFolder, schemaFolder); } private void setupRestApiType(String springFolder, String schemaFolder) { - additionalProperties.put(REQUEST_BUILDER_CLASS, - RestApiSendMessageActionBuilder.class.getName()); - additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, - RestApiSendMessageActionBuilder.class.getSimpleName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS, - RestApiReceiveMessageActionBuilder.class.getName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, - RestApiReceiveMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(REQUEST_BUILDER_CLASS, RestApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, RestApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, RestApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, RestApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", true); additionalProperties.put("isSoap", false); @@ -336,8 +391,7 @@ private void setupRestApiType(String springFolder, String schemaFolder) { private void writeApiToResourceFolder() { String directoryPath = appendSegmentToUrlPath(getOutputDir(), getResourceFolder()); - directoryPath = appendSegmentToUrlPath(directoryPath, - invokerPackage.replace('.', File.separatorChar)); + directoryPath = appendSegmentToUrlPath(directoryPath, invokerPackage.replace('.', File.separatorChar)); String filename = getApiPrefix() + "_openApi.yaml"; @@ -373,9 +427,7 @@ public void preprocessOpenAPI(OpenAPI openAPI) { } } - private void addRestSupportingFiles(String springFolder, - String schemaFolder) { - + private void addRestSupportingFiles(String springFolder, String schemaFolder) { supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder, convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, @@ -401,15 +453,13 @@ private void addDefaultSupportingFiles() { } @Override - public CodegenParameter fromRequestBody(RequestBody body, Set imports, - String bodyParameterName) { + public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) { CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); return convertToCustomCodegenParameter(codegenParameter); } @Override - public CodegenParameter fromFormProperty(String name, Schema propertySchema, - Set imports) { + public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set imports) { CodegenParameter codegenParameter = super.fromFormProperty(name, propertySchema, imports); return convertToCustomCodegenParameter(codegenParameter); } @@ -429,13 +479,11 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) * Converts given codegenParameter to a custom {@link CustomCodegenParameter} to provide * additional derived properties. */ - private CustomCodegenParameter convertToCustomCodegenParameter( - CodegenParameter codegenParameter) { + private CustomCodegenParameter convertToCustomCodegenParameter(CodegenParameter codegenParameter) { CustomCodegenParameter customCodegenParameter = new CustomCodegenParameter(); copyFields(CodegenParameter.class, codegenParameter, customCodegenParameter); - customCodegenParameter.isBaseTypeString = codegenParameter.isString || "String".equals( - codegenParameter.baseType); + customCodegenParameter.isBaseTypeString = codegenParameter.isString || "String".equals(codegenParameter.baseType); return customCodegenParameter; } @@ -447,16 +495,13 @@ public CodegenOperation fromOperation(String path, List servers) { CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); return convertToCustomCodegenOperation(op); - } /** * Converts given codegenOperation to a custom {@link CustomCodegenOperation} to provide * additional derived properties. */ - private CustomCodegenOperation convertToCustomCodegenOperation( - CodegenOperation codegenOperation) { - + private CustomCodegenOperation convertToCustomCodegenOperation(CodegenOperation codegenOperation) { CustomCodegenOperation customOperation = new CustomCodegenOperation(); copyFields(CodegenOperation.class, codegenOperation, customOperation); @@ -469,14 +514,12 @@ private CustomCodegenOperation convertToCustomCodegenOperation( !customOperation.requiredParams.isEmpty() && customOperation.requiredParams .stream() - .anyMatch( - param -> !param.isBodyParam && !"String".equals(param.dataType)); + .anyMatch(param -> !param.isBodyParam && !"String".equals(param.dataType)); if (customOperation.optionalParams != null) { customOperation.optionalAndAuthParameterNames.addAll( customOperation.optionalParams.stream() - .map(codegenParameter -> - toVarName(codegenParameter.nameInCamelCase)) + .map(codegenParameter -> toVarName(codegenParameter.nameInCamelCase)) .toList()); } @@ -484,8 +527,7 @@ private CustomCodegenOperation convertToCustomCodegenOperation( } @Override - public OperationsMap postProcessOperationsWithModels(OperationsMap objs, - List allModels) { + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { OperationsMap operationsMap = super.postProcessOperationsWithModels(objs, allModels); OperationMap operations = objs.getOperations(); @@ -519,6 +561,7 @@ static class CustomCodegenOperation extends CodegenOperation { public CustomCodegenOperation() { super(); + requiredNonBodyParams = new ArrayList<>(); optionalAndAuthParameterNames = new ArrayList<>(); } @@ -535,18 +578,19 @@ public boolean equals(Object o) { return false; } CustomCodegenOperation that = (CustomCodegenOperation) o; - return needsConstructorWithAllStringParameter - == that.needsConstructorWithAllStringParameter - && hasApiKeyAuth == that.hasApiKeyAuth && Objects.equals(requiredNonBodyParams, - that.requiredNonBodyParams) && Objects.equals(optionalAndAuthParameterNames, - that.optionalAndAuthParameterNames); + return needsConstructorWithAllStringParameter == that.needsConstructorWithAllStringParameter + && hasApiKeyAuth == that.hasApiKeyAuth + && Objects.equals(requiredNonBodyParams, that.requiredNonBodyParams) + && Objects.equals(optionalAndAuthParameterNames, that.optionalAndAuthParameterNames); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), requiredNonBodyParams, + return Objects.hash(super.hashCode(), + requiredNonBodyParams, optionalAndAuthParameterNames, - needsConstructorWithAllStringParameter, hasApiKeyAuth); + needsConstructorWithAllStringParameter, + hasApiKeyAuth); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java index 74dd5890a4..05bed786a9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/WsdlToOpenApiTransformer.java @@ -40,7 +40,6 @@ import javax.wsdl.xml.WSDLReader; import javax.xml.namespace.QName; import java.net.URI; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -48,6 +47,7 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; import static com.fasterxml.jackson.databind.MapperFeature.SORT_PROPERTIES_ALPHABETICALLY; import static java.lang.String.format; +import static java.util.Collections.singletonList; /** * Transforms a WSDL specification into a simple OpenAPI specification for usage with the OpenApiGenerator. @@ -166,8 +166,8 @@ private Definition readWSDL() throws WSDLException { } private Info createInfo() { - Info info = new Info(); - info.setTitle("Generated api from wsdl"); + Info info = new Info() + .title("Generated api from wsdl"); info.setDescription( format( @@ -177,8 +177,8 @@ private Info createInfo() { ); info.setVersion("1.0.0"); - Contact contact = new Contact(); - contact.setName("org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer"); + Contact contact = new Contact() + .name("org.citrusframework.openapi.generator.SimpleWsdlToOpenApiTransformer"); info.setContact(contact); return info; @@ -208,24 +208,23 @@ private void addOperations(OpenAPI openApi, QName qName, Binding binding) { } private void addOperation(Paths paths, String name, String description, String soapAction, String tag) { - Operation postOperation = new Operation(); - logger.debug("Adding operation to spec: {}", name); - postOperation.setOperationId(name); - postOperation.setDescription(description); - postOperation.setSummary(soapAction); - postOperation.tags(Collections.singletonList(tag)); + Operation postOperation = new Operation() + .operationId(name) + .description(description) + .summary(soapAction); + postOperation.tags(singletonList(tag)); ApiResponses responses = new ApiResponses(); - ApiResponse apiResponse = new ApiResponse(); - apiResponse.setDescription("Generic Response"); + ApiResponse apiResponse = new ApiResponse() + .description("Generic Response"); responses.addApiResponse("default", apiResponse); postOperation.responses(responses); - PathItem pi = new PathItem(); - pi.setPost(postOperation); + PathItem pathItem = new PathItem() + .post(postOperation); - paths.addPathItem("/" + name, pi); + paths.addPathItem("/" + name, pathItem); } /** diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 09618550e2..4693245206 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -170,7 +170,7 @@ public class {{classname}} implements GeneratedApi {{#needsConstructorWithAllStringParameter}} /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ public {{operationIdCamelCase}}SendActionBuilder send{{operationIdCamelCase}}$({{#requiredNonBodyParams}}{{^isArray}}String {{paramName}}Expression{{/isArray}}{{#isArray}}List {{paramName}}Expression{{/isArray}}{{^-last}}, {{/-last}} {{/requiredNonBodyParams}}) { {{#authWithParameters}} @@ -612,4 +612,4 @@ public class {{classname}} implements GeneratedApi {{/-last}} {{/operation}} {{/operations}} -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache index 8155517939..bc1d9e0074 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_locator.mustache @@ -24,5 +24,4 @@ public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}} { public static URL {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Api() { return {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}.class.getResource("{{prefix}}_openApi.yaml"); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache index a9b329dba5..2c4552e2ef 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -33,7 +33,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}; - @Configuration {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}BeanConfiguration { diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache index 27fe698993..ae5f59c21e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache @@ -81,5 +81,4 @@ public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}NamespaceHandle operationName, apiClass, receiveBeanClass, "{{apiEndpoint}}"); registerBeanDefinitionParser("receive-"+elementName, receiveParser); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache index 4104f0b454..6b168784c4 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler_soap.mustache @@ -74,5 +74,4 @@ public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}NamespaceHandle apiClass, receiveBeanClass, "{{apiEndpoint}}"); registerBeanDefinitionParser("receive-"+elementName, receiveParser); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java index 80a05bf60b..2190a62894 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java @@ -174,5 +174,4 @@ void testFromOperation() { .hasFieldOrPropertyWithValue("httpMethod", "GET") .hasFieldOrPropertyWithValue("path", "/path"); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java index 4283d057b2..815819decd 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/ExpectedCodeGenIT.java @@ -44,14 +44,11 @@ static Stream getResourcesForRest() throws IOException { } static Stream getResourcesForSoap() throws IOException { - return geClassResourcesIgnoringInnerClasses( - BASE_PACKAGE + "/soap/bookservice"); + return geClassResourcesIgnoringInnerClasses(BASE_PACKAGE + "/soap/bookservice"); } - private static Stream geClassResourcesIgnoringInnerClasses(String path) - throws IOException { - return Streams.of( - new PathMatchingResourcePatternResolver().getResources(path + "/**/*.class")) + private static Stream geClassResourcesIgnoringInnerClasses(String path) throws IOException { + return Streams.of(new PathMatchingResourcePatternResolver().getResources(path + "/**/*.class")) .filter(resource -> { try { return !resource.getURI().toString().contains("$"); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java index fc762dca65..0305c0310d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -31,8 +31,6 @@ import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdReceiveActionBuilder; import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; import org.citrusframework.spi.Resources; -import org.citrusframework.util.FileUtils; -import org.citrusframework.util.SocketUtils; import org.citrusframework.validation.json.JsonPathVariableExtractor; import org.citrusframework.validation.script.ScriptValidationContext; import org.citrusframework.variable.GlobalVariables; @@ -46,7 +44,6 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; -import org.springframework.http.HttpStatus; import java.io.IOException; import java.math.BigDecimal; @@ -60,8 +57,16 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.citrusframework.http.actions.HttpActionBuilder.http; import static org.citrusframework.openapi.generator.util.MultipartConverter.multipartMessageToMap; +import static org.citrusframework.util.FileUtils.copyToByteArray; +import static org.citrusframework.util.FileUtils.readToString; +import static org.citrusframework.util.SocketUtils.findAvailableTcpPort; import static org.citrusframework.validation.json.JsonPathMessageValidationContext.Builder.jsonPath; +import static org.springframework.http.HttpStatus.NO_CONTENT; import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; +import static org.springframework.http.MediaType.APPLICATION_PDF_VALUE; /** * This integration test class for the generated TestAPI aims to comprehensively test all aspects of @@ -74,23 +79,26 @@ */ @ExtendWith(CitrusSpringExtension.class) -@SpringBootTest(classes = {PetStoreBeanConfiguration.class, ExtPetStoreBeanConfiguration.class, - CitrusSpringConfig.class, Config.class}, properties = { - "extpetstore.basic.username=extUser", - "extpetstore.basic.password=extPassword", - "extpetstore.bearer.token=defaultBearerToken", - "extpetstore.api-key-query=defaultTopSecretQueryApiKey", - "extpetstore.api-key-header=defaultTopSecretHeaderApiKey", - "extpetstore.api-key-cookie=defaultTopSecretCookieApiKey", - "extpetstore.base64-encode-api-key=true" -} -) +@SpringBootTest( + classes = { + PetStoreBeanConfiguration.class, + ExtPetStoreBeanConfiguration.class, + CitrusSpringConfig.class, + Config.class}, + properties = { + "extpetstore.basic.username=extUser", + "extpetstore.basic.password=extPassword", + "extpetstore.bearer.token=defaultBearerToken", + "extpetstore.api-key-query=defaultTopSecretQueryApiKey", + "extpetstore.api-key-header=defaultTopSecretHeaderApiKey", + "extpetstore.api-key-cookie=defaultTopSecretCookieApiKey", + "extpetstore.base64-encode-api-key=true" + }) class GeneratedRestApiIT { public static final List PET_ID_LIST = List.of(1, 2); public static final List PET_ID_AS_STRING_LIST = List.of("1", "2"); - public static final List PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST = List.of("${one}", - "${two}"); + public static final List PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST = List.of("${one}", "${two}"); public static final PetIdentifier PET_IDENTIFIER = new PetIdentifier()._name("Louis") .alias("Alexander"); @@ -118,11 +126,11 @@ class GeneratedRestApiIT { @TestConfiguration public static class Config { - private final int port = SocketUtils.findAvailableTcpPort(8080); + private final int port = findAvailableTcpPort(8080); - private final int otherPort = SocketUtils.findAvailableTcpPort(8081); + private final int otherPort = findAvailableTcpPort(8081); - private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + private final int wsPort = findAvailableTcpPort(8090); /** * Main http client for accessing the main http server. @@ -166,7 +174,7 @@ public HttpServer httpServer() { .port(port) .timeout(5000L) .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) + .defaultStatus(NO_CONTENT) .handleCookies(true) .handleHandleSemicolonPathContent(true) .build(); @@ -191,7 +199,7 @@ public HttpServer otherHttpServer() { .port(otherPort) .timeout(5000L) .autoStart(true) - .defaultStatus(HttpStatus.NO_CONTENT) + .defaultStatus(NO_CONTENT) .build(); } @@ -257,11 +265,10 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); - } @Test @@ -279,16 +286,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithSimpleStyleArray$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -301,16 +306,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -328,20 +331,17 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. - runner.when(extPetApi.sendGetPetWithSimpleStyleObject( - PET_IDENTIFIER) + runner.when(extPetApi.sendGetPetWithSimpleStyleObject(PET_IDENTIFIER) .schemaValidation(false) .fork(true)); @@ -354,7 +354,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); @@ -362,7 +362,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObject$(PET_IDENTIFIER_AS_STRING) @@ -378,12 +377,11 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObject("200")); } - } @Nested @@ -404,11 +402,10 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); - } @Test @@ -426,16 +423,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when( extPetApi.sendGetPetWithSimpleStyleArrayExploded$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -449,16 +444,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -476,16 +469,14 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleArrayExploded("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded( @@ -503,7 +494,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); @@ -511,7 +502,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithSimpleStyleObjectExploded$( @@ -529,12 +519,11 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleObjectExploded("200")); } - } } @@ -550,11 +539,8 @@ class Array { * request validation to overcome this issue. */ @Test - void throws_request_validation_exception( - @CitrusResource TestCaseRunner runner) { - - HttpClientRequestActionBuilder builder = extPetApi.sendGetPetWithLabelStyleArray( - PET_ID_LIST) + void throws_request_validation_exception(@CitrusResource TestCaseRunner runner) { + HttpClientRequestActionBuilder builder = extPetApi.sendGetPetWithLabelStyleArray(PET_ID_LIST) .fork(false); assertThatThrownBy(() -> runner.when(builder)) @@ -566,7 +552,6 @@ void throws_request_validation_exception( @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray(List.of(1)) @@ -582,16 +567,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray(PET_ID_LIST) @@ -607,16 +590,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleArray$(PET_ID_AS_STRING_LIST) @@ -632,16 +613,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -662,20 +641,17 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArray("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. - runner.when(extPetApi.sendGetPetWithLabelStyleObject( - PET_IDENTIFIER) + runner.when(extPetApi.sendGetPetWithLabelStyleObject(PET_IDENTIFIER) .schemaValidation(false) .fork(true)); @@ -688,7 +664,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); @@ -696,7 +672,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObject$(""" @@ -714,7 +689,7 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObject("200")); @@ -739,11 +714,10 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); - } @Test @@ -761,16 +735,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when( extPetApi.sendGetPetWithLabelStyleArrayExploded$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -784,22 +756,19 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); runner.when( - extPetApi.sendGetPetWithLabelStyleArrayExploded$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + extPetApi.sendGetPetWithLabelStyleArrayExploded$(PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) .fork(true)); runner.then(http().server(httpServer) @@ -811,16 +780,14 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleArrayExploded("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded$(""" @@ -839,7 +806,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); @@ -847,7 +814,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithLabelStyleObjectExploded( @@ -865,13 +831,12 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithLabelStyleObjectExploded("200")); } } - } @Nested @@ -882,7 +847,6 @@ class Array { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithMatrixStyleArray(List.of(1)) .fork(true)); @@ -895,16 +859,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithMatrixStyleArray(PET_ID_LIST) .fork(true)); @@ -917,16 +879,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithMatrixStyleArray$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -939,16 +899,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -966,16 +924,14 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArray("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObject( @@ -992,7 +948,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); @@ -1000,7 +956,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObject$( @@ -1017,12 +972,11 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } - } @Nested @@ -1030,7 +984,6 @@ class ExplodedArray { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(List.of(1)) .fork(true)); @@ -1042,16 +995,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithMatrixStyleArrayExploded(PET_ID_LIST) .fork(true)); @@ -1063,16 +1014,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when( extPetApi.sendGetPetWithMatrixStyleArrayExploded$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -1086,17 +1035,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -1114,16 +1060,14 @@ void java_array_value_non_type_safe_with_variables( .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleArrayExploded("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded( @@ -1141,7 +1085,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); @@ -1149,7 +1093,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithMatrixStyleObjectExploded$( @@ -1167,12 +1110,11 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { .send() .response(OK) .message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithMatrixStyleObject("200")); } - } } } @@ -1186,10 +1128,8 @@ class SimpleStyle { @Nested class Array { - @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(List.of(1)) .fork(true)); @@ -1201,16 +1141,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithSimpleStyleHeader(PET_ID_LIST) .fork(true)); @@ -1222,18 +1160,15 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - - runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$( - PET_ID_AS_STRING_LIST) + runner.when(extPetApi.sendGetPetWithSimpleStyleHeader$(PET_ID_AS_STRING_LIST) .fork(true)); runner.then(http().server(httpServer) @@ -1244,17 +1179,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -1270,16 +1202,14 @@ void java_array_value_non_type_safe_with_variables( runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleHeader("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1295,7 +1225,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); @@ -1303,7 +1233,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1319,12 +1248,11 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); } - } @Nested @@ -1332,7 +1260,6 @@ class ArrayExploded { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(List.of(1)) .fork(true)); @@ -1344,16 +1271,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader(PET_ID_LIST) .fork(true)); @@ -1365,18 +1290,15 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - - runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( - PET_ID_AS_STRING_LIST) + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$(PET_ID_AS_STRING_LIST) .fork(true)); runner.then(http().server(httpServer) @@ -1387,22 +1309,18 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); - runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$( - PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) + runner.when(extPetApi.sendGetPetWithSimpleStyleExplodedHeader$(PET_ID_WITH_VARIABLE_EXPRESSIONS_LIST) .fork(true)); runner.then(http().server(httpServer) @@ -1413,16 +1331,14 @@ void java_array_value_non_type_safe_with_variables( runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithSimpleStyleExplodedHeader("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1438,7 +1354,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when( @@ -1447,7 +1363,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1463,16 +1378,14 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when( extPetApi.receiveGetPetWithSimpleStyleExplodedObjectHeader("200")); } } - } - } @Nested @@ -1486,7 +1399,6 @@ class Array { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleQuery(List.of(1)) .fork(true)); @@ -1498,16 +1410,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); - } @Test void java_arrya_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleQuery(PET_ID_LIST) .fork(true)); @@ -1519,7 +1429,7 @@ void java_arrya_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1527,7 +1437,6 @@ void java_arrya_value(@CitrusResource TestCaseRunner runner) { @Test void java_arrya_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleQuery$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -1539,16 +1448,14 @@ void java_arrya_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @Test - void java_arrya_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_arrya_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -1564,7 +1471,7 @@ void java_arrya_value_non_type_safe_with_variables( runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1572,7 +1479,6 @@ void java_arrya_value_non_type_safe_with_variables( @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1588,7 +1494,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); @@ -1596,7 +1502,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi @@ -1612,7 +1517,7 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); @@ -1624,7 +1529,6 @@ class ArrayExploded { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(List.of(1)) .fork(true)); @@ -1636,16 +1540,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleExplodedQuery(PET_ID_LIST) .fork(true)); @@ -1661,7 +1563,7 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1669,7 +1571,6 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when( extPetApi.sendGetPetWithFormStyleExplodedQuery$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -1686,16 +1587,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -1715,7 +1614,7 @@ void java_array_value_non_type_safe_with_variables( runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleQuery("200")); @@ -1723,7 +1622,6 @@ void java_array_value_non_type_safe_with_variables( @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi .sendGetPetWithFormStyleExplodedObjectQuery( PET_IDENTIFIER) @@ -1738,7 +1636,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); @@ -1746,7 +1644,6 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi .sendGetPetWithFormStyleExplodedObjectQuery$( PET_IDENTIFIER_AS_STRING) @@ -1761,7 +1658,7 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleObjectQuery("200")); @@ -1777,10 +1674,7 @@ class ArrayExploded { @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - - runner.when(extPetApi - .sendGetPetWithDeepObjectTypeQuery( - PET_IDENTIFIER) + runner.when(extPetApi.sendGetPetWithDeepObjectTypeQuery(PET_IDENTIFIER) .fork(true)); runner.then(http().server(httpServer) .receive() @@ -1792,7 +1686,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); @@ -1800,10 +1694,7 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { @Test void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - - runner.when(extPetApi - .sendGetPetWithDeepObjectTypeQuery$( - PET_IDENTIFIER_AS_STRING) + runner.when(extPetApi.sendGetPetWithDeepObjectTypeQuery$(PET_IDENTIFIER_AS_STRING) .fork(true)); runner.then(http().server(httpServer) .receive() @@ -1815,7 +1706,7 @@ void java_object_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithDeepObjectTypeQuery("200")); @@ -1835,7 +1726,6 @@ class Array { @Test void java_single_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleCookie(List.of(1)) .fork(true)); @@ -1847,16 +1737,14 @@ void java_single_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } @Test void java_array_value(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleCookie(PET_ID_LIST) .fork(true)); @@ -1870,16 +1758,14 @@ void java_array_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } @Test void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { - runner.when(extPetApi.sendGetPetWithFormStyleCookie$(PET_ID_AS_STRING_LIST) .fork(true)); @@ -1893,17 +1779,14 @@ void java_array_value_non_type_safe(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } @Test - void java_array_value_non_type_safe_with_variables( - @CitrusResource TestCaseRunner runner) { - + void java_array_value_non_type_safe_with_variables(@CitrusResource TestCaseRunner runner) { runner.variable("one", "1"); runner.variable("two", "2"); @@ -1921,16 +1804,14 @@ void java_array_value_non_type_safe_with_variables( runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } @Test void java_object_value(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie( @@ -1949,16 +1830,14 @@ void java_object_value(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } @Test void java_object_value_none_type(@CitrusResource TestCaseRunner runner) { - // Note that we need to disable oas validation here, as validation is // currently not supported with the chosen serialization approach. runner.when(extPetApi.sendGetPetWithFormObjectStyleCookie$( @@ -1977,11 +1856,10 @@ void java_object_value_none_type(@CitrusResource TestCaseRunner runner) { runner.then(http().server(httpServer) .send() .response(OK).message() - .contentType("application/json") + .contentType(APPLICATION_JSON_VALUE) .body("[]")); runner.when(extPetApi.receiveGetPetWithFormStyleCookie("200")); - } } } @@ -2044,7 +1922,6 @@ void java(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi .receiveUpdatePetWithArrayQueryData(OK) .message()); - } } } @@ -2081,7 +1958,6 @@ void updatePetWithForm_java(@CitrusResource TestCaseRunner runner) { .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); - } } @@ -2104,9 +1980,7 @@ void xml() { } @Test - void java( - @CitrusResource TestCaseRunner runner) { - + void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(petApi @@ -2125,12 +1999,11 @@ void java( .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(petApi .receiveGetPetById(OK) .schemaValidation(false)); - } } } @@ -2154,7 +2027,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2173,7 +2045,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi .receiveGetPetById(OK).message().reasonPhrase("Almost OK"); @@ -2198,7 +2070,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2217,7 +2088,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi .receiveGetPetById("201"); @@ -2242,7 +2113,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2261,7 +2131,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi .receiveGetPetById(OK).message().version("HTTP/1.0"); @@ -2286,7 +2156,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2305,7 +2174,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); GetPetByIdReceiveActionBuilder getPetByIdResponseActionBuilder = petApi.receiveGetPetById( OK); @@ -2313,7 +2182,6 @@ void java(@CitrusResource TestCaseRunner runner) { TestCaseFailedException.class) .hasMessageContaining("Object has missing required properties ([\"name\"]): []") .hasCauseInstanceOf(ValidationException.class); - } } @@ -2330,7 +2198,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2349,7 +2216,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi .receiveGetPetById(OK).message().body(Resources.create( @@ -2359,7 +2226,6 @@ void java(@CitrusResource TestCaseRunner runner) { .hasMessageContaining( "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") .hasCauseInstanceOf(ValidationException.class); - } } @@ -2376,7 +2242,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2395,7 +2260,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi .receiveGetPetById(OK).message().body(""" @@ -2405,7 +2270,6 @@ void java(@CitrusResource TestCaseRunner runner) { .hasMessageContaining( "Number of entries is not equal in element: '$', expected '[description]' but was '[photoUrls, name, id, category, tags, status]'") .hasCauseInstanceOf(ValidationException.class); - } } @@ -2422,7 +2286,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -2441,7 +2304,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); HttpClientResponseActionBuilder.HttpMessageBuilderSupport builder = petApi .receiveGetPetById(OK).message() @@ -2451,7 +2314,6 @@ void java(@CitrusResource TestCaseRunner runner) { .hasMessageContaining( "Values not equal for element '$.name', expected 'unknown' but was") .hasCauseInstanceOf(ValidationException.class); - } } } @@ -2522,7 +2384,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK) .message() @@ -2562,7 +2424,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK).endpoint(otherApplicationServiceClient) .message() @@ -2625,14 +2487,12 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithBasicAuthentication(OK) .message()); - } - } /** @@ -2647,8 +2507,7 @@ void xml() { } @Test - void java( - @CitrusResource TestCaseRunner runner) { + void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi @@ -2668,14 +2527,12 @@ void java( .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithBasicAuthentication(OK) .message()); - } - } } @@ -2694,8 +2551,7 @@ void xml() { } @Test - void java( - @CitrusResource TestCaseRunner runner) { + void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.when(extPetApi @@ -2714,12 +2570,11 @@ void java( .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithBearerAuthentication(OK) .message()); - } } @@ -2754,23 +2609,18 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithBearerAuthentication(OK) .message()); - } - } - } - @Nested class ApiKeyAuthentication { - /** * Demonstrates API key authentication using default values from properties. */ @@ -2784,7 +2634,6 @@ void xml() { @Test void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(extPetApi @@ -2809,13 +2658,12 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithApiKeyAuthentication(OK) .schemaValidation(false)); } - } /** @@ -2830,9 +2678,7 @@ void xml() { } @Test - void java( - @CitrusResource TestCaseRunner runner) { - + void java(@CitrusResource TestCaseRunner runner) { runner.variable("petId", "1234"); runner.variable("apiKeyHeader", "TopSecretHeader"); runner.variable("apiKeyCookie", "TopSecretCookie"); @@ -2861,7 +2707,7 @@ void java( .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/invalidGetPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetByIdWithApiKeyAuthentication(OK) @@ -2878,17 +2724,16 @@ void java( class Multipart { @Test - @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withMultiPartTest") + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withMultipartTest") void xml() { } @Test void java(@CitrusResource TestCaseRunner runner) throws IOException { - - byte[] templateData = FileUtils.copyToByteArray( + byte[] templateData = copyToByteArray( Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationTemplate.bin")); - String additionalData = FileUtils.readToString(Resources.create( + String additionalData = readToString(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationAdditionalData.json")); runner.when(extPetApi.sendGenerateVaccinationReport$( @@ -2923,7 +2768,8 @@ void java(@CitrusResource TestCaseRunner runner) throws IOException { runner.then(http().server(httpServer) .send() .response(OK) - .message().contentType("application/pdf") + .message() + .contentType(APPLICATION_PDF_VALUE) .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/vaccinationReport.pdf"))); @@ -2970,9 +2816,7 @@ void java(@CitrusResource TestCaseRunner runner) { .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); - } - } /** @@ -3009,7 +2853,7 @@ void java(@CitrusResource TestCaseRunner runner) { .receive() .put("/api/v3/ext/pet/form/1234") .message() - .contentType("application/x-www-form-urlencoded") + .contentType(APPLICATION_FORM_URLENCODED_VALUE) .validate((Message message, TestContext context) -> assertThat(message.getPayload(String.class)) .contains("name=Thunder") @@ -3030,7 +2874,6 @@ void java(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi .receiveUpdatePetWithFormUrlEncoded(OK) .message()); - } } @@ -3062,7 +2905,7 @@ void java(@CitrusResource TestCaseRunner runner) { .receive() .put("/api/v3/ext/pet/form/1234") .message() - .contentType("application/x-www-form-urlencoded") + .contentType(APPLICATION_FORM_URLENCODED_VALUE) .validate((Message message, TestContext context) -> assertThat(message.getPayload(String.class)) .contains("name=Thunder") @@ -3083,7 +2926,6 @@ void java(@CitrusResource TestCaseRunner runner) { runner.when(extPetApi .receiveUpdatePetWithFormUrlEncoded(OK) .message()); - } } @@ -3136,7 +2978,6 @@ void java(@CitrusResource TestCaseRunner runner) { .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); - } } @@ -3171,7 +3012,6 @@ void java(@CitrusResource TestCaseRunner runner) { .response(OK)); runner.when(petApi.receiveUpdatePetWithForm("200")); - } } @@ -3207,7 +3047,7 @@ void java(@CitrusResource TestCaseRunner runner) { .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK) .message() @@ -3267,7 +3107,7 @@ void java(@CitrusResource TestCaseRunner runner) { .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK) .message() @@ -3309,7 +3149,7 @@ void java(@CitrusResource TestCaseRunner runner) { .cookie(new Cookie("NonApiCookie", "nonApiCookieValue")) .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK) .message() @@ -3332,7 +3172,6 @@ void xml() { @Test @CitrusTest void java(@CitrusResource TestCaseRunner runner) { - runner.variable("petId", "1234"); runner.when(petApi @@ -3351,7 +3190,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi.receiveGetPetById(OK) .message() @@ -3372,9 +3211,7 @@ void xml() { } @Test - void java( - @CitrusResource TestCaseRunner runner, @CitrusResource TestContext context) { - + void java(@CitrusResource TestCaseRunner runner, @CitrusResource TestContext context) { runner.variable("petId", "1234"); runner.when(petApi @@ -3393,7 +3230,7 @@ void java( .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(petApi .receiveGetPetById(OK) @@ -3404,7 +3241,7 @@ void java( .expression("$.name", "varName"))) ; - assertThat(context.getVariable("varContentType")).isEqualTo("application/json"); + assertThat(context.getVariable("varContentType")).isEqualTo(APPLICATION_JSON_VALUE); assertThat(context.getVariable("varName")).matches("hasso|cutie|fluffy"); } } @@ -3443,7 +3280,7 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .body(Resources.create( "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json")) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.when(extPetApi .receiveGetPetWithCookie(OK) @@ -3465,7 +3302,6 @@ void uploadFile_xml() { @Test @CitrusTest void uploadFile_java(@CitrusResource TestCaseRunner runner) { - String additionalMetadata = "myMeta"; String file = "filedata"; @@ -3481,7 +3317,7 @@ void uploadFile_java(@CitrusResource TestCaseRunner runner) { .receive() .post("/api/v3/pet/${petId}/uploadImage") .message() - .contentType("application/octet-stream") + .contentType(APPLICATION_OCTET_STREAM_VALUE) .queryParam("additionalMetadata", "myMeta") .validate((message, context) -> { Object payload = message.getPayload(); @@ -3498,7 +3334,7 @@ void uploadFile_java(@CitrusResource TestCaseRunner runner) { .body(""" {"code": 12, "type":"post-image-ok", "message":"image successfully uploaded"} """) - .contentType("application/json")); + .contentType(APPLICATION_JSON_VALUE)); runner.then(petApi .receiveUploadFile(OK) @@ -3508,4 +3344,3 @@ void uploadFile_java(@CitrusResource TestCaseRunner runner) { } } } - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java index c72a6ae179..0169704ee1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java @@ -9,7 +9,6 @@ import org.citrusframework.openapi.generator.GeneratedSoapApiIT.Config; import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; import org.citrusframework.openapi.generator.soap.bookservice.spring.BookServiceBeanConfiguration; -import org.citrusframework.util.SocketUtils; import org.citrusframework.ws.client.WebServiceClient; import org.citrusframework.ws.client.WebServiceClientBuilder; import org.citrusframework.ws.endpoint.builder.WebServiceEndpoints; @@ -22,6 +21,7 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; +import static org.citrusframework.util.SocketUtils.findAvailableTcpPort; import static org.citrusframework.ws.actions.SoapActionBuilder.soap; /** @@ -35,11 +35,9 @@ */ @ExtendWith(CitrusSpringExtension.class) -@SpringBootTest(classes = {BookServiceBeanConfiguration.class, CitrusSpringConfig.class, Config.class} -) +@SpringBootTest(classes = {BookServiceBeanConfiguration.class, CitrusSpringConfig.class, Config.class}) class GeneratedSoapApiIT { - @Autowired private WebServiceServer soapServer; @@ -49,7 +47,7 @@ class GeneratedSoapApiIT { @TestConfiguration public static class Config { - private final int wsPort = SocketUtils.findAvailableTcpPort(8090); + private final int wsPort = findAvailableTcpPort(8090); @Bean(name = {"bookstore.endpoint"}) public WebServiceClient soapClient() { @@ -114,4 +112,3 @@ void java(@CitrusResource TestCaseRunner runner) { } } } - diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java index e3244b1efc..af2b7e5543 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSpringBeanConfigurationIT.java @@ -20,8 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat; @CitrusSpringSupport -@ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, - PetStoreBeanConfiguration.class}) +@ContextConfiguration(classes = {CitrusSpringConfig.class, ClientConfiguration.class, PetStoreBeanConfiguration.class}) class GeneratedSpringBeanConfigurationIT { @Test diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java index ba582c7038..fda129439b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/util/MultipartConverter.java @@ -13,6 +13,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE; + /** * Provides utility method to convert a multipart http message to a map for simplified assertion. */ @@ -27,11 +29,8 @@ public static Map multipartMessageToMap(HttpMessage message) { String boundary = contentType.substring(contentType.indexOf("=") + 1); Map partMap = new HashMap<>(); - ByteArrayInputStream inputStream = null; - try { - inputStream = new ByteArrayInputStream(message.getPayload(String.class).getBytes()); - MultipartStream multipartStream = new MultipartStream(inputStream, boundary.getBytes(), - 4096, null); + try (ByteArrayInputStream inputStream = new ByteArrayInputStream(message.getPayload(String.class).getBytes())) { + MultipartStream multipartStream = new MultipartStream(inputStream, boundary.getBytes(), 4096, null); boolean nextPart = multipartStream.skipPreamble(); while (nextPart) { @@ -51,15 +50,12 @@ public static Map multipartMessageToMap(HttpMessage message) { } catch (IOException e) { throw new CitrusRuntimeException("Unable to parse multipart data"); } - } private static String getHeaderGroup(String headers, Pattern groupPattern) { - - Matcher m = groupPattern.matcher(headers); - - if (m.find()) { - return m.group(1); + Matcher matcher = groupPattern.matcher(headers); + if (matcher.find()) { + return matcher.group(1); } else { throw new CitrusRuntimeException( "unable to determine header group name: " + groupPattern); @@ -67,11 +63,10 @@ private static String getHeaderGroup(String headers, Pattern groupPattern) { } private static Object convertContent(String rawContent, String contentType) { - if (contentType != null) { - if (contentType.contains("application/octet-stream")) { - return rawContent.getBytes(StandardCharsets.ISO_8859_1); - } + if (contentType != null&& contentType.contains(APPLICATION_OCTET_STREAM_VALUE)) { + return rawContent.getBytes(StandardCharsets.ISO_8859_1); } + return rawContent; } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java index b3ffdcb025..a19494195a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStore.java @@ -7,5 +7,4 @@ public class ExtPetStore { public static URL extPetStoreApi() { return ExtPetStore.class.getResource("ExtPetStore_openApi.yaml"); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index eab1dca899..787be4e426 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -1,118 +1,119 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Category { - private Long id; - - private String _name; + private Long id; - public Category() { - } + private String _name; - public Category id(Long id) { + public Category() { + } - this.id = id; - return this; - } - - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable - - public Long getId() { - return id; - } + public Category id(Long id) { + + this.id = id; + return this; + } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public Category _name(String _name) { + public void setId(Long id) { + this.id = id; + } - this._name = _name; - return this; - } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nullable + public Category _name(String _name) { + + this._name = _name; + return this; + } - public String getName() { - return _name; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public void setName(String _name) { - this._name = _name; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Category category = (Category) o; - return Objects.equals(this.id, category.id) && - Objects.equals(this._name, category._name); - } + public void setName(String _name) { + this._name = _name; + } - @Override - public int hashCode() { - return Objects.hash(id, _name); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Category {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index 1518e9b85e..7b8ae8d6bf 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -1,119 +1,120 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.extpetstore.model; -import java.time.LocalDate; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.LocalDate; /** - * Additional historical data for a vaccination report, not contained in internal storage. + * Additional historical data for a vaccination report, not contained in internal storage. */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class HistoricalData { - private LocalDate lastVaccinationDate; - - private Integer vaccinationCount; + private LocalDate lastVaccinationDate; - public HistoricalData() { - } - - public HistoricalData lastVaccinationDate(LocalDate lastVaccinationDate) { - - this.lastVaccinationDate = lastVaccinationDate; - return this; - } + private Integer vaccinationCount; - /** - * The date of the last vaccination. - * - * @return lastVaccinationDate - **/ - @jakarta.annotation.Nullable + public HistoricalData() { + } - public LocalDate getLastVaccinationDate() { - return lastVaccinationDate; - } + public HistoricalData lastVaccinationDate(LocalDate lastVaccinationDate) { + + this.lastVaccinationDate = lastVaccinationDate; + return this; + } + /** + * The date of the last vaccination. + * @return lastVaccinationDate + **/ + @jakarta.annotation.Nullable - public void setLastVaccinationDate(LocalDate lastVaccinationDate) { - this.lastVaccinationDate = lastVaccinationDate; - } + public LocalDate getLastVaccinationDate() { + return lastVaccinationDate; + } - public HistoricalData vaccinationCount(Integer vaccinationCount) { + public void setLastVaccinationDate(LocalDate lastVaccinationDate) { + this.lastVaccinationDate = lastVaccinationDate; + } - this.vaccinationCount = vaccinationCount; - return this; - } - /** - * The number of vaccinations the pet has received. - * - * @return vaccinationCount - **/ - @jakarta.annotation.Nullable + public HistoricalData vaccinationCount(Integer vaccinationCount) { + + this.vaccinationCount = vaccinationCount; + return this; + } - public Integer getVaccinationCount() { - return vaccinationCount; - } + /** + * The number of vaccinations the pet has received. + * @return vaccinationCount + **/ + @jakarta.annotation.Nullable + public Integer getVaccinationCount() { + return vaccinationCount; + } - public void setVaccinationCount(Integer vaccinationCount) { - this.vaccinationCount = vaccinationCount; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - HistoricalData historicalData = (HistoricalData) o; - return Objects.equals(this.lastVaccinationDate, historicalData.lastVaccinationDate) && - Objects.equals(this.vaccinationCount, historicalData.vaccinationCount); - } + public void setVaccinationCount(Integer vaccinationCount) { + this.vaccinationCount = vaccinationCount; + } - @Override - public int hashCode() { - return Objects.hash(lastVaccinationDate, vaccinationCount); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class HistoricalData {\n"); - sb.append(" lastVaccinationDate: ").append(toIndentedString(lastVaccinationDate)).append("\n"); - sb.append(" vaccinationCount: ").append(toIndentedString(vaccinationCount)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + HistoricalData historicalData = (HistoricalData) o; + return Objects.equals(this.lastVaccinationDate, historicalData.lastVaccinationDate) && + Objects.equals(this.vaccinationCount, historicalData.vaccinationCount); + } + + @Override + public int hashCode() { + return Objects.hash(lastVaccinationDate, vaccinationCount); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class HistoricalData {\n"); + sb.append(" lastVaccinationDate: ").append(toIndentedString(lastVaccinationDate)).append("\n"); + sb.append(" vaccinationCount: ").append(toIndentedString(vaccinationCount)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index f83c998f23..c1d0601195 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -1,270 +1,279 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.extpetstore.model; -import org.citrusframework.openapi.generator.rest.extpetstore.model.Category; -import org.citrusframework.openapi.generator.rest.extpetstore.model.Tag; - +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Objects; +import org.citrusframework.openapi.generator.rest.extpetstore.model.Category; +import org.citrusframework.openapi.generator.rest.extpetstore.model.Tag; /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Pet { - private Long id; + private Long id; - private String _name; + private String _name; - private Category category; + private Category category; - private List photoUrls = new ArrayList<>(); + private List photoUrls = new ArrayList<>(); - private List tags = new ArrayList<>(); - private StatusEnum status; + private List tags = new ArrayList<>(); - public Pet() { - } + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + + PENDING("pending"), + + SOLD("sold"); - public Pet id(Long id) { + private String value; - this.id = id; - return this; + StatusEnum(String value) { + this.value = value; } - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable + public String getValue() { + return value; + } - public Long getId() { - return id; + @Override + public String toString() { + return String.valueOf(value); } - public void setId(Long id) { - this.id = id; + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); } + } - public Pet _name(String _name) { + private StatusEnum status; - this._name = _name; - return this; - } + public Pet() { + } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nonnull + public Pet id(Long id) { + + this.id = id; + return this; + } - public String getName() { - return _name; - } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setName(String _name) { - this._name = _name; - } + public Long getId() { + return id; + } - public Pet category(Category category) { - this.category = category; - return this; - } + public void setId(Long id) { + this.id = id; + } - /** - * Get category - * - * @return category - **/ - @jakarta.annotation.Nullable - public Category getCategory() { - return category; - } + public Pet _name(String _name) { + + this._name = _name; + return this; + } - public void setCategory(Category category) { - this.category = category; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nonnull - public Pet photoUrls(List photoUrls) { + public String getName() { + return _name; + } - this.photoUrls = photoUrls; - return this; - } - public Pet addPhotoUrlsItem(String photoUrlsItem) { - if (this.photoUrls == null) { - this.photoUrls = new ArrayList<>(); - } - this.photoUrls.add(photoUrlsItem); - return this; - } + public void setName(String _name) { + this._name = _name; + } - /** - * Get photoUrls - * - * @return photoUrls - **/ - @jakarta.annotation.Nonnull - public List getPhotoUrls() { - return photoUrls; - } + public Pet category(Category category) { + + this.category = category; + return this; + } - public void setPhotoUrls(List photoUrls) { - this.photoUrls = photoUrls; - } + /** + * Get category + * @return category + **/ + @jakarta.annotation.Nullable - public Pet tags(List tags) { + public Category getCategory() { + return category; + } - this.tags = tags; - return this; - } - public Pet addTagsItem(Tag tagsItem) { - if (this.tags == null) { - this.tags = new ArrayList<>(); - } - this.tags.add(tagsItem); - return this; - } + public void setCategory(Category category) { + this.category = category; + } - /** - * Get tags - * - * @return tags - **/ - @jakarta.annotation.Nullable - public List getTags() { - return tags; - } + public Pet photoUrls(List photoUrls) { + + this.photoUrls = photoUrls; + return this; + } - public void setTags(List tags) { - this.tags = tags; + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); } + this.photoUrls.add(photoUrlsItem); + return this; + } - public Pet status(StatusEnum status) { + /** + * Get photoUrls + * @return photoUrls + **/ + @jakarta.annotation.Nonnull - this.status = status; - return this; - } + public List getPhotoUrls() { + return photoUrls; + } - /** - * pet status in the store - * - * @return status - **/ - @jakarta.annotation.Nullable - public StatusEnum getStatus() { - return status; - } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } - public void setStatus(StatusEnum status) { - this.status = status; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Pet pet = (Pet) o; - return Objects.equals(this.id, pet.id) && - Objects.equals(this._name, pet._name) && - Objects.equals(this.category, pet.category) && - Objects.equals(this.photoUrls, pet.photoUrls) && - Objects.equals(this.tags, pet.tags) && - Objects.equals(this.status, pet.status); - } + public Pet tags(List tags) { + + this.tags = tags; + return this; + } - @Override - public int hashCode() { - return Objects.hash(id, _name, category, photoUrls, tags, status); + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); } + this.tags.add(tagsItem); + return this; + } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Pet {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append(" category: ").append(toIndentedString(category)).append("\n"); - sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); - sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append("}"); - return sb.toString(); - } + /** + * Get tags + * @return tags + **/ + @jakarta.annotation.Nullable - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + public List getTags() { + return tags; + } - /** - * pet status in the store - */ - public enum StatusEnum { - AVAILABLE("available"), - PENDING("pending"), + public void setTags(List tags) { + this.tags = tags; + } - SOLD("sold"); - private String value; + public Pet status(StatusEnum status) { + + this.status = status; + return this; + } - StatusEnum(String value) { - this.value = value; - } + /** + * pet status in the store + * @return status + **/ + @jakarta.annotation.Nullable - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } + public StatusEnum getStatus() { + return status; + } - public String getValue() { - return value; - } - @Override - public String toString() { - return String.valueOf(value); - } + public void setStatus(StatusEnum status) { + this.status = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name, category, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java new file mode 100644 index 0000000000..b1631a9618 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java @@ -0,0 +1,119 @@ +/* +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package org.citrusframework.openapi.generator.rest.extpetstore.model; + +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; + +/** + * PetIdentifier + */ +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetIdentifier { + private String _name; + + private String alias; + + public PetIdentifier() { + } + + public PetIdentifier _name(String _name) { + + this._name = _name; + return this; + } + + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + + public String getName() { + return _name; + } + + + public void setName(String _name) { + this._name = _name; + } + + + public PetIdentifier alias(String alias) { + + this.alias = alias; + return this; + } + + /** + * Get alias + * @return alias + **/ + @jakarta.annotation.Nullable + + public String getAlias() { + return alias; + } + + + public void setAlias(String alias) { + this.alias = alias; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PetIdentifier petIdentifier = (PetIdentifier) o; + return Objects.equals(this._name, petIdentifier._name) && + Objects.equals(this.alias, petIdentifier.alias); + } + + @Override + public int hashCode() { + return Objects.hash(_name, alias); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class PetIdentifier {\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" alias: ").append(toIndentedString(alias)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + +} + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index 6286eacf72..952ae944a0 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -1,118 +1,119 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Tag { - private Long id; - - private String _name; + private Long id; - public Tag() { - } + private String _name; - public Tag id(Long id) { + public Tag() { + } - this.id = id; - return this; - } - - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable - - public Long getId() { - return id; - } + public Tag id(Long id) { + + this.id = id; + return this; + } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public Tag _name(String _name) { + public void setId(Long id) { + this.id = id; + } - this._name = _name; - return this; - } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nullable + public Tag _name(String _name) { + + this._name = _name; + return this; + } - public String getName() { - return _name; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public void setName(String _name) { - this._name = _name; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Tag tag = (Tag) o; - return Objects.equals(this.id, tag.id) && - Objects.equals(this._name, tag._name); - } + public void setName(String _name) { + this._name = _name; + } - @Override - public int hashCode() { - return Objects.hash(id, _name); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Tag {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 37c83480a2..215e486b93 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -1,91 +1,93 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.extpetstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * VaccinationDocumentResult */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class VaccinationDocumentResult { - private String documentId; - - public VaccinationDocumentResult() { - } + private String documentId; - public VaccinationDocumentResult documentId(String documentId) { - - this.documentId = documentId; - return this; - } + public VaccinationDocumentResult() { + } - /** - * The unique ID of the uploaded vaccination document. - * - * @return documentId - **/ - @jakarta.annotation.Nullable + public VaccinationDocumentResult documentId(String documentId) { + + this.documentId = documentId; + return this; + } - public String getDocumentId() { - return documentId; - } + /** + * The unique ID of the uploaded vaccination document. + * @return documentId + **/ + @jakarta.annotation.Nullable + public String getDocumentId() { + return documentId; + } - public void setDocumentId(String documentId) { - this.documentId = documentId; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - VaccinationDocumentResult vaccinationDocumentResult = (VaccinationDocumentResult) o; - return Objects.equals(this.documentId, vaccinationDocumentResult.documentId); - } + public void setDocumentId(String documentId) { + this.documentId = documentId; + } - @Override - public int hashCode() { - return Objects.hash(documentId); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class VaccinationDocumentResult {\n"); - sb.append(" documentId: ").append(toIndentedString(documentId)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + VaccinationDocumentResult vaccinationDocumentResult = (VaccinationDocumentResult) o; + return Objects.equals(this.documentId, vaccinationDocumentResult.documentId); + } + + @Override + public int hashCode() { + return Objects.hash(documentId); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class VaccinationDocumentResult {\n"); + sb.append(" documentId: ").append(toIndentedString(documentId)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index 271c5ce2ce..40c3ada71e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -1,61 +1,73 @@ package org.citrusframework.openapi.generator.rest.extpetstore.request; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; -import org.citrusframework.openapi.generator.rest.extpetstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.TestApiUtils; import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import java.math.BigDecimal; -import java.net.URL; -import java.time.LocalDate; -import java.util.List; -import java.util.Map; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static org.citrusframework.util.StringUtils.isEmpty; -import static org.citrusframework.util.StringUtils.isNotEmpty; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; +import org.citrusframework.openapi.generator.rest.extpetstore.model.*; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class ExtPetApi implements GeneratedApi { +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class ExtPetApi implements GeneratedApi +{ - private final List customizers; - private final Endpoint endpoint; - private final OpenApiSpecification openApiSpecification; @Value("${" + "extpetstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; + @Value("${" + "extpetstore.basic.username:#{null}}") private String basicUsername; + @Value("${" + "extpetstore.basic.password:#{null}}") private String basicPassword; + @Value("${" + "extpetstore.bearer.token:#{null}}") private String basicAuthBearer; + @Value("${" + "extpetstore.api-key-header:#{null}}") private String defaultApiKeyHeader; + @Value("${" + "extpetstore.api-key-cookie:#{null}}") private String defaultApiKeyCookie; + @Value("${" + "extpetstore.api-key-query:#{null}}") private String defaultApiKeyQuery; - public ExtPetApi(Endpoint endpoint) { + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public ExtPetApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public ExtPetApi(Endpoint endpoint, List customizers) { + public ExtPetApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -103,731 +115,731 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport(Resource template, Integer reqIntVal) { - return new GenerateVaccinationReportSendActionBuilder(this, openApiSpecification, template, reqIntVal); + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport(Resource template, Integer reqIntVal) { + return new GenerateVaccinationReportSendActionBuilder(this, openApiSpecification, template, reqIntVal); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport$(String templateExpression, String reqIntValExpression) { - return new GenerateVaccinationReportSendActionBuilder(openApiSpecification, this, templateExpression, reqIntValExpression); + public GenerateVaccinationReportSendActionBuilder sendGenerateVaccinationReport$(String templateExpression, String reqIntValExpression ) { + return new GenerateVaccinationReportSendActionBuilder(openApiSpecification, this, templateExpression, reqIntValExpression); } - public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull HttpStatus statusCode) { + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull HttpStatus statusCode) { return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull String statusCode) { - return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, statusCode); + public GenerateVaccinationReportReceiveActionBuilder receiveGenerateVaccinationReport(@NotNull String statusCode) { + return new GenerateVaccinationReportReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication$(String petIdExpression, String allDetailsExpression) { - GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - builder.setApiKeyQuery(defaultApiKeyQuery); - builder.setApiKeyHeader(defaultApiKeyHeader); - builder.setApiKeyCookie(defaultApiKeyCookie); - return builder; + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder sendGetPetByIdWithApiKeyAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithApiKeyAuthenticationSendActionBuilder builder = new GetPetByIdWithApiKeyAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKeyQuery(defaultApiKeyQuery); + builder.setApiKeyHeader(defaultApiKeyHeader); + builder.setApiKeyCookie(defaultApiKeyCookie); + return builder; } - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder receiveGetPetByIdWithApiKeyAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - return builder; + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication$(String petIdExpression, String allDetailsExpression) { - GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBasicAuthUsername(basicUsername); - builder.setBasicAuthPassword(basicPassword); - return builder; + public GetPetByIdWithBasicAuthenticationSendActionBuilder sendGetPetByIdWithBasicAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithBasicAuthenticationSendActionBuilder builder = new GetPetByIdWithBasicAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthUsername(basicUsername); + builder.setBasicAuthPassword(basicPassword); + return builder; } - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder receiveGetPetByIdWithBasicAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBasicAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication(Long petId, Boolean allDetails) { - GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); - return builder; + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication(Long petId, Boolean allDetails) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(this, openApiSpecification, petId, allDetails); + return builder; } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication$(String petIdExpression, String allDetailsExpression) { - GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); - builder.setBasicAuthBearer(basicAuthBearer); - return builder; + public GetPetByIdWithBearerAuthenticationSendActionBuilder sendGetPetByIdWithBearerAuthentication$(String petIdExpression, String allDetailsExpression ) { + GetPetByIdWithBearerAuthenticationSendActionBuilder builder = new GetPetByIdWithBearerAuthenticationSendActionBuilder(openApiSpecification, this, petIdExpression, allDetailsExpression); + builder.setBasicAuthBearer(basicAuthBearer); + return builder; } - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull HttpStatus statusCode) { + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull HttpStatus statusCode) { return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull String statusCode) { - return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder receiveGetPetByIdWithBearerAuthentication(@NotNull String statusCode) { + return new GetPetByIdWithBearerAuthenticationReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithCookieSendActionBuilder sendGetPetWithCookie(Long petId, String sessionId) { - return new GetPetWithCookieSendActionBuilder(this, openApiSpecification, petId, sessionId); + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie(Long petId, String sessionId) { + return new GetPetWithCookieSendActionBuilder(this, openApiSpecification, petId, sessionId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithCookieSendActionBuilder sendGetPetWithCookie$(String petIdExpression, String sessionIdExpression) { - return new GetPetWithCookieSendActionBuilder(openApiSpecification, this, petIdExpression, sessionIdExpression); + public GetPetWithCookieSendActionBuilder sendGetPetWithCookie$(String petIdExpression, String sessionIdExpression ) { + return new GetPetWithCookieSendActionBuilder(openApiSpecification, this, petIdExpression, sessionIdExpression); } - public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull HttpStatus statusCode) { + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull HttpStatus statusCode) { return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull String statusCode) { - return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithCookieReceiveActionBuilder receiveGetPetWithCookie(@NotNull String statusCode) { + return new GetPetWithCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery(PetIdentifier petId) { - return new GetPetWithDeepObjectTypeQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery(PetIdentifier petId) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery$(String petIdExpression) { - return new GetPetWithDeepObjectTypeQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithDeepObjectTypeQuerySendActionBuilder sendGetPetWithDeepObjectTypeQuery$(String petIdExpression ) { + return new GetPetWithDeepObjectTypeQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull HttpStatus statusCode) { + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull HttpStatus statusCode) { return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull String statusCode) { - return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder receiveGetPetWithDeepObjectTypeQuery(@NotNull String statusCode) { + return new GetPetWithDeepObjectTypeQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie(List petId) { - return new GetPetWithFormExplodedStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie(List petId) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie$(List petIdExpression) { - return new GetPetWithFormExplodedStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormExplodedStyleCookieSendActionBuilder sendGetPetWithFormExplodedStyleCookie$(List petIdExpression ) { + return new GetPetWithFormExplodedStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder receiveGetPetWithFormExplodedStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormExplodedStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie(PetIdentifier petId) { - return new GetPetWithFormObjectStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie(PetIdentifier petId) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie$(String petIdExpression) { - return new GetPetWithFormObjectStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormObjectStyleCookieSendActionBuilder sendGetPetWithFormObjectStyleCookie$(String petIdExpression ) { + return new GetPetWithFormObjectStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormObjectStyleCookieReceiveActionBuilder receiveGetPetWithFormObjectStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormObjectStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie(List petId) { - return new GetPetWithFormStyleCookieSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie(List petId) { + return new GetPetWithFormStyleCookieSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie$(List petIdExpression) { - return new GetPetWithFormStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleCookieSendActionBuilder sendGetPetWithFormStyleCookie$(List petIdExpression ) { + return new GetPetWithFormStyleCookieSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull String statusCode) { - return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleCookieReceiveActionBuilder receiveGetPetWithFormStyleCookie(@NotNull String statusCode) { + return new GetPetWithFormStyleCookieReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery(PetIdentifier petId) { - return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery$(String petIdExpression) { - return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder sendGetPetWithFormStyleExplodedObjectQuery$(String petIdExpression ) { + return new GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery(List petId) { - return new GetPetWithFormStyleExplodedQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery(List petId) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery$(List petIdExpression) { - return new GetPetWithFormStyleExplodedQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleExplodedQuerySendActionBuilder sendGetPetWithFormStyleExplodedQuery$(List petIdExpression ) { + return new GetPetWithFormStyleExplodedQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder receiveGetPetWithFormStyleExplodedQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleExplodedQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery(PetIdentifier petId) { - return new GetPetWithFormStyleObjectQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery(PetIdentifier petId) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery$(String petIdExpression) { - return new GetPetWithFormStyleObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleObjectQuerySendActionBuilder sendGetPetWithFormStyleObjectQuery$(String petIdExpression ) { + return new GetPetWithFormStyleObjectQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleObjectQueryReceiveActionBuilder receiveGetPetWithFormStyleObjectQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleObjectQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery(List petId) { - return new GetPetWithFormStyleQuerySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery(List petId) { + return new GetPetWithFormStyleQuerySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery$(List petIdExpression) { - return new GetPetWithFormStyleQuerySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithFormStyleQuerySendActionBuilder sendGetPetWithFormStyleQuery$(List petIdExpression ) { + return new GetPetWithFormStyleQuerySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull HttpStatus statusCode) { + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull HttpStatus statusCode) { return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull String statusCode) { - return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithFormStyleQueryReceiveActionBuilder receiveGetPetWithFormStyleQuery(@NotNull String statusCode) { + return new GetPetWithFormStyleQueryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray(List petId) { - return new GetPetWithLabelStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray(List petId) { + return new GetPetWithLabelStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray$(List petIdExpression) { - return new GetPetWithLabelStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleArraySendActionBuilder sendGetPetWithLabelStyleArray$(List petIdExpression ) { + return new GetPetWithLabelStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull String statusCode) { - return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleArrayReceiveActionBuilder receiveGetPetWithLabelStyleArray(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded(List petId) { - return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded(List petId) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded$(List petIdExpression) { - return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder sendGetPetWithLabelStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithLabelStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder receiveGetPetWithLabelStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject(PetIdentifier petId) { - return new GetPetWithLabelStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject$(String petIdExpression) { - return new GetPetWithLabelStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleObjectSendActionBuilder sendGetPetWithLabelStyleObject$(String petIdExpression ) { + return new GetPetWithLabelStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull String statusCode) { - return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleObjectReceiveActionBuilder receiveGetPetWithLabelStyleObject(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded$(String petIdExpression) { - return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder sendGetPetWithLabelStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithLabelStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder receiveGetPetWithLabelStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray(List petId) { - return new GetPetWithMatrixStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray(List petId) { + return new GetPetWithMatrixStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray$(List petIdExpression) { - return new GetPetWithMatrixStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleArraySendActionBuilder sendGetPetWithMatrixStyleArray$(List petIdExpression ) { + return new GetPetWithMatrixStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull String statusCode) { - return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleArrayReceiveActionBuilder receiveGetPetWithMatrixStyleArray(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded(List petId) { - return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded(List petId) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded$(List petIdExpression) { - return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder sendGetPetWithMatrixStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithMatrixStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject(PetIdentifier petId) { - return new GetPetWithMatrixStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject$(String petIdExpression) { - return new GetPetWithMatrixStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleObjectSendActionBuilder sendGetPetWithMatrixStyleObject$(String petIdExpression ) { + return new GetPetWithMatrixStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull String statusCode) { - return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleObjectReceiveActionBuilder receiveGetPetWithMatrixStyleObject(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded$(String petIdExpression) { - return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder sendGetPetWithMatrixStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithMatrixStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWithMatrixStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray(List petId) { - return new GetPetWithSimpleStyleArraySendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray(List petId) { + return new GetPetWithSimpleStyleArraySendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray$(List petIdExpression) { - return new GetPetWithSimpleStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleArraySendActionBuilder sendGetPetWithSimpleStyleArray$(List petIdExpression ) { + return new GetPetWithSimpleStyleArraySendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull String statusCode) { - return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleArrayReceiveActionBuilder receiveGetPetWithSimpleStyleArray(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded(List petId) { - return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded(List petId) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded$(List petIdExpression) { - return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder sendGetPetWithSimpleStyleArrayExploded$(List petIdExpression ) { + return new GetPetWithSimpleStyleArrayExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull String statusCode) { - return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleArrayExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader(List petId) { - return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader(List petId) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader$(List petIdExpression) { - return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedHeader$(List petIdExpression ) { + return new GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader(PetIdentifier petId) { - return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader$(String petIdExpression) { - return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleExplodedObjectHeader$(String petIdExpression ) { + return new GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleExplodedObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader(List petId) { - return new GetPetWithSimpleStyleHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader(List petId) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader$(List petIdExpression) { - return new GetPetWithSimpleStyleHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleHeaderSendActionBuilder sendGetPetWithSimpleStyleHeader$(List petIdExpression ) { + return new GetPetWithSimpleStyleHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject$(String petIdExpression) { - return new GetPetWithSimpleStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectSendActionBuilder sendGetPetWithSimpleStyleObject$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectReceiveActionBuilder receiveGetPetWithSimpleStyleObject(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded$(String petIdExpression) { - return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder sendGetPetWithSimpleStyleObjectExploded$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectExplodedSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder receiveGetPetWithSimpleStyleObjectExploded(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader(PetIdentifier petId) { - return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(this, openApiSpecification, petId); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader(PetIdentifier petId) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader$(String petIdExpression) { - return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder sendGetPetWithSimpleStyleObjectHeader$(String petIdExpression ) { + return new GetPetWithSimpleStyleObjectHeaderSendActionBuilder(openApiSpecification, this, petIdExpression); } - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull HttpStatus statusCode) { + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull HttpStatus statusCode) { return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull String statusCode) { - return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSimpleStyleObjectHeader(@NotNull String statusCode) { + return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PostVaccinationDocumentSendActionBuilder sendPostVaccinationDocument(String bucket, String filename) { - return new PostVaccinationDocumentSendActionBuilder(this, openApiSpecification, bucket, filename); + public PostVaccinationDocumentSendActionBuilder sendPostVaccinationDocument(String bucket, String filename) { + return new PostVaccinationDocumentSendActionBuilder(this, openApiSpecification, bucket, filename); } - public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull HttpStatus statusCode) { + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull HttpStatus statusCode) { return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull String statusCode) { - return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, statusCode); + public PostVaccinationDocumentReceiveActionBuilder receivePostVaccinationDocument(@NotNull String statusCode) { + return new PostVaccinationDocumentReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PostVaccinationFormDataSendActionBuilder sendPostVaccinationFormData() { - return new PostVaccinationFormDataSendActionBuilder(this, openApiSpecification); + public PostVaccinationFormDataSendActionBuilder sendPostVaccinationFormData() { + return new PostVaccinationFormDataSendActionBuilder(this, openApiSpecification); } - public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull HttpStatus statusCode) { + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull HttpStatus statusCode) { return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull String statusCode) { - return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, statusCode); + public PostVaccinationFormDataReceiveActionBuilder receivePostVaccinationFormData(@NotNull String statusCode) { + return new PostVaccinationFormDataReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData(Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { - return new UpdatePetWithArrayQueryDataSendActionBuilder(this, openApiSpecification, petId, _name, status, tags, nicknames, sampleStringHeader); + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData(Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(this, openApiSpecification, petId, _name, status, tags, nicknames, sampleStringHeader); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData$(String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { - return new UpdatePetWithArrayQueryDataSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, tagsExpression, nicknamesExpression, sampleStringHeaderExpression); + public UpdatePetWithArrayQueryDataSendActionBuilder sendUpdatePetWithArrayQueryData$(String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression ) { + return new UpdatePetWithArrayQueryDataSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, tagsExpression, nicknamesExpression, sampleStringHeaderExpression); } - public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull HttpStatus statusCode) { + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull HttpStatus statusCode) { return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull String statusCode) { - return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithArrayQueryDataReceiveActionBuilder receiveUpdatePetWithArrayQueryData(@NotNull String statusCode) { + return new UpdatePetWithArrayQueryDataReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded(Long petId, String _name, String status, Integer age, List tags) { - return new UpdatePetWithFormUrlEncodedSendActionBuilder(this, openApiSpecification, petId, _name, status, age, tags); + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded(Long petId, String _name, String status, Integer age, List tags) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(this, openApiSpecification, petId, _name, status, age, tags); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded$(String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { - return new UpdatePetWithFormUrlEncodedSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, ageExpression, tagsExpression); + public UpdatePetWithFormUrlEncodedSendActionBuilder sendUpdatePetWithFormUrlEncoded$(String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression ) { + return new UpdatePetWithFormUrlEncodedSendActionBuilder(openApiSpecification, this, petIdExpression, _nameExpression, statusExpression, ageExpression, tagsExpression); } - public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull HttpStatus statusCode) { + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull HttpStatus statusCode) { return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull String statusCode) { - return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithFormUrlEncodedReceiveActionBuilder receiveUpdatePetWithFormUrlEncoded(@NotNull String statusCode) { + return new UpdatePetWithFormUrlEncodedReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class GenerateVaccinationReportSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -840,17 +852,17 @@ public static class GenerateVaccinationReportSendActionBuilder extends */ public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Resource template, Integer reqIntVal) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(template)); - formParameter("reqIntVal", reqIntVal); + formParameter("template", toBinary(template) ); + formParameter("reqIntVal", reqIntVal); } /** * Constructor with required parameters as string to allow for dynamic content. */ - public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String templateExpression, String reqIntValExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(templateExpression)); - formParameter("reqIntVal", reqIntValExpression); + public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String templateExpression, String reqIntValExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + formParameter("template", toBinary(templateExpression) ); + formParameter("reqIntVal", reqIntValExpression); } /** @@ -858,145 +870,145 @@ public GenerateVaccinationReportSendActionBuilder(OpenApiSpecification openApiSp */ public GenerateVaccinationReportSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String templateExpression, String reqIntValExpression) { super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); - formParameter("template", toBinary(templateExpression)); - formParameter("reqIntVal", reqIntValExpression); + formParameter("template", toBinary(templateExpression) ); + formParameter("reqIntVal", reqIntValExpression); } public GenerateVaccinationReportSendActionBuilder template(Resource template) { - formParameter("template", toBinary(template)); + formParameter("template", toBinary(template) ); return this; } public GenerateVaccinationReportSendActionBuilder template(String templateExpression) { - formParameter("template", toBinary(templateExpression)); - return this; + formParameter("template", toBinary(templateExpression) ); + return this; } public GenerateVaccinationReportSendActionBuilder reqIntVal(Integer reqIntVal) { - formParameter("reqIntVal", reqIntVal); + formParameter("reqIntVal", reqIntVal); return this; } public GenerateVaccinationReportSendActionBuilder reqIntVal(String reqIntValExpression) { - formParameter("reqIntVal", reqIntValExpression); - return this; + formParameter("reqIntVal", reqIntValExpression); + return this; } public GenerateVaccinationReportSendActionBuilder optIntVal(Integer optIntVal) { - formParameter("optIntVal", optIntVal); + formParameter("optIntVal", optIntVal); return this; } public void setOptIntVal(Integer optIntVal) { - formParameter("optIntVal", optIntVal); + formParameter("optIntVal", optIntVal); } public GenerateVaccinationReportSendActionBuilder optIntVal(String optIntValExpression) { - formParameter("optIntVal", optIntValExpression); + formParameter("optIntVal", optIntValExpression); return this; } public void setOptIntVal(String optIntValExpression) { - formParameter("optIntVal", optIntValExpression); + formParameter("optIntVal", optIntValExpression); } public GenerateVaccinationReportSendActionBuilder optBoolVal(Boolean optBoolVal) { - formParameter("optBoolVal", optBoolVal); + formParameter("optBoolVal", optBoolVal); return this; } public void setOptBoolVal(Boolean optBoolVal) { - formParameter("optBoolVal", optBoolVal); + formParameter("optBoolVal", optBoolVal); } public GenerateVaccinationReportSendActionBuilder optBoolVal(String optBoolValExpression) { - formParameter("optBoolVal", optBoolValExpression); + formParameter("optBoolVal", optBoolValExpression); return this; } public void setOptBoolVal(String optBoolValExpression) { - formParameter("optBoolVal", optBoolValExpression); + formParameter("optBoolVal", optBoolValExpression); } public GenerateVaccinationReportSendActionBuilder optNumberVal(BigDecimal optNumberVal) { - formParameter("optNumberVal", optNumberVal); + formParameter("optNumberVal", optNumberVal); return this; } public void setOptNumberVal(BigDecimal optNumberVal) { - formParameter("optNumberVal", optNumberVal); + formParameter("optNumberVal", optNumberVal); } public GenerateVaccinationReportSendActionBuilder optNumberVal(String optNumberValExpression) { - formParameter("optNumberVal", optNumberValExpression); + formParameter("optNumberVal", optNumberValExpression); return this; } public void setOptNumberVal(String optNumberValExpression) { - formParameter("optNumberVal", optNumberValExpression); + formParameter("optNumberVal", optNumberValExpression); } public GenerateVaccinationReportSendActionBuilder optStringVal(String optStringVal) { - formParameter("optStringVal", optStringVal); + formParameter("optStringVal", optStringVal); return this; } public void setOptStringVal(String optStringVal) { - formParameter("optStringVal", optStringVal); + formParameter("optStringVal", optStringVal); } public GenerateVaccinationReportSendActionBuilder optDateVal(LocalDate optDateVal) { - formParameter("optDateVal", optDateVal); + formParameter("optDateVal", optDateVal); return this; } public void setOptDateVal(LocalDate optDateVal) { - formParameter("optDateVal", optDateVal); + formParameter("optDateVal", optDateVal); } public GenerateVaccinationReportSendActionBuilder optDateVal(String optDateValExpression) { - formParameter("optDateVal", optDateValExpression); + formParameter("optDateVal", optDateValExpression); return this; } public void setOptDateVal(String optDateValExpression) { - formParameter("optDateVal", optDateValExpression); + formParameter("optDateVal", optDateValExpression); } public GenerateVaccinationReportSendActionBuilder additionalData(HistoricalData additionalData) { - formParameter("additionalData", additionalData); + formParameter("additionalData", additionalData); return this; } public void setAdditionalData(HistoricalData additionalData) { - formParameter("additionalData", additionalData); + formParameter("additionalData", additionalData); } public GenerateVaccinationReportSendActionBuilder additionalData(String additionalDataExpression) { - formParameter("additionalData", additionalDataExpression); + formParameter("additionalData", additionalDataExpression); return this; } public void setAdditionalData(String additionalDataExpression) { - formParameter("additionalData", additionalDataExpression); + formParameter("additionalData", additionalDataExpression); } public GenerateVaccinationReportSendActionBuilder schema(Resource schema) { - formParameter("schema", toBinary(schema)); + formParameter("schema", toBinary(schema) ); return this; } public void setSchema(Resource schema) { - formParameter("schema", toBinary(schema)); + formParameter("schema", toBinary(schema) ); } public GenerateVaccinationReportSendActionBuilder schema(String schemaExpression) { - formParameter("schema", toBinary(schemaExpression)); + formParameter("schema", toBinary(schemaExpression) ); return this; } public void setSchema(String schemaExpression) { - formParameter("schema", toBinary(schemaExpression)); + formParameter("schema", toBinary(schemaExpression) ); } @Override @@ -1011,7 +1023,7 @@ public SendMessageAction doBuild() { } public static class GenerateVaccinationReportReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -1019,7 +1031,7 @@ public static class GenerateVaccinationReportReceiveActionBuilder extends private static final String OPERATION_NAME = "generateVaccinationReport"; - public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GenerateVaccinationReportReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1040,7 +1052,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithApiKeyAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1078,8 +1090,8 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1100,7 +1112,7 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithApiKeyAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1110,24 +1122,24 @@ public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(Boolean al public GetPetByIdWithApiKeyAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder details(String... details) { + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder details(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String... details) { + public void setDetails(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithApiKeyAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { + public GetPetByIdWithApiKeyAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String... requesterInformation) { + public void setRequesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1177,7 +1189,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1185,7 +1197,7 @@ public static class GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetByIdWithApiKeyAuthentication"; - public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1206,7 +1218,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithBasicAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1236,8 +1248,8 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBasicAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithBasicAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1258,7 +1270,7 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithBasicAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1268,24 +1280,24 @@ public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(Boolean all public GetPetByIdWithBasicAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithBasicAuthenticationSendActionBuilder details(String... details) { + public GetPetByIdWithBasicAuthenticationSendActionBuilder details(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String... details) { + public void setDetails(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithBasicAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { + public GetPetByIdWithBasicAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String... requesterInformation) { + public void setRequesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1308,11 +1320,11 @@ public void setBasicAuthPassword(String password) { } protected void addBasicAuthHeader(String basicUsername, String basicPassword, - HttpMessageBuilderSupport messageBuilderSupport) { + HttpMessageBuilderSupport messageBuilderSupport) { TestApiUtils.addBasicAuthHeader( - isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, - isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, - messageBuilderSupport); + isNotEmpty(basicUsername) ? basicUsername : defaultBasicUsername, + isNotEmpty(basicPassword) ? basicPassword : defaultBasicPassword, + messageBuilderSupport); } @Override @@ -1328,7 +1340,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithBasicAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1336,7 +1348,7 @@ public static class GetPetByIdWithBasicAuthenticationReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetByIdWithBasicAuthentication"; - public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithBasicAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1357,7 +1369,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdWithBearerAuthenticationSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1382,8 +1394,8 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdWithBearerAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdWithBearerAuthenticationSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String allDetailsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); } @@ -1404,7 +1416,7 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(Long petId) { public GetPetByIdWithBearerAuthenticationSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(Boolean allDetails) { @@ -1414,24 +1426,24 @@ public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(Boolean al public GetPetByIdWithBearerAuthenticationSendActionBuilder allDetails(String allDetailsExpression) { queryParameter("allDetails", allDetailsExpression, ParameterStyle.FORM, true, false); - return this; + return this; } - public GetPetByIdWithBearerAuthenticationSendActionBuilder details(String... details) { + public GetPetByIdWithBearerAuthenticationSendActionBuilder details(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); return this; } - public void setDetails(String... details) { + public void setDetails(String...details) { queryParameter("details", details, ParameterStyle.FORM, true, false); } - public GetPetByIdWithBearerAuthenticationSendActionBuilder requesterInformation(String... requesterInformation) { + public GetPetByIdWithBearerAuthenticationSendActionBuilder requesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); return this; } - public void setRequesterInformation(String... requesterInformation) { + public void setRequesterInformation(String...requesterInformation) { queryParameter("requesterInformation", requesterInformation, ParameterStyle.FORM, true, false); } @@ -1447,7 +1459,7 @@ public void setBasicAuthBearer(String basicAuthBearer) { @Override public SendMessageAction doBuild() { if (!isEmpty(basicAuthBearer) || !isEmpty(defaultBasicAuthBearer)) { - headerParameter("Authorization", "Bearer " + getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); + headerParameter("Authorization", "Bearer " +getOrDefault(basicAuthBearer, defaultBasicAuthBearer, true)); } if (getCustomizers() != null) { @@ -1459,7 +1471,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdWithBearerAuthenticationReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1467,7 +1479,7 @@ public static class GetPetByIdWithBearerAuthenticationReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetByIdWithBearerAuthentication"; - public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdWithBearerAuthenticationReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1488,7 +1500,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1508,8 +1520,8 @@ public GetPetWithCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecificati /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String sessionIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String sessionIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); cookieParameter("session_id", sessionIdExpression, ParameterStyle.FORM, true, false); } @@ -1530,7 +1542,7 @@ public GetPetWithCookieSendActionBuilder petId(Long petId) { public GetPetWithCookieSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public GetPetWithCookieSendActionBuilder sessionId(String sessionId) { @@ -1559,7 +1571,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1567,7 +1579,7 @@ public static class GetPetWithCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithCookie"; - public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1588,7 +1600,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithDeepObjectTypeQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1607,8 +1619,8 @@ public GetPetWithDeepObjectTypeQuerySendActionBuilder(ExtPetApi extPetApi, OpenA /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithDeepObjectTypeQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithDeepObjectTypeQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); } @@ -1627,7 +1639,7 @@ public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(PetIdentifier petId) public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.DEEPOBJECT, true, true); - return this; + return this; } @Override @@ -1642,7 +1654,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithDeepObjectTypeQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1650,7 +1662,7 @@ public static class GetPetWithDeepObjectTypeQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithDeepObjectTypeQuery"; - public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithDeepObjectTypeQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1671,7 +1683,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormExplodedStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1690,8 +1702,8 @@ public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormExplodedStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormExplodedStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); } @@ -1703,14 +1715,14 @@ public GetPetWithFormExplodedStyleCookieSendActionBuilder(ExtPetApi extPetApi, O cookieParameter("petId", petId, ParameterStyle.FORM, true, false); } - public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(Integer... petId) { + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(Integer...petId) { cookieParameter("petId", petId, ParameterStyle.FORM, true, false); return this; } - public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String... petIdExpression) { + public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String...petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); - return this; + return this; } @Override @@ -1725,7 +1737,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormExplodedStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1733,7 +1745,7 @@ public static class GetPetWithFormExplodedStyleCookieReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithFormExplodedStyleCookie"; - public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormExplodedStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1754,7 +1766,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormObjectStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1773,8 +1785,8 @@ public GetPetWithFormObjectStyleCookieSendActionBuilder(ExtPetApi extPetApi, Ope /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormObjectStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormObjectStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); } @@ -1793,7 +1805,7 @@ public GetPetWithFormObjectStyleCookieSendActionBuilder petId(PetIdentifier petI public GetPetWithFormObjectStyleCookieSendActionBuilder petId(String petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); - return this; + return this; } @Override @@ -1808,7 +1820,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormObjectStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1816,7 +1828,7 @@ public static class GetPetWithFormObjectStyleCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormObjectStyleCookie"; - public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormObjectStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1837,7 +1849,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleCookieSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1856,8 +1868,8 @@ public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleCookieSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); } @@ -1869,14 +1881,14 @@ public GetPetWithFormStyleCookieSendActionBuilder(ExtPetApi extPetApi, OpenApiSp cookieParameter("petId", petId, ParameterStyle.FORM, false, false); } - public GetPetWithFormStyleCookieSendActionBuilder petId(Integer... petId) { + public GetPetWithFormStyleCookieSendActionBuilder petId(Integer...petId) { cookieParameter("petId", petId, ParameterStyle.FORM, false, false); return this; } - public GetPetWithFormStyleCookieSendActionBuilder petId(String... petIdExpression) { + public GetPetWithFormStyleCookieSendActionBuilder petId(String...petIdExpression) { cookieParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); - return this; + return this; } @Override @@ -1891,7 +1903,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleCookieReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1899,7 +1911,7 @@ public static class GetPetWithFormStyleCookieReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleCookie"; - public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleCookieReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -1920,7 +1932,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedObjectQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -1939,8 +1951,8 @@ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(ExtPetApi extPetA /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); } @@ -1959,7 +1971,7 @@ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(PetIdentifi public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, true); - return this; + return this; } @Override @@ -1974,7 +1986,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -1982,7 +1994,7 @@ public static class GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder e private static final String OPERATION_NAME = "getPetWithFormStyleExplodedObjectQuery"; - public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2003,7 +2015,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2022,8 +2034,8 @@ public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, Op /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleExplodedQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleExplodedQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); } @@ -2035,14 +2047,14 @@ public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, Op queryParameter("petId", petId, ParameterStyle.FORM, true, false); } - public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(Integer... petId) { + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(Integer...petId) { queryParameter("petId", petId, ParameterStyle.FORM, true, false); return this; } - public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String... petIdExpression) { + public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String...petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, true, false); - return this; + return this; } @Override @@ -2057,7 +2069,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleExplodedQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2065,7 +2077,7 @@ public static class GetPetWithFormStyleExplodedQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleExplodedQuery"; - public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleExplodedQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2086,7 +2098,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleObjectQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2105,8 +2117,8 @@ public GetPetWithFormStyleObjectQuerySendActionBuilder(ExtPetApi extPetApi, Open /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleObjectQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); } @@ -2125,7 +2137,7 @@ public GetPetWithFormStyleObjectQuerySendActionBuilder petId(PetIdentifier petId public GetPetWithFormStyleObjectQuerySendActionBuilder petId(String petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, true); - return this; + return this; } @Override @@ -2140,7 +2152,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleObjectQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2148,7 +2160,7 @@ public static class GetPetWithFormStyleObjectQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleObjectQuery"; - public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleObjectQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2169,7 +2181,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithFormStyleQuerySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2188,8 +2200,8 @@ public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpe /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithFormStyleQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithFormStyleQuerySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); } @@ -2201,14 +2213,14 @@ public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, OpenApiSpe queryParameter("petId", petId, ParameterStyle.FORM, false, false); } - public GetPetWithFormStyleQuerySendActionBuilder petId(Integer... petId) { + public GetPetWithFormStyleQuerySendActionBuilder petId(Integer...petId) { queryParameter("petId", petId, ParameterStyle.FORM, false, false); return this; } - public GetPetWithFormStyleQuerySendActionBuilder petId(String... petIdExpression) { + public GetPetWithFormStyleQuerySendActionBuilder petId(String...petIdExpression) { queryParameter("petId", petIdExpression, ParameterStyle.FORM, false, false); - return this; + return this; } @Override @@ -2223,7 +2235,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithFormStyleQueryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2231,7 +2243,7 @@ public static class GetPetWithFormStyleQueryReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithFormStyleQuery"; - public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithFormStyleQueryReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2252,7 +2264,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2271,8 +2283,8 @@ public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); } @@ -2284,14 +2296,14 @@ public GetPetWithLabelStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiSp pathParameter("petId", petId, ParameterStyle.LABEL, false, false); } - public GetPetWithLabelStyleArraySendActionBuilder petId(Integer... petId) { + public GetPetWithLabelStyleArraySendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.LABEL, false, false); return this; } - public GetPetWithLabelStyleArraySendActionBuilder petId(String... petIdExpression) { + public GetPetWithLabelStyleArraySendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, false); - return this; + return this; } @Override @@ -2306,7 +2318,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2314,7 +2326,7 @@ public static class GetPetWithLabelStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithLabelStyleArray"; - public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2335,7 +2347,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2354,8 +2366,8 @@ public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); } @@ -2367,14 +2379,14 @@ public GetPetWithLabelStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, O pathParameter("petId", petId, ParameterStyle.LABEL, true, false); } - public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(Integer... petId) { + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.LABEL, true, false); return this; } - public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { + public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, false); - return this; + return this; } @Override @@ -2389,7 +2401,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2397,7 +2409,7 @@ public static class GetPetWithLabelStyleArrayExplodedReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithLabelStyleArrayExploded"; - public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2418,7 +2430,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2437,8 +2449,8 @@ public GetPetWithLabelStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); } @@ -2457,7 +2469,7 @@ public GetPetWithLabelStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithLabelStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, false, true); - return this; + return this; } @Override @@ -2472,7 +2484,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2480,7 +2492,7 @@ public static class GetPetWithLabelStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithLabelStyleObject"; - public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2501,7 +2513,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2520,8 +2532,8 @@ public GetPetWithLabelStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithLabelStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithLabelStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); } @@ -2540,7 +2552,7 @@ public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(PetIdentifier p public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.LABEL, true, true); - return this; + return this; } @Override @@ -2555,7 +2567,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithLabelStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2563,7 +2575,7 @@ public static class GetPetWithLabelStyleObjectExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithLabelStyleObjectExploded"; - public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithLabelStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2584,7 +2596,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2603,8 +2615,8 @@ public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); } @@ -2616,14 +2628,14 @@ public GetPetWithMatrixStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); } - public GetPetWithMatrixStyleArraySendActionBuilder petId(Integer... petId) { + public GetPetWithMatrixStyleArraySendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.MATRIX, false, false); return this; } - public GetPetWithMatrixStyleArraySendActionBuilder petId(String... petIdExpression) { + public GetPetWithMatrixStyleArraySendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, false); - return this; + return this; } @Override @@ -2638,7 +2650,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2646,7 +2658,7 @@ public static class GetPetWithMatrixStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithMatrixStyleArray"; - public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2667,7 +2679,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2686,8 +2698,8 @@ public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); } @@ -2699,14 +2711,14 @@ public GetPetWithMatrixStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); } - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(Integer... petId) { + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.MATRIX, true, false); return this; } - public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { + public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, false); - return this; + return this; } @Override @@ -2721,7 +2733,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2729,7 +2741,7 @@ public static class GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithMatrixStyleArrayExploded"; - public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2750,7 +2762,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2769,8 +2781,8 @@ public GetPetWithMatrixStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); } @@ -2789,7 +2801,7 @@ public GetPetWithMatrixStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithMatrixStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, false, true); - return this; + return this; } @Override @@ -2804,7 +2816,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2812,7 +2824,7 @@ public static class GetPetWithMatrixStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithMatrixStyleObject"; - public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2833,7 +2845,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2852,8 +2864,8 @@ public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithMatrixStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); } @@ -2872,7 +2884,7 @@ public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(PetIdentifier public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.MATRIX, true, true); - return this; + return this; } @Override @@ -2887,7 +2899,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2895,7 +2907,7 @@ public static class GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithMatrixStyleObjectExploded"; - public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2916,7 +2928,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleArraySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -2935,8 +2947,8 @@ public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleArraySendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -2948,14 +2960,14 @@ public GetPetWithSimpleStyleArraySendActionBuilder(ExtPetApi extPetApi, OpenApiS pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleArraySendActionBuilder petId(Integer... petId) { + public GetPetWithSimpleStyleArraySendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleArraySendActionBuilder petId(String... petIdExpression) { + public GetPetWithSimpleStyleArraySendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -2970,7 +2982,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -2978,7 +2990,7 @@ public static class GetPetWithSimpleStyleArrayReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleArray"; - public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleArrayReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -2999,7 +3011,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3018,8 +3030,8 @@ public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -3031,14 +3043,14 @@ public GetPetWithSimpleStyleArrayExplodedSendActionBuilder(ExtPetApi extPetApi, pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(Integer... petId) { + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(Integer...petId) { pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String... petIdExpression) { + public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String...petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -3053,7 +3065,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3061,7 +3073,7 @@ public static class GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder exten private static final String OPERATION_NAME = "getPetWithSimpleStyleArrayExploded"; - public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3082,7 +3094,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3101,8 +3113,8 @@ public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); } @@ -3114,14 +3126,14 @@ public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder(ExtPetApi extPetApi, headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); } - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(Integer... petId) { + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(Integer...petId) { headerParameter("petId", petId, ParameterStyle.SIMPLE, true, false); return this; } - public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String... petIdExpression) { + public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String...petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, false); - return this; + return this; } @Override @@ -3136,7 +3148,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3144,7 +3156,7 @@ public static class GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedHeader"; - public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3165,7 +3177,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3184,8 +3196,8 @@ public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(ExtPetApi extP /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); } @@ -3204,7 +3216,7 @@ public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(PetIdent public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(String petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); - return this; + return this; } @Override @@ -3219,7 +3231,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3227,7 +3239,7 @@ public static class GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilde private static final String OPERATION_NAME = "getPetWithSimpleStyleExplodedObjectHeader"; - public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3248,7 +3260,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3267,8 +3279,8 @@ public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, List petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -3280,14 +3292,14 @@ public GetPetWithSimpleStyleHeaderSendActionBuilder(ExtPetApi extPetApi, OpenApi headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); } - public GetPetWithSimpleStyleHeaderSendActionBuilder petId(Integer... petId) { + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(Integer...petId) { headerParameter("petId", petId, ParameterStyle.SIMPLE, false, false); return this; } - public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String... petIdExpression) { + public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String...petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -3302,7 +3314,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3310,7 +3322,7 @@ public static class GetPetWithSimpleStyleHeaderReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleHeader"; - public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3331,7 +3343,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3350,8 +3362,8 @@ public GetPetWithSimpleStyleObjectSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); } @@ -3370,7 +3382,7 @@ public GetPetWithSimpleStyleObjectSendActionBuilder petId(PetIdentifier petId) { public GetPetWithSimpleStyleObjectSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); - return this; + return this; } @Override @@ -3385,7 +3397,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3393,7 +3405,7 @@ public static class GetPetWithSimpleStyleObjectReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetWithSimpleStyleObject"; - public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3414,7 +3426,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectExplodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3433,8 +3445,8 @@ public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(ExtPetApi extPetApi, /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectExplodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); } @@ -3453,7 +3465,7 @@ public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(PetIdentifier public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, true, true); - return this; + return this; } @Override @@ -3468,7 +3480,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3476,7 +3488,7 @@ public static class GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder exte private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectExploded"; - public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3497,7 +3509,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectHeaderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -3516,8 +3528,8 @@ public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(ExtPetApi extPetApi, O /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetWithSimpleStyleObjectHeaderSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); } @@ -3536,7 +3548,7 @@ public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(PetIdentifier pe public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(String petIdExpression) { headerParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, true); - return this; + return this; } @Override @@ -3551,7 +3563,7 @@ public SendMessageAction doBuild() { } public static class GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -3559,7 +3571,7 @@ public static class GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder extend private static final String OPERATION_NAME = "getPetWithSimpleStyleObjectHeader"; - public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3580,7 +3592,7 @@ public ReceiveMessageAction doBuild() { } public static class PostVaccinationDocumentSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -3628,7 +3640,7 @@ public SendMessageAction doBuild() { } public static class PostVaccinationDocumentReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -3636,7 +3648,7 @@ public static class PostVaccinationDocumentReceiveActionBuilder extends private static final String OPERATION_NAME = "postVaccinationDocument"; - public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PostVaccinationDocumentReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3657,7 +3669,7 @@ public ReceiveMessageAction doBuild() { } public static class PostVaccinationFormDataSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -3677,66 +3689,66 @@ public PostVaccinationFormDataSendActionBuilder(ExtPetApi extPetApi, OpenApiSpec } public PostVaccinationFormDataSendActionBuilder vaccine(String vaccine) { - formParameter("vaccine", vaccine); + formParameter("vaccine", vaccine); return this; } public void setVaccine(String vaccine) { - formParameter("vaccine", vaccine); + formParameter("vaccine", vaccine); } public PostVaccinationFormDataSendActionBuilder isFirstVaccination(Boolean isFirstVaccination) { - formParameter("isFirstVaccination", isFirstVaccination); + formParameter("isFirstVaccination", isFirstVaccination); return this; } public void setIsFirstVaccination(Boolean isFirstVaccination) { - formParameter("isFirstVaccination", isFirstVaccination); + formParameter("isFirstVaccination", isFirstVaccination); } public PostVaccinationFormDataSendActionBuilder isFirstVaccination(String isFirstVaccinationExpression) { - formParameter("isFirstVaccination", isFirstVaccinationExpression); + formParameter("isFirstVaccination", isFirstVaccinationExpression); return this; } public void setIsFirstVaccination(String isFirstVaccinationExpression) { - formParameter("isFirstVaccination", isFirstVaccinationExpression); + formParameter("isFirstVaccination", isFirstVaccinationExpression); } public PostVaccinationFormDataSendActionBuilder doseNumber(Integer doseNumber) { - formParameter("doseNumber", doseNumber); + formParameter("doseNumber", doseNumber); return this; } public void setDoseNumber(Integer doseNumber) { - formParameter("doseNumber", doseNumber); + formParameter("doseNumber", doseNumber); } public PostVaccinationFormDataSendActionBuilder doseNumber(String doseNumberExpression) { - formParameter("doseNumber", doseNumberExpression); + formParameter("doseNumber", doseNumberExpression); return this; } public void setDoseNumber(String doseNumberExpression) { - formParameter("doseNumber", doseNumberExpression); + formParameter("doseNumber", doseNumberExpression); } public PostVaccinationFormDataSendActionBuilder vaccinationDate(LocalDate vaccinationDate) { - formParameter("vaccinationDate", vaccinationDate); + formParameter("vaccinationDate", vaccinationDate); return this; } public void setVaccinationDate(LocalDate vaccinationDate) { - formParameter("vaccinationDate", vaccinationDate); + formParameter("vaccinationDate", vaccinationDate); } public PostVaccinationFormDataSendActionBuilder vaccinationDate(String vaccinationDateExpression) { - formParameter("vaccinationDate", vaccinationDateExpression); + formParameter("vaccinationDate", vaccinationDateExpression); return this; } public void setVaccinationDate(String vaccinationDateExpression) { - formParameter("vaccinationDate", vaccinationDateExpression); + formParameter("vaccinationDate", vaccinationDateExpression); } @Override @@ -3751,7 +3763,7 @@ public SendMessageAction doBuild() { } public static class PostVaccinationFormDataReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -3759,7 +3771,7 @@ public static class PostVaccinationFormDataReceiveActionBuilder extends private static final String OPERATION_NAME = "postVaccinationFormData"; - public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PostVaccinationFormDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3780,7 +3792,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithArrayQueryDataSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3804,8 +3816,8 @@ public UpdatePetWithArrayQueryDataSendActionBuilder(ExtPetApi extPetApi, OpenApi /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithArrayQueryDataSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithArrayQueryDataSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, List tagsExpression, List nicknamesExpression, String sampleStringHeaderExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); queryParameter("name", _nameExpression, ParameterStyle.FORM, true, false); queryParameter("status", statusExpression, ParameterStyle.FORM, true, false); @@ -3834,7 +3846,7 @@ public UpdatePetWithArrayQueryDataSendActionBuilder petId(Long petId) { public UpdatePetWithArrayQueryDataSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithArrayQueryDataSendActionBuilder _name(String _name) { @@ -3847,12 +3859,12 @@ public UpdatePetWithArrayQueryDataSendActionBuilder status(String status) { return this; } - public UpdatePetWithArrayQueryDataSendActionBuilder tags(String... tags) { + public UpdatePetWithArrayQueryDataSendActionBuilder tags(String...tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); return this; } - public UpdatePetWithArrayQueryDataSendActionBuilder nicknames(String... nicknames) { + public UpdatePetWithArrayQueryDataSendActionBuilder nicknames(String...nicknames) { queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); return this; } @@ -3892,7 +3904,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithArrayQueryDataReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3900,7 +3912,7 @@ public static class UpdatePetWithArrayQueryDataReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithArrayQueryData"; - public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithArrayQueryDataReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -3921,7 +3933,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithFormUrlEncodedSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -3935,22 +3947,22 @@ public static class UpdatePetWithFormUrlEncodedSendActionBuilder extends public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, Long petId, String _name, String status, Integer age, List tags) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - formParameter("name", _name); - formParameter("status", status); - formParameter("age", age); - formParameter("tags", tags); + formParameter("name", _name); + formParameter("status", status); + formParameter("age", age); + formParameter("tags", tags); } /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { - super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApiSpecification, ExtPetApi extPetApi, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tagsExpression) { + super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - formParameter("name", _nameExpression); - formParameter("status", statusExpression); - formParameter("age", ageExpression); - formParameter("tags", tagsExpression); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tagsExpression); } /** @@ -3959,10 +3971,10 @@ public UpdatePetWithFormUrlEncodedSendActionBuilder(OpenApiSpecification openApi public UpdatePetWithFormUrlEncodedSendActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression, String _nameExpression, String statusExpression, String ageExpression, List tags) { super(extPetApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - formParameter("name", _nameExpression); - formParameter("status", statusExpression); - formParameter("age", ageExpression); - formParameter("tags", tags); + formParameter("name", _nameExpression); + formParameter("status", statusExpression); + formParameter("age", ageExpression); + formParameter("tags", tags); } public UpdatePetWithFormUrlEncodedSendActionBuilder petId(Long petId) { @@ -3972,59 +3984,59 @@ public UpdatePetWithFormUrlEncodedSendActionBuilder petId(Long petId) { public UpdatePetWithFormUrlEncodedSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder _name(String _name) { - formParameter("name", _name); + formParameter("name", _name); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder status(String status) { - formParameter("status", status); + formParameter("status", status); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder age(Integer age) { - formParameter("age", age); + formParameter("age", age); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder age(String ageExpression) { - formParameter("age", ageExpression); - return this; + formParameter("age", ageExpression); + return this; } - public UpdatePetWithFormUrlEncodedSendActionBuilder tags(String... tags) { - formParameter("tags", tags); + public UpdatePetWithFormUrlEncodedSendActionBuilder tags(String...tags) { + formParameter("tags", tags); return this; } public UpdatePetWithFormUrlEncodedSendActionBuilder owners(Integer owners) { - formParameter("owners", owners); + formParameter("owners", owners); return this; } public void setOwners(Integer owners) { - formParameter("owners", owners); + formParameter("owners", owners); } public UpdatePetWithFormUrlEncodedSendActionBuilder owners(String ownersExpression) { - formParameter("owners", ownersExpression); + formParameter("owners", ownersExpression); return this; } public void setOwners(String ownersExpression) { - formParameter("owners", ownersExpression); + formParameter("owners", ownersExpression); } - public UpdatePetWithFormUrlEncodedSendActionBuilder nicknames(String... nicknames) { - formParameter("nicknames", nicknames); + public UpdatePetWithFormUrlEncodedSendActionBuilder nicknames(String...nicknames) { + formParameter("nicknames", nicknames); return this; } - public void setNicknames(String... nicknames) { - formParameter("nicknames", nicknames); + public void setNicknames(String...nicknames) { + formParameter("nicknames", nicknames); } @Override @@ -4039,7 +4051,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithFormUrlEncodedReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -4047,7 +4059,7 @@ public static class UpdatePetWithFormUrlEncodedReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithFormUrlEncoded"; - public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithFormUrlEncodedReceiveActionBuilder(ExtPetApi extPetApi, OpenApiSpecification openApiSpecification, String statusCode) { super(extPetApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -4066,4 +4078,4 @@ public ReceiveMessageAction doBuild() { } } -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index f527937765..255b34f06c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -1,32 +1,30 @@ package org.citrusframework.openapi.generator.rest.extpetstore.spring; +import java.util.List; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; -import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - -import java.util.List; - +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ExtPetStoreBeanConfiguration { @Bean public OpenApiRepository extPetStoreOpenApiRepository() { var openApiRepository = new OpenApiRepository(); openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( - ExtPetStore.extPetStoreApi())); + ExtPetStore.extPetStoreApi())); return openApiRepository; } - @Bean(name = "ExtPetApi") + @Bean(name="ExtPetApi") public ExtPetApi extPetApi(@Qualifier("extpetstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new ExtPetApi(endpoint, customizers); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index 52e08f2e11..b42c4e89e1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -1,242 +1,241 @@ package org.citrusframework.openapi.generator.rest.extpetstore.spring; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; -import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; -import org.citrusframework.openapi.testapi.GeneratedApi; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.rest.extpetstore.request.ExtPetApi; import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; +import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStore; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.194751400+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.158583300+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( - ExtPetStore.extPetStoreApi()); + ExtPetStore.extPetStoreApi()); @Override public void init() { - registerOperationParsers(ExtPetApi.class, "generate-vaccination-report", "generateVaccinationReport", "/pet/vaccination/status-report", + registerOperationParsers(ExtPetApi.class,"generate-vaccination-report", "generateVaccinationReport", "/pet/vaccination/status-report", ExtPetApi.GenerateVaccinationReportSendActionBuilder.class, ExtPetApi.GenerateVaccinationReportReceiveActionBuilder.class, - new String[]{"template", "reqIntVal"}, - new String[]{"optIntVal", "optBoolVal", "optNumberVal", "optStringVal", "optDateVal", "additionalData", "schema"}); + new String[]{ "template", "reqIntVal" }, + new String[]{ "optIntVal", "optBoolVal", "optNumberVal", "optStringVal", "optDateVal", "additionalData", "schema" }); - registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-api-key-authentication", "getPetByIdWithApiKeyAuthentication", "/secure-api-key/pet/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-api-key-authentication", "getPetByIdWithApiKeyAuthentication", "/secure-api-key/pet/{petId}", ExtPetApi.GetPetByIdWithApiKeyAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithApiKeyAuthenticationReceiveActionBuilder.class, - new String[]{"petId", "allDetails"}, - new String[]{"details", "requesterInformation", "apiKeyQuery", "apiKeyHeader", "apiKeyCookie"}); + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "apiKeyQuery", "apiKeyHeader", "apiKeyCookie" }); - registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-basic-authentication", "getPetByIdWithBasicAuthentication", "/secure-basic/pet/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-basic-authentication", "getPetByIdWithBasicAuthentication", "/secure-basic/pet/{petId}", ExtPetApi.GetPetByIdWithBasicAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithBasicAuthenticationReceiveActionBuilder.class, - new String[]{"petId", "allDetails"}, - new String[]{"details", "requesterInformation", "basicAuthUsername", "basicAuthPassword"}); + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "basicAuthUsername", "basicAuthPassword" }); - registerOperationParsers(ExtPetApi.class, "get-pet-by-id-with-bearer-authentication", "getPetByIdWithBearerAuthentication", "/secure-bearer/pet/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-by-id-with-bearer-authentication", "getPetByIdWithBearerAuthentication", "/secure-bearer/pet/{petId}", ExtPetApi.GetPetByIdWithBearerAuthenticationSendActionBuilder.class, ExtPetApi.GetPetByIdWithBearerAuthenticationReceiveActionBuilder.class, - new String[]{"petId", "allDetails"}, - new String[]{"details", "requesterInformation", "basicAuthBearer"}); + new String[]{ "petId", "allDetails" }, + new String[]{ "details", "requesterInformation", "basicAuthBearer" }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-cookie", "getPetWithCookie", "/pet/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-cookie", "getPetWithCookie", "/pet/{petId}", ExtPetApi.GetPetWithCookieSendActionBuilder.class, ExtPetApi.GetPetWithCookieReceiveActionBuilder.class, - new String[]{"petId", "sessionId"}, - new String[]{"optTrxId"}); + new String[]{ "petId", "sessionId" }, + new String[]{ "optTrxId" }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-deep-object-type-query", "getPetWithDeepObjectTypeQuery", "/pet/query/deep/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-deep-object-type-query", "getPetWithDeepObjectTypeQuery", "/pet/query/deep/object", ExtPetApi.GetPetWithDeepObjectTypeQuerySendActionBuilder.class, ExtPetApi.GetPetWithDeepObjectTypeQueryReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-exploded-style-cookie", "getPetWithFormExplodedStyleCookie", "/pet/cookie/form/exploded", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-exploded-style-cookie", "getPetWithFormExplodedStyleCookie", "/pet/cookie/form/exploded", ExtPetApi.GetPetWithFormExplodedStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormExplodedStyleCookieReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-object-style-cookie", "getPetWithFormObjectStyleCookie", "/pet/cookie/form/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-object-style-cookie", "getPetWithFormObjectStyleCookie", "/pet/cookie/form/object", ExtPetApi.GetPetWithFormObjectStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormObjectStyleCookieReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-cookie", "getPetWithFormStyleCookie", "/pet/cookie/form", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-cookie", "getPetWithFormStyleCookie", "/pet/cookie/form", ExtPetApi.GetPetWithFormStyleCookieSendActionBuilder.class, ExtPetApi.GetPetWithFormStyleCookieReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-exploded-object-query", "getPetWithFormStyleExplodedObjectQuery", "/pet/query/form/exploded/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-object-query", "getPetWithFormStyleExplodedObjectQuery", "/pet/query/form/exploded/object", ExtPetApi.GetPetWithFormStyleExplodedObjectQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleExplodedObjectQueryReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-exploded-query", "getPetWithFormStyleExplodedQuery", "/pet/query/form/exploded", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-exploded-query", "getPetWithFormStyleExplodedQuery", "/pet/query/form/exploded", ExtPetApi.GetPetWithFormStyleExplodedQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleExplodedQueryReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-object-query", "getPetWithFormStyleObjectQuery", "/pet/query/form/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-object-query", "getPetWithFormStyleObjectQuery", "/pet/query/form/object", ExtPetApi.GetPetWithFormStyleObjectQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleObjectQueryReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-form-style-query", "getPetWithFormStyleQuery", "/pet/query/form", + registerOperationParsers(ExtPetApi.class,"get-pet-with-form-style-query", "getPetWithFormStyleQuery", "/pet/query/form", ExtPetApi.GetPetWithFormStyleQuerySendActionBuilder.class, ExtPetApi.GetPetWithFormStyleQueryReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-array", "getPetWithLabelStyleArray", "/pet/label/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array", "getPetWithLabelStyleArray", "/pet/label/{petId}", ExtPetApi.GetPetWithLabelStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleArrayReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-array-exploded", "getPetWithLabelStyleArrayExploded", "/pet/label/exploded/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-array-exploded", "getPetWithLabelStyleArrayExploded", "/pet/label/exploded/{petId}", ExtPetApi.GetPetWithLabelStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleArrayExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-object", "getPetWithLabelStyleObject", "/pet/label/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object", "getPetWithLabelStyleObject", "/pet/label/object/{petId}", ExtPetApi.GetPetWithLabelStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleObjectReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-label-style-object-exploded", "getPetWithLabelStyleObjectExploded", "/pet/label/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-label-style-object-exploded", "getPetWithLabelStyleObjectExploded", "/pet/label/exploded/object/{petId}", ExtPetApi.GetPetWithLabelStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithLabelStyleObjectExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-array", "getPetWithMatrixStyleArray", "/pet/matrix/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array", "getPetWithMatrixStyleArray", "/pet/matrix/{petId}", ExtPetApi.GetPetWithMatrixStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleArrayReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-array-exploded", "getPetWithMatrixStyleArrayExploded", "/pet/matrix/exploded/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-array-exploded", "getPetWithMatrixStyleArrayExploded", "/pet/matrix/exploded/{petId}", ExtPetApi.GetPetWithMatrixStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleArrayExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-object", "getPetWithMatrixStyleObject", "/pet/matrix/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object", "getPetWithMatrixStyleObject", "/pet/matrix/object/{petId}", ExtPetApi.GetPetWithMatrixStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleObjectReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-matrix-style-object-exploded", "getPetWithMatrixStyleObjectExploded", "/pet/matrix/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-matrix-style-object-exploded", "getPetWithMatrixStyleObjectExploded", "/pet/matrix/exploded/object/{petId}", ExtPetApi.GetPetWithMatrixStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", ExtPetApi.GetPetWithSimpleStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleArrayReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-array-exploded", "getPetWithSimpleStyleArrayExploded", "/pet/simple/exploded/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array-exploded", "getPetWithSimpleStyleArrayExploded", "/pet/simple/exploded/{petId}", ExtPetApi.GetPetWithSimpleStyleArrayExplodedSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleArrayExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-exploded-header", "getPetWithSimpleStyleExplodedHeader", "/pet/header/simple/exploded", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-header", "getPetWithSimpleStyleExplodedHeader", "/pet/header/simple/exploded", ExtPetApi.GetPetWithSimpleStyleExplodedHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleExplodedHeaderReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-exploded-object-header", "getPetWithSimpleStyleExplodedObjectHeader", "/pet/header/simple/exploded/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-exploded-object-header", "getPetWithSimpleStyleExplodedObjectHeader", "/pet/header/simple/exploded/object", ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleExplodedObjectHeaderReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-header", "getPetWithSimpleStyleHeader", "/pet/header/simple", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-header", "getPetWithSimpleStyleHeader", "/pet/header/simple", ExtPetApi.GetPetWithSimpleStyleHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleHeaderReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object", "getPetWithSimpleStyleObject", "/pet/simple/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object", "getPetWithSimpleStyleObject", "/pet/simple/object/{petId}", ExtPetApi.GetPetWithSimpleStyleObjectSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object-exploded", "getPetWithSimpleStyleObjectExploded", "/pet/simple/exploded/object/{petId}", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-exploded", "getPetWithSimpleStyleObjectExploded", "/pet/simple/exploded/object/{petId}", ExtPetApi.GetPetWithSimpleStyleObjectExplodedSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectExplodedReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "get-pet-with-simple-style-object-header", "getPetWithSimpleStyleObjectHeader", "/pet/header/simple/object", + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-object-header", "getPetWithSimpleStyleObjectHeader", "/pet/header/simple/object", ExtPetApi.GetPetWithSimpleStyleObjectHeaderSendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{}); + new String[]{ "petId" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}", + registerOperationParsers(ExtPetApi.class,"post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}", ExtPetApi.PostVaccinationDocumentSendActionBuilder.class, ExtPetApi.PostVaccinationDocumentReceiveActionBuilder.class, - new String[]{"bucket", "filename"}, - new String[]{}); + new String[]{ "bucket", "filename" }, + new String[]{ }); - registerOperationParsers(ExtPetApi.class, "post-vaccination-form-data", "postVaccinationFormData", "/pet/vaccination/form", + registerOperationParsers(ExtPetApi.class,"post-vaccination-form-data", "postVaccinationFormData", "/pet/vaccination/form", ExtPetApi.PostVaccinationFormDataSendActionBuilder.class, ExtPetApi.PostVaccinationFormDataReceiveActionBuilder.class, - new String[]{}, - new String[]{"vaccine", "isFirstVaccination", "doseNumber", "vaccinationDate"}); + new String[]{ }, + new String[]{ "vaccine", "isFirstVaccination", "doseNumber", "vaccinationDate" }); - registerOperationParsers(ExtPetApi.class, "update-pet-with-array-query-data", "updatePetWithArrayQueryData", "/pet/{petId}", + registerOperationParsers(ExtPetApi.class,"update-pet-with-array-query-data", "updatePetWithArrayQueryData", "/pet/{petId}", ExtPetApi.UpdatePetWithArrayQueryDataSendActionBuilder.class, ExtPetApi.UpdatePetWithArrayQueryDataReceiveActionBuilder.class, - new String[]{"petId", "_name", "status", "tags", "nicknames", "sampleStringHeader"}, - new String[]{"sampleIntHeader"}); + new String[]{ "petId", "_name", "status", "tags", "nicknames", "sampleStringHeader" }, + new String[]{ "sampleIntHeader" }); - registerOperationParsers(ExtPetApi.class, "update-pet-with-form-url-encoded", "updatePetWithFormUrlEncoded", "/pet/form/{petId}", + registerOperationParsers(ExtPetApi.class,"update-pet-with-form-url-encoded", "updatePetWithFormUrlEncoded", "/pet/form/{petId}", ExtPetApi.UpdatePetWithFormUrlEncodedSendActionBuilder.class, ExtPetApi.UpdatePetWithFormUrlEncodedReceiveActionBuilder.class, - new String[]{"petId", "_name", "status", "age", "tags"}, - new String[]{"owners", "nicknames"}); + new String[]{ "petId", "_name", "status", "age", "tags" }, + new String[]{ "owners", "nicknames" }); } private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, - Class sendBeanClass, - Class receiveBeanClass, - String[] constructorParameters, - String[] nonConstructorParameters) { + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, - path, - apiClass, - sendBeanClass, - receiveBeanClass, - "extpetstore.endpoint"); + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "extpetstore.endpoint"); sendParser.setConstructorParameters(constructorParameters); sendParser.setNonConstructorParameters(nonConstructorParameters); - registerBeanDefinitionParser("send-" + elementName, sendParser); + registerBeanDefinitionParser("send-"+elementName, sendParser); RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, - operationName, apiClass, receiveBeanClass, "extpetstore.endpoint"); - registerBeanDefinitionParser("receive-" + elementName, receiveParser); + operationName, apiClass, receiveBeanClass, "extpetstore.endpoint"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java index 6c18492c1d..ee42b127f7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStore.java @@ -7,5 +7,4 @@ public class PetStore { public static URL petStoreApi() { return PetStore.class.getResource("petStore_openApi.yaml"); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index da3af60ddf..8cc578a679 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -1,172 +1,171 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * Address */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Address { - private String street; - - private String city; + private String street; - private String state; + private String city; - private String zip; + private String state; - public Address() { - } + private String zip; - public Address street(String street) { + public Address() { + } - this.street = street; - return this; - } + public Address street(String street) { + + this.street = street; + return this; + } - /** - * Get street - * - * @return street - **/ - @jakarta.annotation.Nullable + /** + * Get street + * @return street + **/ + @jakarta.annotation.Nullable - public String getStreet() { - return street; - } + public String getStreet() { + return street; + } - public void setStreet(String street) { - this.street = street; - } + public void setStreet(String street) { + this.street = street; + } - public Address city(String city) { - - this.city = city; - return this; - } - - /** - * Get city - * - * @return city - **/ - @jakarta.annotation.Nullable - - public String getCity() { - return city; - } - - - public void setCity(String city) { - this.city = city; - } - - - public Address state(String state) { - - this.state = state; - return this; - } - - /** - * Get state - * - * @return state - **/ - @jakarta.annotation.Nullable - - public String getState() { - return state; - } + public Address city(String city) { + + this.city = city; + return this; + } - - public void setState(String state) { - this.state = state; - } - - - public Address zip(String zip) { - - this.zip = zip; - return this; - } - - /** - * Get zip - * - * @return zip - **/ - @jakarta.annotation.Nullable - - public String getZip() { - return zip; - } - - - public void setZip(String zip) { - this.zip = zip; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Address address = (Address) o; - return Objects.equals(this.street, address.street) && - Objects.equals(this.city, address.city) && - Objects.equals(this.state, address.state) && - Objects.equals(this.zip, address.zip); - } - - @Override - public int hashCode() { - return Objects.hash(street, city, state, zip); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Address {\n"); - sb.append(" street: ").append(toIndentedString(street)).append("\n"); - sb.append(" city: ").append(toIndentedString(city)).append("\n"); - sb.append(" state: ").append(toIndentedString(state)).append("\n"); - sb.append(" zip: ").append(toIndentedString(zip)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + /** + * Get city + * @return city + **/ + @jakarta.annotation.Nullable + + public String getCity() { + return city; + } + + + public void setCity(String city) { + this.city = city; + } + + + public Address state(String state) { + + this.state = state; + return this; + } + + /** + * Get state + * @return state + **/ + @jakarta.annotation.Nullable + + public String getState() { + return state; + } + + + public void setState(String state) { + this.state = state; + } + + + public Address zip(String zip) { + + this.zip = zip; + return this; + } + + /** + * Get zip + * @return zip + **/ + @jakarta.annotation.Nullable + + public String getZip() { + return zip; + } + + + public void setZip(String zip) { + this.zip = zip; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Address address = (Address) o; + return Objects.equals(this.street, address.street) && + Objects.equals(this.city, address.city) && + Objects.equals(this.state, address.state) && + Objects.equals(this.zip, address.zip); + } + + @Override + public int hashCode() { + return Objects.hash(street, city, state, zip); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Address {\n"); + sb.append(" street: ").append(toIndentedString(street)).append("\n"); + sb.append(" city: ").append(toIndentedString(city)).append("\n"); + sb.append(" state: ").append(toIndentedString(state)).append("\n"); + sb.append(" zip: ").append(toIndentedString(zip)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index a76481be55..5fdb888837 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -1,118 +1,119 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Category { - private Long id; - - private String _name; + private Long id; - public Category() { - } + private String _name; - public Category id(Long id) { + public Category() { + } - this.id = id; - return this; - } - - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable - - public Long getId() { - return id; - } + public Category id(Long id) { + + this.id = id; + return this; + } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public Category _name(String _name) { + public void setId(Long id) { + this.id = id; + } - this._name = _name; - return this; - } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nullable + public Category _name(String _name) { + + this._name = _name; + return this; + } - public String getName() { - return _name; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public void setName(String _name) { - this._name = _name; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Category category = (Category) o; - return Objects.equals(this.id, category.id) && - Objects.equals(this._name, category._name); - } + public void setName(String _name) { + this._name = _name; + } - @Override - public int hashCode() { - return Objects.hash(id, _name); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Category {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + Category category = (Category) o; + return Objects.equals(this.id, category.id) && + Objects.equals(this._name, category._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Category {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index d541f5317b..e5706a25f0 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -1,157 +1,157 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; -import org.citrusframework.openapi.generator.rest.petstore.model.Address; - +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Objects; +import org.citrusframework.openapi.generator.rest.petstore.model.Address; /** * Customer */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Customer { - private Long id; + private Long id; - private String username; + private String username; - private List
        address = new ArrayList<>(); + private List
        address = new ArrayList<>(); - public Customer() { - } + public Customer() { + } - public Customer id(Long id) { + public Customer id(Long id) { + + this.id = id; + return this; + } - this.id = id; - return this; - } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable + public Long getId() { + return id; + } - public Long getId() { - return id; - } + public void setId(Long id) { + this.id = id; + } - public void setId(Long id) { - this.id = id; - } + public Customer username(String username) { + + this.username = username; + return this; + } - public Customer username(String username) { + /** + * Get username + * @return username + **/ + @jakarta.annotation.Nullable - this.username = username; - return this; - } + public String getUsername() { + return username; + } - /** - * Get username - * - * @return username - **/ - @jakarta.annotation.Nullable - public String getUsername() { - return username; - } + public void setUsername(String username) { + this.username = username; + } - public void setUsername(String username) { - this.username = username; - } - - - public Customer address(List
        address) { + public Customer address(List
        address) { + + this.address = address; + return this; + } - this.address = address; - return this; + public Customer addAddressItem(Address addressItem) { + if (this.address == null) { + this.address = new ArrayList<>(); } + this.address.add(addressItem); + return this; + } - public Customer addAddressItem(Address addressItem) { - if (this.address == null) { - this.address = new ArrayList<>(); - } - this.address.add(addressItem); - return this; - } + /** + * Get address + * @return address + **/ + @jakarta.annotation.Nullable - /** - * Get address - * - * @return address - **/ - @jakarta.annotation.Nullable + public List
        getAddress() { + return address; + } - public List
        getAddress() { - return address; - } + public void setAddress(List
        address) { + this.address = address; + } - public void setAddress(List
        address) { - this.address = address; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Customer customer = (Customer) o; - return Objects.equals(this.id, customer.id) && - Objects.equals(this.username, customer.username) && - Objects.equals(this.address, customer.address); + if (o == null || getClass() != o.getClass()) { + return false; } - - @Override - public int hashCode() { - return Objects.hash(id, username, address); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Customer {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" username: ").append(toIndentedString(username)).append("\n"); - sb.append(" address: ").append(toIndentedString(address)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + Customer customer = (Customer) o; + return Objects.equals(this.id, customer.id) && + Objects.equals(this.username, customer.username) && + Objects.equals(this.address, customer.address); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, address); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Customer {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" address: ").append(toIndentedString(address)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index 27d204e2cb..c34627ba27 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -1,145 +1,145 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class ModelApiResponse { - private Integer code; - - private String type; + private Integer code; - private String _message; + private String type; - public ModelApiResponse() { - } + private String _message; - public ModelApiResponse code(Integer code) { - - this.code = code; - return this; - } + public ModelApiResponse() { + } - /** - * Get code - * - * @return code - **/ - @jakarta.annotation.Nullable + public ModelApiResponse code(Integer code) { + + this.code = code; + return this; + } - public Integer getCode() { - return code; - } - - - public void setCode(Integer code) { - this.code = code; - } + /** + * Get code + * @return code + **/ + @jakarta.annotation.Nullable + public Integer getCode() { + return code; + } - public ModelApiResponse type(String type) { - this.type = type; - return this; - } + public void setCode(Integer code) { + this.code = code; + } - /** - * Get type - * - * @return type - **/ - @jakarta.annotation.Nullable - public String getType() { - return type; - } + public ModelApiResponse type(String type) { + + this.type = type; + return this; + } + /** + * Get type + * @return type + **/ + @jakarta.annotation.Nullable - public void setType(String type) { - this.type = type; - } + public String getType() { + return type; + } - public ModelApiResponse _message(String _message) { + public void setType(String type) { + this.type = type; + } - this._message = _message; - return this; - } - /** - * Get _message - * - * @return _message - **/ - @jakarta.annotation.Nullable + public ModelApiResponse _message(String _message) { + + this._message = _message; + return this; + } - public String getMessage() { - return _message; - } + /** + * Get _message + * @return _message + **/ + @jakarta.annotation.Nullable + public String getMessage() { + return _message; + } - public void setMessage(String _message) { - this._message = _message; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ModelApiResponse _apiResponse = (ModelApiResponse) o; - return Objects.equals(this.code, _apiResponse.code) && - Objects.equals(this.type, _apiResponse.type) && - Objects.equals(this._message, _apiResponse._message); - } + public void setMessage(String _message) { + this._message = _message; + } - @Override - public int hashCode() { - return Objects.hash(code, type, _message); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class ModelApiResponse {\n"); - sb.append(" code: ").append(toIndentedString(code)).append("\n"); - sb.append(" type: ").append(toIndentedString(type)).append("\n"); - sb.append(" _message: ").append(toIndentedString(_message)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + ModelApiResponse _apiResponse = (ModelApiResponse) o; + return Objects.equals(this.code, _apiResponse.code) && + Objects.equals(this.type, _apiResponse.type) && + Objects.equals(this._message, _apiResponse._message); + } + + @Override + public int hashCode() { + return Objects.hash(code, type, _message); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ModelApiResponse {\n"); + sb.append(" code: ").append(toIndentedString(code)).append("\n"); + sb.append(" type: ").append(toIndentedString(type)).append("\n"); + sb.append(" _message: ").append(toIndentedString(_message)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index 080663a5bb..925a3f0fce 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -1,249 +1,259 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; -import java.time.OffsetDateTime; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import java.time.OffsetDateTime; /** * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Order { - private Long id; + private Long id; - private Long petId; + private Long petId; - private Integer quantity; + private Integer quantity; - private OffsetDateTime shipDate; - private StatusEnum status; - private Boolean complete; + private OffsetDateTime shipDate; - public Order() { - } + /** + * Order Status + */ + public enum StatusEnum { + PLACED("placed"), + + APPROVED("approved"), + + DELIVERED("delivered"); - public Order id(Long id) { + private String value; - this.id = id; - return this; + StatusEnum(String value) { + this.value = value; } - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable + public String getValue() { + return value; + } - public Long getId() { - return id; + @Override + public String toString() { + return String.valueOf(value); } - public void setId(Long id) { - this.id = id; + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); } + } - public Order petId(Long petId) { + private StatusEnum status; - this.petId = petId; - return this; - } + private Boolean complete; - /** - * Get petId - * - * @return petId - **/ - @jakarta.annotation.Nullable + public Order() { + } - public Long getPetId() { - return petId; - } + public Order id(Long id) { + + this.id = id; + return this; + } - public void setPetId(Long petId) { - this.petId = petId; - } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public Order quantity(Integer quantity) { + public Long getId() { + return id; + } - this.quantity = quantity; - return this; - } - /** - * Get quantity - * - * @return quantity - **/ - @jakarta.annotation.Nullable + public void setId(Long id) { + this.id = id; + } - public Integer getQuantity() { - return quantity; - } - public void setQuantity(Integer quantity) { - this.quantity = quantity; - } + public Order petId(Long petId) { + + this.petId = petId; + return this; + } - public Order shipDate(OffsetDateTime shipDate) { + /** + * Get petId + * @return petId + **/ + @jakarta.annotation.Nullable - this.shipDate = shipDate; - return this; - } + public Long getPetId() { + return petId; + } - /** - * Get shipDate - * - * @return shipDate - **/ - @jakarta.annotation.Nullable - public OffsetDateTime getShipDate() { - return shipDate; - } + public void setPetId(Long petId) { + this.petId = petId; + } - public void setShipDate(OffsetDateTime shipDate) { - this.shipDate = shipDate; - } - public Order status(StatusEnum status) { + public Order quantity(Integer quantity) { + + this.quantity = quantity; + return this; + } - this.status = status; - return this; - } + /** + * Get quantity + * @return quantity + **/ + @jakarta.annotation.Nullable - /** - * Order Status - * - * @return status - **/ - @jakarta.annotation.Nullable + public Integer getQuantity() { + return quantity; + } - public StatusEnum getStatus() { - return status; - } - public void setStatus(StatusEnum status) { - this.status = status; - } + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } - public Order complete(Boolean complete) { - this.complete = complete; - return this; - } + public Order shipDate(OffsetDateTime shipDate) { + + this.shipDate = shipDate; + return this; + } - /** - * Get complete - * - * @return complete - **/ - @jakarta.annotation.Nullable + /** + * Get shipDate + * @return shipDate + **/ + @jakarta.annotation.Nullable - public Boolean getComplete() { - return complete; - } + public OffsetDateTime getShipDate() { + return shipDate; + } - public void setComplete(Boolean complete) { - this.complete = complete; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Order order = (Order) o; - return Objects.equals(this.id, order.id) && - Objects.equals(this.petId, order.petId) && - Objects.equals(this.quantity, order.quantity) && - Objects.equals(this.shipDate, order.shipDate) && - Objects.equals(this.status, order.status) && - Objects.equals(this.complete, order.complete); - } + public void setShipDate(OffsetDateTime shipDate) { + this.shipDate = shipDate; + } - @Override - public int hashCode() { - return Objects.hash(id, petId, quantity, shipDate, status, complete); - } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Order {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); - sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); - sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); - sb.append("}"); - return sb.toString(); - } + public Order status(StatusEnum status) { + + this.status = status; + return this; + } - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + /** + * Order Status + * @return status + **/ + @jakarta.annotation.Nullable - /** - * Order Status - */ - public enum StatusEnum { - PLACED("placed"), + public StatusEnum getStatus() { + return status; + } - APPROVED("approved"), - DELIVERED("delivered"); + public void setStatus(StatusEnum status) { + this.status = status; + } - private String value; - StatusEnum(String value) { - this.value = value; - } + public Order complete(Boolean complete) { + + this.complete = complete; + return this; + } - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } + /** + * Get complete + * @return complete + **/ + @jakarta.annotation.Nullable - public String getValue() { - return value; - } + public Boolean getComplete() { + return complete; + } - @Override - public String toString() { - return String.valueOf(value); - } + + public void setComplete(Boolean complete) { + this.complete = complete; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Order order = (Order) o; + return Objects.equals(this.id, order.id) && + Objects.equals(this.petId, order.petId) && + Objects.equals(this.quantity, order.quantity) && + Objects.equals(this.shipDate, order.shipDate) && + Objects.equals(this.status, order.status) && + Objects.equals(this.complete, order.complete); + } + + @Override + public int hashCode() { + return Objects.hash(id, petId, quantity, shipDate, status, complete); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Order {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" petId: ").append(toIndentedString(petId)).append("\n"); + sb.append(" quantity: ").append(toIndentedString(quantity)).append("\n"); + sb.append(" shipDate: ").append(toIndentedString(shipDate)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append(" complete: ").append(toIndentedString(complete)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index b330e39068..1dacfd204e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -1,270 +1,279 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; -import org.citrusframework.openapi.generator.rest.petstore.model.Category; -import org.citrusframework.openapi.generator.rest.petstore.model.Tag; - +import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Objects; +import org.citrusframework.openapi.generator.rest.petstore.model.Category; +import org.citrusframework.openapi.generator.rest.petstore.model.Tag; /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Pet { - private Long id; + private Long id; - private String _name; + private String _name; - private Category category; + private Category category; - private List photoUrls = new ArrayList<>(); + private List photoUrls = new ArrayList<>(); - private List tags = new ArrayList<>(); - private StatusEnum status; + private List tags = new ArrayList<>(); - public Pet() { - } + /** + * pet status in the store + */ + public enum StatusEnum { + AVAILABLE("available"), + + PENDING("pending"), + + SOLD("sold"); - public Pet id(Long id) { + private String value; - this.id = id; - return this; + StatusEnum(String value) { + this.value = value; } - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable + public String getValue() { + return value; + } - public Long getId() { - return id; + @Override + public String toString() { + return String.valueOf(value); } - public void setId(Long id) { - this.id = id; + public static StatusEnum fromValue(String value) { + for (StatusEnum b : StatusEnum.values()) { + if (b.value.equals(value)) { + return b; + } + } + throw new IllegalArgumentException("Unexpected value '" + value + "'"); } + } - public Pet _name(String _name) { + private StatusEnum status; - this._name = _name; - return this; - } + public Pet() { + } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nonnull + public Pet id(Long id) { + + this.id = id; + return this; + } - public String getName() { - return _name; - } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setName(String _name) { - this._name = _name; - } + public Long getId() { + return id; + } - public Pet category(Category category) { - this.category = category; - return this; - } + public void setId(Long id) { + this.id = id; + } - /** - * Get category - * - * @return category - **/ - @jakarta.annotation.Nullable - public Category getCategory() { - return category; - } + public Pet _name(String _name) { + + this._name = _name; + return this; + } - public void setCategory(Category category) { - this.category = category; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nonnull - public Pet photoUrls(List photoUrls) { + public String getName() { + return _name; + } - this.photoUrls = photoUrls; - return this; - } - public Pet addPhotoUrlsItem(String photoUrlsItem) { - if (this.photoUrls == null) { - this.photoUrls = new ArrayList<>(); - } - this.photoUrls.add(photoUrlsItem); - return this; - } + public void setName(String _name) { + this._name = _name; + } - /** - * Get photoUrls - * - * @return photoUrls - **/ - @jakarta.annotation.Nonnull - public List getPhotoUrls() { - return photoUrls; - } + public Pet category(Category category) { + + this.category = category; + return this; + } - public void setPhotoUrls(List photoUrls) { - this.photoUrls = photoUrls; - } + /** + * Get category + * @return category + **/ + @jakarta.annotation.Nullable - public Pet tags(List tags) { + public Category getCategory() { + return category; + } - this.tags = tags; - return this; - } - public Pet addTagsItem(Tag tagsItem) { - if (this.tags == null) { - this.tags = new ArrayList<>(); - } - this.tags.add(tagsItem); - return this; - } + public void setCategory(Category category) { + this.category = category; + } - /** - * Get tags - * - * @return tags - **/ - @jakarta.annotation.Nullable - public List getTags() { - return tags; - } + public Pet photoUrls(List photoUrls) { + + this.photoUrls = photoUrls; + return this; + } - public void setTags(List tags) { - this.tags = tags; + public Pet addPhotoUrlsItem(String photoUrlsItem) { + if (this.photoUrls == null) { + this.photoUrls = new ArrayList<>(); } + this.photoUrls.add(photoUrlsItem); + return this; + } - public Pet status(StatusEnum status) { + /** + * Get photoUrls + * @return photoUrls + **/ + @jakarta.annotation.Nonnull - this.status = status; - return this; - } + public List getPhotoUrls() { + return photoUrls; + } - /** - * pet status in the store - * - * @return status - **/ - @jakarta.annotation.Nullable - public StatusEnum getStatus() { - return status; - } + public void setPhotoUrls(List photoUrls) { + this.photoUrls = photoUrls; + } - public void setStatus(StatusEnum status) { - this.status = status; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Pet pet = (Pet) o; - return Objects.equals(this.id, pet.id) && - Objects.equals(this._name, pet._name) && - Objects.equals(this.category, pet.category) && - Objects.equals(this.photoUrls, pet.photoUrls) && - Objects.equals(this.tags, pet.tags) && - Objects.equals(this.status, pet.status); - } + public Pet tags(List tags) { + + this.tags = tags; + return this; + } - @Override - public int hashCode() { - return Objects.hash(id, _name, category, photoUrls, tags, status); + public Pet addTagsItem(Tag tagsItem) { + if (this.tags == null) { + this.tags = new ArrayList<>(); } + this.tags.add(tagsItem); + return this; + } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Pet {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append(" category: ").append(toIndentedString(category)).append("\n"); - sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); - sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); - sb.append(" status: ").append(toIndentedString(status)).append("\n"); - sb.append("}"); - return sb.toString(); - } + /** + * Get tags + * @return tags + **/ + @jakarta.annotation.Nullable - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } + public List getTags() { + return tags; + } - /** - * pet status in the store - */ - public enum StatusEnum { - AVAILABLE("available"), - PENDING("pending"), + public void setTags(List tags) { + this.tags = tags; + } - SOLD("sold"); - private String value; + public Pet status(StatusEnum status) { + + this.status = status; + return this; + } - StatusEnum(String value) { - this.value = value; - } + /** + * pet status in the store + * @return status + **/ + @jakarta.annotation.Nullable - public static StatusEnum fromValue(String value) { - for (StatusEnum b : StatusEnum.values()) { - if (b.value.equals(value)) { - return b; - } - } - throw new IllegalArgumentException("Unexpected value '" + value + "'"); - } + public StatusEnum getStatus() { + return status; + } - public String getValue() { - return value; - } - @Override - public String toString() { - return String.valueOf(value); - } + public void setStatus(StatusEnum status) { + this.status = status; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Pet pet = (Pet) o; + return Objects.equals(this.id, pet.id) && + Objects.equals(this._name, pet._name) && + Objects.equals(this.category, pet.category) && + Objects.equals(this.photoUrls, pet.photoUrls) && + Objects.equals(this.tags, pet.tags) && + Objects.equals(this.status, pet.status); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name, category, photoUrls, tags, status); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Pet {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append(" category: ").append(toIndentedString(category)).append("\n"); + sb.append(" photoUrls: ").append(toIndentedString(photoUrls)).append("\n"); + sb.append(" tags: ").append(toIndentedString(tags)).append("\n"); + sb.append(" status: ").append(toIndentedString(status)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index 59a5de829b..f0b752e0e5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -1,118 +1,119 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class Tag { - private Long id; - - private String _name; + private Long id; - public Tag() { - } + private String _name; - public Tag id(Long id) { + public Tag() { + } - this.id = id; - return this; - } - - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable - - public Long getId() { - return id; - } + public Tag id(Long id) { + + this.id = id; + return this; + } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public Tag _name(String _name) { + public void setId(Long id) { + this.id = id; + } - this._name = _name; - return this; - } - /** - * Get _name - * - * @return _name - **/ - @jakarta.annotation.Nullable + public Tag _name(String _name) { + + this._name = _name; + return this; + } - public String getName() { - return _name; - } + /** + * Get _name + * @return _name + **/ + @jakarta.annotation.Nullable + public String getName() { + return _name; + } - public void setName(String _name) { - this._name = _name; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Tag tag = (Tag) o; - return Objects.equals(this.id, tag.id) && - Objects.equals(this._name, tag._name); - } + public void setName(String _name) { + this._name = _name; + } - @Override - public int hashCode() { - return Objects.hash(id, _name); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class Tag {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + Tag tag = (Tag) o; + return Objects.equals(this.id, tag.id) && + Objects.equals(this._name, tag._name); + } + + @Override + public int hashCode() { + return Objects.hash(id, _name); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class Tag {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" _name: ").append(toIndentedString(_name)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index 7a049fe569..bce06668b9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -1,280 +1,275 @@ /* - * Copyright the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +* Copyright the original author or authors. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ package org.citrusframework.openapi.generator.rest.petstore.model; import java.util.Objects; +import java.util.Arrays; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; /** * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class User { - private Long id; - - private String username; - - private String firstName; + private Long id; - private String lastName; + private String username; - private String email; + private String firstName; - private String password; + private String lastName; - private String phone; + private String email; - private Integer userStatus; - - public User() { - } + private String password; - public User id(Long id) { + private String phone; - this.id = id; - return this; - } + private Integer userStatus; - /** - * Get id - * - * @return id - **/ - @jakarta.annotation.Nullable + public User() { + } - public Long getId() { - return id; - } + public User id(Long id) { + + this.id = id; + return this; + } + /** + * Get id + * @return id + **/ + @jakarta.annotation.Nullable - public void setId(Long id) { - this.id = id; - } + public Long getId() { + return id; + } - public User username(String username) { + public void setId(Long id) { + this.id = id; + } - this.username = username; - return this; - } - /** - * Get username - * - * @return username - **/ - @jakarta.annotation.Nullable + public User username(String username) { + + this.username = username; + return this; + } - public String getUsername() { - return username; - } + /** + * Get username + * @return username + **/ + @jakarta.annotation.Nullable - - public void setUsername(String username) { - this.username = username; - } - - - public User firstName(String firstName) { - - this.firstName = firstName; - return this; - } - - /** - * Get firstName - * - * @return firstName - **/ - @jakarta.annotation.Nullable - - public String getFirstName() { - return firstName; - } + public String getUsername() { + return username; + } - public void setFirstName(String firstName) { - this.firstName = firstName; - } + public void setUsername(String username) { + this.username = username; + } - public User lastName(String lastName) { + public User firstName(String firstName) { + + this.firstName = firstName; + return this; + } - this.lastName = lastName; - return this; - } + /** + * Get firstName + * @return firstName + **/ + @jakarta.annotation.Nullable - /** - * Get lastName - * - * @return lastName - **/ - @jakarta.annotation.Nullable + public String getFirstName() { + return firstName; + } - public String getLastName() { - return lastName; - } + public void setFirstName(String firstName) { + this.firstName = firstName; + } - public void setLastName(String lastName) { - this.lastName = lastName; - } + public User lastName(String lastName) { + + this.lastName = lastName; + return this; + } - public User email(String email) { + /** + * Get lastName + * @return lastName + **/ + @jakarta.annotation.Nullable - this.email = email; - return this; - } + public String getLastName() { + return lastName; + } - /** - * Get email - * - * @return email - **/ - @jakarta.annotation.Nullable - public String getEmail() { - return email; - } + public void setLastName(String lastName) { + this.lastName = lastName; + } - public void setEmail(String email) { - this.email = email; - } + public User email(String email) { + + this.email = email; + return this; + } + /** + * Get email + * @return email + **/ + @jakarta.annotation.Nullable - public User password(String password) { + public String getEmail() { + return email; + } - this.password = password; - return this; - } - /** - * Get password - * - * @return password - **/ - @jakarta.annotation.Nullable + public void setEmail(String email) { + this.email = email; + } - public String getPassword() { - return password; - } + public User password(String password) { + + this.password = password; + return this; + } - public void setPassword(String password) { - this.password = password; - } + /** + * Get password + * @return password + **/ + @jakarta.annotation.Nullable + public String getPassword() { + return password; + } - public User phone(String phone) { - this.phone = phone; - return this; - } + public void setPassword(String password) { + this.password = password; + } - /** - * Get phone - * - * @return phone - **/ - @jakarta.annotation.Nullable - public String getPhone() { - return phone; - } + public User phone(String phone) { + + this.phone = phone; + return this; + } + /** + * Get phone + * @return phone + **/ + @jakarta.annotation.Nullable - public void setPhone(String phone) { - this.phone = phone; - } + public String getPhone() { + return phone; + } - public User userStatus(Integer userStatus) { + public void setPhone(String phone) { + this.phone = phone; + } - this.userStatus = userStatus; - return this; - } - /** - * User Status - * - * @return userStatus - **/ - @jakarta.annotation.Nullable + public User userStatus(Integer userStatus) { + + this.userStatus = userStatus; + return this; + } - public Integer getUserStatus() { - return userStatus; - } + /** + * User Status + * @return userStatus + **/ + @jakarta.annotation.Nullable + public Integer getUserStatus() { + return userStatus; + } - public void setUserStatus(Integer userStatus) { - this.userStatus = userStatus; - } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - User user = (User) o; - return Objects.equals(this.id, user.id) && - Objects.equals(this.username, user.username) && - Objects.equals(this.firstName, user.firstName) && - Objects.equals(this.lastName, user.lastName) && - Objects.equals(this.email, user.email) && - Objects.equals(this.password, user.password) && - Objects.equals(this.phone, user.phone) && - Objects.equals(this.userStatus, user.userStatus); - } + public void setUserStatus(Integer userStatus) { + this.userStatus = userStatus; + } - @Override - public int hashCode() { - return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class User {\n"); - sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" username: ").append(toIndentedString(username)).append("\n"); - sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); - sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); - sb.append(" email: ").append(toIndentedString(email)).append("\n"); - sb.append(" password: ").append(toIndentedString(password)).append("\n"); - sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); - sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); - sb.append("}"); - return sb.toString(); + if (o == null || getClass() != o.getClass()) { + return false; } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); + User user = (User) o; + return Objects.equals(this.id, user.id) && + Objects.equals(this.username, user.username) && + Objects.equals(this.firstName, user.firstName) && + Objects.equals(this.lastName, user.lastName) && + Objects.equals(this.email, user.email) && + Objects.equals(this.password, user.password) && + Objects.equals(this.phone, user.phone) && + Objects.equals(this.userStatus, user.userStatus); + } + + @Override + public int hashCode() { + return Objects.hash(id, username, firstName, lastName, email, password, phone, userStatus); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class User {\n"); + sb.append(" id: ").append(toIndentedString(id)).append("\n"); + sb.append(" username: ").append(toIndentedString(username)).append("\n"); + sb.append(" firstName: ").append(toIndentedString(firstName)).append("\n"); + sb.append(" lastName: ").append(toIndentedString(lastName)).append("\n"); + sb.append(" email: ").append(toIndentedString(email)).append("\n"); + sb.append(" password: ").append(toIndentedString(password)).append("\n"); + sb.append(" phone: ").append(toIndentedString(phone)).append("\n"); + sb.append(" userStatus: ").append(toIndentedString(userStatus)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; } + return o.toString().replace("\n", "\n "); + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index f68399a060..37926cd0aa 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -1,46 +1,58 @@ package org.citrusframework.openapi.generator.rest.petstore.request; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import java.net.URL; -import java.util.List; -import java.util.Map; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class PetApi implements GeneratedApi { +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class PetApi implements GeneratedApi +{ - private final List customizers; - private final Endpoint endpoint; - private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; + @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - public PetApi(Endpoint endpoint) { + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public PetApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public PetApi(Endpoint endpoint, List customizers) { + public PetApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -88,158 +100,158 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public AddPetSendActionBuilder sendAddPet() { - return new AddPetSendActionBuilder(this, openApiSpecification); + public AddPetSendActionBuilder sendAddPet() { + return new AddPetSendActionBuilder(this, openApiSpecification); } - public AddPetReceiveActionBuilder receiveAddPet(@NotNull HttpStatus statusCode) { + public AddPetReceiveActionBuilder receiveAddPet(@NotNull HttpStatus statusCode) { return new AddPetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public AddPetReceiveActionBuilder receiveAddPet(@NotNull String statusCode) { - return new AddPetReceiveActionBuilder(this, openApiSpecification, statusCode); + public AddPetReceiveActionBuilder receiveAddPet(@NotNull String statusCode) { + return new AddPetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public DeletePetSendActionBuilder sendDeletePet(Long petId) { - return new DeletePetSendActionBuilder(this, openApiSpecification, petId); + public DeletePetSendActionBuilder sendDeletePet(Long petId) { + return new DeletePetSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public DeletePetSendActionBuilder sendDeletePet$(String petIdExpression) { - return new DeletePetSendActionBuilder(openApiSpecification, this, petIdExpression); + public DeletePetSendActionBuilder sendDeletePet$(String petIdExpression ) { + return new DeletePetSendActionBuilder(openApiSpecification, this, petIdExpression); } - public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull HttpStatus statusCode) { + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull HttpStatus statusCode) { return new DeletePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull String statusCode) { - return new DeletePetReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeletePetReceiveActionBuilder receiveDeletePet(@NotNull String statusCode) { + return new DeletePetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public FindPetsByStatusSendActionBuilder sendFindPetsByStatus() { - return new FindPetsByStatusSendActionBuilder(this, openApiSpecification); + public FindPetsByStatusSendActionBuilder sendFindPetsByStatus() { + return new FindPetsByStatusSendActionBuilder(this, openApiSpecification); } - public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull HttpStatus statusCode) { + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull HttpStatus statusCode) { return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull String statusCode) { - return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, statusCode); + public FindPetsByStatusReceiveActionBuilder receiveFindPetsByStatus(@NotNull String statusCode) { + return new FindPetsByStatusReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public FindPetsByTagsSendActionBuilder sendFindPetsByTags() { - return new FindPetsByTagsSendActionBuilder(this, openApiSpecification); + public FindPetsByTagsSendActionBuilder sendFindPetsByTags() { + return new FindPetsByTagsSendActionBuilder(this, openApiSpecification); } - public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull HttpStatus statusCode) { + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull HttpStatus statusCode) { return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull String statusCode) { - return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, statusCode); + public FindPetsByTagsReceiveActionBuilder receiveFindPetsByTags(@NotNull String statusCode) { + return new FindPetsByTagsReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetPetByIdSendActionBuilder sendGetPetById(Long petId) { - GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(this, openApiSpecification, petId); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetPetByIdSendActionBuilder sendGetPetById(Long petId) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(this, openApiSpecification, petId); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetPetByIdSendActionBuilder sendGetPetById$(String petIdExpression) { - GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(openApiSpecification, this, petIdExpression); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - builder.setApiKey(defaultApiKey); - return builder; + public GetPetByIdSendActionBuilder sendGetPetById$(String petIdExpression ) { + GetPetByIdSendActionBuilder builder = new GetPetByIdSendActionBuilder(openApiSpecification, this, petIdExpression); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + builder.setApiKey(defaultApiKey); + return builder; } - public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull HttpStatus statusCode) { + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull HttpStatus statusCode) { return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull String statusCode) { - return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetPetByIdReceiveActionBuilder receiveGetPetById(@NotNull String statusCode) { + return new GetPetByIdReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetSendActionBuilder sendUpdatePet() { - return new UpdatePetSendActionBuilder(this, openApiSpecification); + public UpdatePetSendActionBuilder sendUpdatePet() { + return new UpdatePetSendActionBuilder(this, openApiSpecification); } - public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull HttpStatus statusCode) { + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull HttpStatus statusCode) { return new UpdatePetReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull String statusCode) { - return new UpdatePetReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetReceiveActionBuilder receiveUpdatePet(@NotNull String statusCode) { + return new UpdatePetReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm(Long petId) { - return new UpdatePetWithFormSendActionBuilder(this, openApiSpecification, petId); + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm(Long petId) { + return new UpdatePetWithFormSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm$(String petIdExpression) { - return new UpdatePetWithFormSendActionBuilder(openApiSpecification, this, petIdExpression); + public UpdatePetWithFormSendActionBuilder sendUpdatePetWithForm$(String petIdExpression ) { + return new UpdatePetWithFormSendActionBuilder(openApiSpecification, this, petIdExpression); } - public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull HttpStatus statusCode) { + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull HttpStatus statusCode) { return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull String statusCode) { - return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdatePetWithFormReceiveActionBuilder receiveUpdatePetWithForm(@NotNull String statusCode) { + return new UpdatePetWithFormReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UploadFileSendActionBuilder sendUploadFile(Long petId) { - return new UploadFileSendActionBuilder(this, openApiSpecification, petId); + public UploadFileSendActionBuilder sendUploadFile(Long petId) { + return new UploadFileSendActionBuilder(this, openApiSpecification, petId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public UploadFileSendActionBuilder sendUploadFile$(String petIdExpression) { - return new UploadFileSendActionBuilder(openApiSpecification, this, petIdExpression); + public UploadFileSendActionBuilder sendUploadFile$(String petIdExpression ) { + return new UploadFileSendActionBuilder(openApiSpecification, this, petIdExpression); } - public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull HttpStatus statusCode) { + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull HttpStatus statusCode) { return new UploadFileReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull String statusCode) { - return new UploadFileReceiveActionBuilder(this, openApiSpecification, statusCode); + public UploadFileReceiveActionBuilder receiveUploadFile(@NotNull String statusCode) { + return new UploadFileReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class AddPetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -270,7 +282,7 @@ public SendMessageAction doBuild() { } public static class AddPetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -278,7 +290,7 @@ public static class AddPetReceiveActionBuilder extends private static final String OPERATION_NAME = "addPet"; - public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public AddPetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -299,7 +311,7 @@ public ReceiveMessageAction doBuild() { } public static class DeletePetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -318,8 +330,8 @@ public DeletePetSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSpe /** * Constructor with required parameters as string to allow for dynamic content. */ - public DeletePetSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public DeletePetSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -338,7 +350,7 @@ public DeletePetSendActionBuilder petId(Long petId) { public DeletePetSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public DeletePetSendActionBuilder apiKey(String apiKey) { @@ -362,7 +374,7 @@ public SendMessageAction doBuild() { } public static class DeletePetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -370,7 +382,7 @@ public static class DeletePetReceiveActionBuilder extends private static final String OPERATION_NAME = "deletePet"; - public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeletePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -391,7 +403,7 @@ public ReceiveMessageAction doBuild() { } public static class FindPetsByStatusSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -431,7 +443,7 @@ public SendMessageAction doBuild() { } public static class FindPetsByStatusReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -439,7 +451,7 @@ public static class FindPetsByStatusReceiveActionBuilder extends private static final String OPERATION_NAME = "findPetsByStatus"; - public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public FindPetsByStatusReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -460,7 +472,7 @@ public ReceiveMessageAction doBuild() { } public static class FindPetsByTagsSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -479,12 +491,12 @@ public FindPetsByTagsSendActionBuilder(PetApi petApi, OpenApiSpecification openA super(petApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); } - public FindPetsByTagsSendActionBuilder tags(String... tags) { + public FindPetsByTagsSendActionBuilder tags(String...tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); return this; } - public void setTags(String... tags) { + public void setTags(String...tags) { queryParameter("tags", tags, ParameterStyle.FORM, true, false); } @@ -500,7 +512,7 @@ public SendMessageAction doBuild() { } public static class FindPetsByTagsReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -508,7 +520,7 @@ public static class FindPetsByTagsReceiveActionBuilder extends private static final String OPERATION_NAME = "findPetsByTags"; - public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public FindPetsByTagsReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -529,7 +541,7 @@ public ReceiveMessageAction doBuild() { } public static class GetPetByIdSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -556,8 +568,8 @@ public GetPetByIdSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetPetByIdSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetPetByIdSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -576,7 +588,7 @@ public GetPetByIdSendActionBuilder petId(Long petId) { public GetPetByIdSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public void setBase64EncodeApiKey(boolean encode) { @@ -605,7 +617,7 @@ public SendMessageAction doBuild() { } public static class GetPetByIdReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -613,7 +625,7 @@ public static class GetPetByIdReceiveActionBuilder extends private static final String OPERATION_NAME = "getPetById"; - public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetPetByIdReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -634,7 +646,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -665,7 +677,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -673,7 +685,7 @@ public static class UpdatePetReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePet"; - public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -694,7 +706,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdatePetWithFormSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -713,8 +725,8 @@ public UpdatePetWithFormSendActionBuilder(PetApi petApi, OpenApiSpecification op /** * Constructor with required parameters as string to allow for dynamic content. */ - public UpdatePetWithFormSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UpdatePetWithFormSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -733,7 +745,7 @@ public UpdatePetWithFormSendActionBuilder petId(Long petId) { public UpdatePetWithFormSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UpdatePetWithFormSendActionBuilder _name(String _name) { @@ -766,7 +778,7 @@ public SendMessageAction doBuild() { } public static class UpdatePetWithFormReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -774,7 +786,7 @@ public static class UpdatePetWithFormReceiveActionBuilder extends private static final String OPERATION_NAME = "updatePetWithForm"; - public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdatePetWithFormReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -795,7 +807,7 @@ public ReceiveMessageAction doBuild() { } public static class UploadFileSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -814,8 +826,8 @@ public UploadFileSendActionBuilder(PetApi petApi, OpenApiSpecification openApiSp /** * Constructor with required parameters as string to allow for dynamic content. */ - public UploadFileSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { - super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public UploadFileSendActionBuilder(OpenApiSpecification openApiSpecification, PetApi petApi, String petIdExpression) { + super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -834,7 +846,7 @@ public UploadFileSendActionBuilder petId(Long petId) { public UploadFileSendActionBuilder petId(String petIdExpression) { pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } public UploadFileSendActionBuilder additionalMetadata(String additionalMetadata) { @@ -872,7 +884,7 @@ public SendMessageAction doBuild() { } public static class UploadFileReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -880,7 +892,7 @@ public static class UploadFileReceiveActionBuilder extends private static final String OPERATION_NAME = "uploadFile"; - public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UploadFileReceiveActionBuilder(PetApi petApi, OpenApiSpecification openApiSpecification, String statusCode) { super(petApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -899,4 +911,4 @@ public ReceiveMessageAction doBuild() { } } -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 34595093b2..58f2cc1078 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -1,45 +1,58 @@ package org.citrusframework.openapi.generator.rest.petstore.request; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import java.net.URL; -import java.util.List; -import java.util.Map; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class StoreApi implements GeneratedApi { +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class StoreApi implements GeneratedApi +{ - private final List customizers; - private final Endpoint endpoint; - private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; + @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - public StoreApi(Endpoint endpoint) { + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public StoreApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public StoreApi(Endpoint endpoint, List customizers) { + public StoreApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -87,81 +100,81 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public DeleteOrderSendActionBuilder sendDeleteOrder(Long orderId) { - return new DeleteOrderSendActionBuilder(this, openApiSpecification, orderId); + public DeleteOrderSendActionBuilder sendDeleteOrder(Long orderId) { + return new DeleteOrderSendActionBuilder(this, openApiSpecification, orderId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public DeleteOrderSendActionBuilder sendDeleteOrder$(String orderIdExpression) { - return new DeleteOrderSendActionBuilder(openApiSpecification, this, orderIdExpression); + public DeleteOrderSendActionBuilder sendDeleteOrder$(String orderIdExpression ) { + return new DeleteOrderSendActionBuilder(openApiSpecification, this, orderIdExpression); } - public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull HttpStatus statusCode) { + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull HttpStatus statusCode) { return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull String statusCode) { - return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeleteOrderReceiveActionBuilder receiveDeleteOrder(@NotNull String statusCode) { + return new DeleteOrderReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetInventorySendActionBuilder sendGetInventory() { - GetInventorySendActionBuilder builder = new GetInventorySendActionBuilder(this, openApiSpecification); - builder.setBase64EncodeApiKey(base64EncodeApiKey); - return builder; + public GetInventorySendActionBuilder sendGetInventory() { + GetInventorySendActionBuilder builder = new GetInventorySendActionBuilder(this, openApiSpecification); + builder.setBase64EncodeApiKey(base64EncodeApiKey); + return builder; } - public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull HttpStatus statusCode) { + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull HttpStatus statusCode) { return new GetInventoryReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull String statusCode) { - return new GetInventoryReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetInventoryReceiveActionBuilder receiveGetInventory(@NotNull String statusCode) { + return new GetInventoryReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetOrderByIdSendActionBuilder sendGetOrderById(Long orderId) { - return new GetOrderByIdSendActionBuilder(this, openApiSpecification, orderId); + public GetOrderByIdSendActionBuilder sendGetOrderById(Long orderId) { + return new GetOrderByIdSendActionBuilder(this, openApiSpecification, orderId); } /** - * Builder with required parameters as string to allow for dynamic content. + * Builder with required parameters as string, allowing dynamic content using citrus expressions. */ - public GetOrderByIdSendActionBuilder sendGetOrderById$(String orderIdExpression) { - return new GetOrderByIdSendActionBuilder(openApiSpecification, this, orderIdExpression); + public GetOrderByIdSendActionBuilder sendGetOrderById$(String orderIdExpression ) { + return new GetOrderByIdSendActionBuilder(openApiSpecification, this, orderIdExpression); } - public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull HttpStatus statusCode) { + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull HttpStatus statusCode) { return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull String statusCode) { - return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetOrderByIdReceiveActionBuilder receiveGetOrderById(@NotNull String statusCode) { + return new GetOrderByIdReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public PlaceOrderSendActionBuilder sendPlaceOrder() { - return new PlaceOrderSendActionBuilder(this, openApiSpecification); + public PlaceOrderSendActionBuilder sendPlaceOrder() { + return new PlaceOrderSendActionBuilder(this, openApiSpecification); } - public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull HttpStatus statusCode) { + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull HttpStatus statusCode) { return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull String statusCode) { - return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, statusCode); + public PlaceOrderReceiveActionBuilder receivePlaceOrder(@NotNull String statusCode) { + return new PlaceOrderReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class DeleteOrderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -180,8 +193,8 @@ public DeleteOrderSendActionBuilder(StoreApi storeApi, OpenApiSpecification open /** * Constructor with required parameters as string to allow for dynamic content. */ - public DeleteOrderSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { - super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public DeleteOrderSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -200,7 +213,7 @@ public DeleteOrderSendActionBuilder orderId(Long orderId) { public DeleteOrderSendActionBuilder orderId(String orderIdExpression) { pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -215,7 +228,7 @@ public SendMessageAction doBuild() { } public static class DeleteOrderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -223,7 +236,7 @@ public static class DeleteOrderReceiveActionBuilder extends private static final String OPERATION_NAME = "deleteOrder"; - public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeleteOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -244,7 +257,7 @@ public ReceiveMessageAction doBuild() { } public static class GetInventorySendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -297,7 +310,7 @@ public SendMessageAction doBuild() { } public static class GetInventoryReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -305,7 +318,7 @@ public static class GetInventoryReceiveActionBuilder extends private static final String OPERATION_NAME = "getInventory"; - public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetInventoryReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -326,7 +339,7 @@ public ReceiveMessageAction doBuild() { } public static class GetOrderByIdSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -345,8 +358,8 @@ public GetOrderByIdSendActionBuilder(StoreApi storeApi, OpenApiSpecification ope /** * Constructor with required parameters as string to allow for dynamic content. */ - public GetOrderByIdSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { - super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); + public GetOrderByIdSendActionBuilder(OpenApiSpecification openApiSpecification, StoreApi storeApi, String orderIdExpression) { + super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); } @@ -365,7 +378,7 @@ public GetOrderByIdSendActionBuilder orderId(Long orderId) { public GetOrderByIdSendActionBuilder orderId(String orderIdExpression) { pathParameter("orderId", orderIdExpression, ParameterStyle.SIMPLE, false, false); - return this; + return this; } @Override @@ -380,7 +393,7 @@ public SendMessageAction doBuild() { } public static class GetOrderByIdReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -388,7 +401,7 @@ public static class GetOrderByIdReceiveActionBuilder extends private static final String OPERATION_NAME = "getOrderById"; - public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetOrderByIdReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -409,7 +422,7 @@ public ReceiveMessageAction doBuild() { } public static class PlaceOrderSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -454,7 +467,7 @@ public SendMessageAction doBuild() { } public static class PlaceOrderReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -462,7 +475,7 @@ public static class PlaceOrderReceiveActionBuilder extends private static final String OPERATION_NAME = "placeOrder"; - public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { + public PlaceOrderReceiveActionBuilder(StoreApi storeApi, OpenApiSpecification openApiSpecification, String statusCode) { super(storeApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -481,4 +494,4 @@ public ReceiveMessageAction doBuild() { } } -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index 75f7a48b04..43681eca80 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -1,45 +1,58 @@ package org.citrusframework.openapi.generator.rest.petstore.request; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static org.citrusframework.util.StringUtils.isEmpty; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import jakarta.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.net.URL; +import java.time.LocalDate; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.List; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; -import org.citrusframework.openapi.generator.rest.petstore.model.*; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.ParameterStyle; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.testapi.TestApiUtils; +import org.citrusframework.spi.Resource; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; -import java.net.URL; -import java.util.List; -import java.util.Map; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.generator.rest.petstore.model.*; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class UserApi implements GeneratedApi { +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class UserApi implements GeneratedApi +{ - private final List customizers; - private final Endpoint endpoint; - private final OpenApiSpecification openApiSpecification; @Value("${" + "petstore.base64-encode-api-key:#{false}}") private boolean base64EncodeApiKey; + @Value("${" + "petstore.api-key:#{null}}") private String defaultApiKey; - public UserApi(Endpoint endpoint) { + private final List customizers; + + private final Endpoint endpoint; + + private final OpenApiSpecification openApiSpecification; + + public UserApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public UserApi(Endpoint endpoint, List customizers) { + public UserApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; @@ -87,110 +100,110 @@ public List getCustomizers() { /** * Builder with type safe required parameters. */ - public CreateUserSendActionBuilder sendCreateUser() { - return new CreateUserSendActionBuilder(this, openApiSpecification); + public CreateUserSendActionBuilder sendCreateUser() { + return new CreateUserSendActionBuilder(this, openApiSpecification); } - public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull HttpStatus statusCode) { + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull HttpStatus statusCode) { return new CreateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull String statusCode) { - return new CreateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public CreateUserReceiveActionBuilder receiveCreateUser(@NotNull String statusCode) { + return new CreateUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public CreateUsersWithListInputSendActionBuilder sendCreateUsersWithListInput() { - return new CreateUsersWithListInputSendActionBuilder(this, openApiSpecification); + public CreateUsersWithListInputSendActionBuilder sendCreateUsersWithListInput() { + return new CreateUsersWithListInputSendActionBuilder(this, openApiSpecification); } - public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull HttpStatus statusCode) { + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull HttpStatus statusCode) { return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull String statusCode) { - return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, statusCode); + public CreateUsersWithListInputReceiveActionBuilder receiveCreateUsersWithListInput(@NotNull String statusCode) { + return new CreateUsersWithListInputReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public DeleteUserSendActionBuilder sendDeleteUser(String username) { - return new DeleteUserSendActionBuilder(this, openApiSpecification, username); + public DeleteUserSendActionBuilder sendDeleteUser(String username) { + return new DeleteUserSendActionBuilder(this, openApiSpecification, username); } - public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull HttpStatus statusCode) { + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull HttpStatus statusCode) { return new DeleteUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull String statusCode) { - return new DeleteUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public DeleteUserReceiveActionBuilder receiveDeleteUser(@NotNull String statusCode) { + return new DeleteUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public GetUserByNameSendActionBuilder sendGetUserByName(String username) { - return new GetUserByNameSendActionBuilder(this, openApiSpecification, username); + public GetUserByNameSendActionBuilder sendGetUserByName(String username) { + return new GetUserByNameSendActionBuilder(this, openApiSpecification, username); } - public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull HttpStatus statusCode) { + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull HttpStatus statusCode) { return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull String statusCode) { - return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, statusCode); + public GetUserByNameReceiveActionBuilder receiveGetUserByName(@NotNull String statusCode) { + return new GetUserByNameReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public LoginUserSendActionBuilder sendLoginUser() { - return new LoginUserSendActionBuilder(this, openApiSpecification); + public LoginUserSendActionBuilder sendLoginUser() { + return new LoginUserSendActionBuilder(this, openApiSpecification); } - public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull HttpStatus statusCode) { + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull HttpStatus statusCode) { return new LoginUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull String statusCode) { - return new LoginUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public LoginUserReceiveActionBuilder receiveLoginUser(@NotNull String statusCode) { + return new LoginUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public LogoutUserSendActionBuilder sendLogoutUser() { - return new LogoutUserSendActionBuilder(this, openApiSpecification); + public LogoutUserSendActionBuilder sendLogoutUser() { + return new LogoutUserSendActionBuilder(this, openApiSpecification); } - public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull HttpStatus statusCode) { + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull HttpStatus statusCode) { return new LogoutUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull String statusCode) { - return new LogoutUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public LogoutUserReceiveActionBuilder receiveLogoutUser(@NotNull String statusCode) { + return new LogoutUserReceiveActionBuilder(this, openApiSpecification, statusCode); } /** * Builder with type safe required parameters. */ - public UpdateUserSendActionBuilder sendUpdateUser(String username) { - return new UpdateUserSendActionBuilder(this, openApiSpecification, username); + public UpdateUserSendActionBuilder sendUpdateUser(String username) { + return new UpdateUserSendActionBuilder(this, openApiSpecification, username); } - public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull HttpStatus statusCode) { + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull HttpStatus statusCode) { return new UpdateUserReceiveActionBuilder(this, openApiSpecification, Integer.toString(statusCode.value())); } - public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull String statusCode) { - return new UpdateUserReceiveActionBuilder(this, openApiSpecification, statusCode); + public UpdateUserReceiveActionBuilder receiveUpdateUser(@NotNull String statusCode) { + return new UpdateUserReceiveActionBuilder(this, openApiSpecification, statusCode); } public static class CreateUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -235,7 +248,7 @@ public SendMessageAction doBuild() { } public static class CreateUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -243,7 +256,7 @@ public static class CreateUserReceiveActionBuilder extends private static final String OPERATION_NAME = "createUser"; - public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public CreateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -264,7 +277,7 @@ public ReceiveMessageAction doBuild() { } public static class CreateUsersWithListInputSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "POST"; @@ -283,18 +296,18 @@ public CreateUsersWithListInputSendActionBuilder(UserApi userApi, OpenApiSpecifi super(userApi, openApiSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); } - public CreateUsersWithListInputSendActionBuilder user(User... user) { + public CreateUsersWithListInputSendActionBuilder user(User...user) { return this; } - public void setUser(User... user) { + public void setUser(User...user) { } - public CreateUsersWithListInputSendActionBuilder user(String... userExpression) { + public CreateUsersWithListInputSendActionBuilder user(String...userExpression) { return this; } - public void setUser(String... userExpression) { + public void setUser(String...userExpression) { } @Override @@ -309,7 +322,7 @@ public SendMessageAction doBuild() { } public static class CreateUsersWithListInputReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "POST"; @@ -317,7 +330,7 @@ public static class CreateUsersWithListInputReceiveActionBuilder extends private static final String OPERATION_NAME = "createUsersWithListInput"; - public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public CreateUsersWithListInputReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -338,7 +351,7 @@ public ReceiveMessageAction doBuild() { } public static class DeleteUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -379,7 +392,7 @@ public SendMessageAction doBuild() { } public static class DeleteUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "DELETE"; @@ -387,7 +400,7 @@ public static class DeleteUserReceiveActionBuilder extends private static final String OPERATION_NAME = "deleteUser"; - public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public DeleteUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -408,7 +421,7 @@ public ReceiveMessageAction doBuild() { } public static class GetUserByNameSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -449,7 +462,7 @@ public SendMessageAction doBuild() { } public static class GetUserByNameReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -457,7 +470,7 @@ public static class GetUserByNameReceiveActionBuilder extends private static final String OPERATION_NAME = "getUserByName"; - public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public GetUserByNameReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -478,7 +491,7 @@ public ReceiveMessageAction doBuild() { } public static class LoginUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -527,7 +540,7 @@ public SendMessageAction doBuild() { } public static class LoginUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -535,7 +548,7 @@ public static class LoginUserReceiveActionBuilder extends private static final String OPERATION_NAME = "loginUser"; - public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public LoginUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -556,7 +569,7 @@ public ReceiveMessageAction doBuild() { } public static class LogoutUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "GET"; @@ -587,7 +600,7 @@ public SendMessageAction doBuild() { } public static class LogoutUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "GET"; @@ -595,7 +608,7 @@ public static class LogoutUserReceiveActionBuilder extends private static final String OPERATION_NAME = "logoutUser"; - public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public LogoutUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -616,7 +629,7 @@ public ReceiveMessageAction doBuild() { } public static class UpdateUserSendActionBuilder extends - RestApiSendMessageActionBuilder { + RestApiSendMessageActionBuilder { private static final String METHOD = "PUT"; @@ -671,7 +684,7 @@ public SendMessageAction doBuild() { } public static class UpdateUserReceiveActionBuilder extends - RestApiReceiveMessageActionBuilder { + RestApiReceiveMessageActionBuilder { private static final String METHOD = "PUT"; @@ -679,7 +692,7 @@ public static class UpdateUserReceiveActionBuilder extends private static final String OPERATION_NAME = "updateUser"; - public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { + public UpdateUserReceiveActionBuilder(UserApi userApi, OpenApiSpecification openApiSpecification, String statusCode) { super(userApi, openApiSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); } @@ -698,4 +711,4 @@ public ReceiveMessageAction doBuild() { } } -} \ No newline at end of file +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index e319031c3d..5f77e29dd7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -1,44 +1,42 @@ package org.citrusframework.openapi.generator.rest.petstore.spring; +import java.util.List; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; -import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - -import java.util.List; - +import org.citrusframework.openapi.generator.rest.petstore.PetStore; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreBeanConfiguration { @Bean public OpenApiRepository petStoreOpenApiRepository() { var openApiRepository = new OpenApiRepository(); openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( - PetStore.petStoreApi())); + PetStore.petStoreApi())); return openApiRepository; } - @Bean(name = "PetApi") + @Bean(name="PetApi") public PetApi petApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new PetApi(endpoint, customizers); } - @Bean(name = "StoreApi") + @Bean(name="StoreApi") public StoreApi storeApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new StoreApi(endpoint, customizers); } - @Bean(name = "UserApi") + @Bean(name="UserApi") public UserApi userApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { return new UserApi(endpoint, customizers); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index 7f78d34841..152885556e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -1,160 +1,159 @@ package org.citrusframework.openapi.generator.rest.petstore.spring; import org.citrusframework.openapi.OpenApiSpecification; -import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; import org.citrusframework.openapi.generator.rest.petstore.request.PetApi; import org.citrusframework.openapi.generator.rest.petstore.request.StoreApi; import org.citrusframework.openapi.generator.rest.petstore.request.UserApi; -import org.citrusframework.openapi.testapi.GeneratedApi; -import org.citrusframework.openapi.testapi.RestApiReceiveMessageActionBuilder; -import org.citrusframework.openapi.testapi.RestApiSendMessageActionBuilder; import org.citrusframework.openapi.testapi.spring.RestApiReceiveMessageActionParser; import org.citrusframework.openapi.testapi.spring.RestApiSendMessageActionParser; +import org.citrusframework.openapi.generator.rest.petstore.PetStore; +import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:45.597236600+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:43.309584600+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( - PetStore.petStoreApi()); + PetStore.petStoreApi()); @Override public void init() { - registerOperationParsers(PetApi.class, "add-pet", "addPet", "/pet", + registerOperationParsers(PetApi.class,"add-pet", "addPet", "/pet", PetApi.AddPetSendActionBuilder.class, PetApi.AddPetReceiveActionBuilder.class, - new String[]{}, - new String[]{}); + new String[]{ }, + new String[]{ }); - registerOperationParsers(PetApi.class, "delete-pet", "deletePet", "/pet/{petId}", + registerOperationParsers(PetApi.class,"delete-pet", "deletePet", "/pet/{petId}", PetApi.DeletePetSendActionBuilder.class, PetApi.DeletePetReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{"apiKey"}); + new String[]{ "petId" }, + new String[]{ "apiKey" }); - registerOperationParsers(PetApi.class, "find-pets-by-status", "findPetsByStatus", "/pet/findByStatus", + registerOperationParsers(PetApi.class,"find-pets-by-status", "findPetsByStatus", "/pet/findByStatus", PetApi.FindPetsByStatusSendActionBuilder.class, PetApi.FindPetsByStatusReceiveActionBuilder.class, - new String[]{}, - new String[]{"status"}); + new String[]{ }, + new String[]{ "status" }); - registerOperationParsers(PetApi.class, "find-pets-by-tags", "findPetsByTags", "/pet/findByTags", + registerOperationParsers(PetApi.class,"find-pets-by-tags", "findPetsByTags", "/pet/findByTags", PetApi.FindPetsByTagsSendActionBuilder.class, PetApi.FindPetsByTagsReceiveActionBuilder.class, - new String[]{}, - new String[]{"tags"}); + new String[]{ }, + new String[]{ "tags" }); - registerOperationParsers(PetApi.class, "get-pet-by-id", "getPetById", "/pet/{petId}", + registerOperationParsers(PetApi.class,"get-pet-by-id", "getPetById", "/pet/{petId}", PetApi.GetPetByIdSendActionBuilder.class, PetApi.GetPetByIdReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{"apiKey"}); + new String[]{ "petId" }, + new String[]{ "apiKey" }); - registerOperationParsers(PetApi.class, "update-pet", "updatePet", "/pet", + registerOperationParsers(PetApi.class,"update-pet", "updatePet", "/pet", PetApi.UpdatePetSendActionBuilder.class, PetApi.UpdatePetReceiveActionBuilder.class, - new String[]{}, - new String[]{}); + new String[]{ }, + new String[]{ }); - registerOperationParsers(PetApi.class, "update-pet-with-form", "updatePetWithForm", "/pet/{petId}", + registerOperationParsers(PetApi.class,"update-pet-with-form", "updatePetWithForm", "/pet/{petId}", PetApi.UpdatePetWithFormSendActionBuilder.class, PetApi.UpdatePetWithFormReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{"_name", "status"}); + new String[]{ "petId" }, + new String[]{ "_name", "status" }); - registerOperationParsers(PetApi.class, "upload-file", "uploadFile", "/pet/{petId}/uploadImage", + registerOperationParsers(PetApi.class,"upload-file", "uploadFile", "/pet/{petId}/uploadImage", PetApi.UploadFileSendActionBuilder.class, PetApi.UploadFileReceiveActionBuilder.class, - new String[]{"petId"}, - new String[]{"additionalMetadata", "ERROR_UNKNOWN"}); + new String[]{ "petId" }, + new String[]{ "additionalMetadata", "ERROR_UNKNOWN" }); - registerOperationParsers(StoreApi.class, "delete-order", "deleteOrder", "/store/order/{orderId}", + registerOperationParsers(StoreApi.class,"delete-order", "deleteOrder", "/store/order/{orderId}", StoreApi.DeleteOrderSendActionBuilder.class, StoreApi.DeleteOrderReceiveActionBuilder.class, - new String[]{"orderId"}, - new String[]{}); + new String[]{ "orderId" }, + new String[]{ }); - registerOperationParsers(StoreApi.class, "get-inventory", "getInventory", "/store/inventory", + registerOperationParsers(StoreApi.class,"get-inventory", "getInventory", "/store/inventory", StoreApi.GetInventorySendActionBuilder.class, StoreApi.GetInventoryReceiveActionBuilder.class, - new String[]{}, - new String[]{"apiKey"}); + new String[]{ }, + new String[]{ "apiKey" }); - registerOperationParsers(StoreApi.class, "get-order-by-id", "getOrderById", "/store/order/{orderId}", + registerOperationParsers(StoreApi.class,"get-order-by-id", "getOrderById", "/store/order/{orderId}", StoreApi.GetOrderByIdSendActionBuilder.class, StoreApi.GetOrderByIdReceiveActionBuilder.class, - new String[]{"orderId"}, - new String[]{}); + new String[]{ "orderId" }, + new String[]{ }); - registerOperationParsers(StoreApi.class, "place-order", "placeOrder", "/store/order", + registerOperationParsers(StoreApi.class,"place-order", "placeOrder", "/store/order", StoreApi.PlaceOrderSendActionBuilder.class, StoreApi.PlaceOrderReceiveActionBuilder.class, - new String[]{}, - new String[]{"ERROR_UNKNOWN"}); + new String[]{ }, + new String[]{ "ERROR_UNKNOWN" }); - registerOperationParsers(UserApi.class, "create-user", "createUser", "/user", + registerOperationParsers(UserApi.class,"create-user", "createUser", "/user", UserApi.CreateUserSendActionBuilder.class, UserApi.CreateUserReceiveActionBuilder.class, - new String[]{}, - new String[]{"ERROR_UNKNOWN"}); + new String[]{ }, + new String[]{ "ERROR_UNKNOWN" }); - registerOperationParsers(UserApi.class, "create-users-with-list-input", "createUsersWithListInput", "/user/createWithList", + registerOperationParsers(UserApi.class,"create-users-with-list-input", "createUsersWithListInput", "/user/createWithList", UserApi.CreateUsersWithListInputSendActionBuilder.class, UserApi.CreateUsersWithListInputReceiveActionBuilder.class, - new String[]{}, - new String[]{"user"}); + new String[]{ }, + new String[]{ "user" }); - registerOperationParsers(UserApi.class, "delete-user", "deleteUser", "/user/{username}", + registerOperationParsers(UserApi.class,"delete-user", "deleteUser", "/user/{username}", UserApi.DeleteUserSendActionBuilder.class, UserApi.DeleteUserReceiveActionBuilder.class, - new String[]{"username"}, - new String[]{}); + new String[]{ "username" }, + new String[]{ }); - registerOperationParsers(UserApi.class, "get-user-by-name", "getUserByName", "/user/{username}", + registerOperationParsers(UserApi.class,"get-user-by-name", "getUserByName", "/user/{username}", UserApi.GetUserByNameSendActionBuilder.class, UserApi.GetUserByNameReceiveActionBuilder.class, - new String[]{"username"}, - new String[]{}); + new String[]{ "username" }, + new String[]{ }); - registerOperationParsers(UserApi.class, "login-user", "loginUser", "/user/login", + registerOperationParsers(UserApi.class,"login-user", "loginUser", "/user/login", UserApi.LoginUserSendActionBuilder.class, UserApi.LoginUserReceiveActionBuilder.class, - new String[]{}, - new String[]{"username", "password"}); + new String[]{ }, + new String[]{ "username", "password" }); - registerOperationParsers(UserApi.class, "logout-user", "logoutUser", "/user/logout", + registerOperationParsers(UserApi.class,"logout-user", "logoutUser", "/user/logout", UserApi.LogoutUserSendActionBuilder.class, UserApi.LogoutUserReceiveActionBuilder.class, - new String[]{}, - new String[]{}); + new String[]{ }, + new String[]{ }); - registerOperationParsers(UserApi.class, "update-user", "updateUser", "/user/{username}", + registerOperationParsers(UserApi.class,"update-user", "updateUser", "/user/{username}", UserApi.UpdateUserSendActionBuilder.class, UserApi.UpdateUserReceiveActionBuilder.class, - new String[]{"username"}, - new String[]{"ERROR_UNKNOWN"}); + new String[]{ "username" }, + new String[]{ "ERROR_UNKNOWN" }); } private void registerOperationParsers(Class apiClass, String elementName, String operationName, String path, - Class sendBeanClass, - Class receiveBeanClass, - String[] constructorParameters, - String[] nonConstructorParameters) { + Class sendBeanClass, + Class receiveBeanClass, + String[] constructorParameters, + String[] nonConstructorParameters) { RestApiSendMessageActionParser sendParser = new RestApiSendMessageActionParser(openApiSpecification, operationName, - path, - apiClass, - sendBeanClass, - receiveBeanClass, - "petstore.endpoint"); + path, + apiClass, + sendBeanClass, + receiveBeanClass, + "petstore.endpoint"); sendParser.setConstructorParameters(constructorParameters); sendParser.setNonConstructorParameters(nonConstructorParameters); - registerBeanDefinitionParser("send-" + elementName, sendParser); + registerBeanDefinitionParser("send-"+elementName, sendParser); RestApiReceiveMessageActionParser receiveParser = new RestApiReceiveMessageActionParser(openApiSpecification, - operationName, apiClass, receiveBeanClass, "petstore.endpoint"); - registerBeanDefinitionParser("receive-" + elementName, receiveParser); + operationName, apiClass, receiveBeanClass, "petstore.endpoint"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); } - } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/BookService.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/BookService.java new file mode 100644 index 0000000000..08ceebb8e8 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/BookService.java @@ -0,0 +1,10 @@ +package org.citrusframework.openapi.generator.soap.bookservice; + +import java.net.URL; + +public class BookService { + + public static URL bookServiceApi() { + return BookService.class.getResource("BookService_openApi.yaml"); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index c6992817a8..8afa3eac7e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -1,32 +1,33 @@ package org.citrusframework.openapi.generator.soap.bookservice.request; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.citrusframework.ws.actions.ReceiveSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; -import org.citrusframework.ws.actions.ReceiveSoapMessageAction; -import org.citrusframework.ws.actions.SendSoapMessageAction; - -import java.util.List; -import java.util.Map; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-05T19:07:46.419751700+02:00[Europe/Zurich]", comments = "Generator version: 7.5.0") -public class BookServiceSoapApi implements GeneratedApi { +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.612584400+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class BookServiceSoapApi implements GeneratedApi +{ private final Endpoint endpoint; private final List customizers; - public BookServiceSoapApi(Endpoint endpoint) { + public BookServiceSoapApi(Endpoint endpoint) { this(endpoint, emptyList()); } - public BookServiceSoapApi(Endpoint endpoint, List customizers) { + public BookServiceSoapApi(Endpoint endpoint, List customizers) { this.endpoint = endpoint; this.customizers = customizers; } @@ -65,27 +66,27 @@ public List getCustomizers() { return customizers; } - public AddBookSendActionBuilder sendAddBook() { + public AddBookSendActionBuilder sendAddBook() { return new AddBookSendActionBuilder(this); } - public AddBookReceiveActionBuilder receiveAddBook() { + public AddBookReceiveActionBuilder receiveAddBook() { return new AddBookReceiveActionBuilder(this); } - public GetAllBooksSendActionBuilder sendGetAllBooks() { + public GetAllBooksSendActionBuilder sendGetAllBooks() { return new GetAllBooksSendActionBuilder(this); } - public GetAllBooksReceiveActionBuilder receiveGetAllBooks() { + public GetAllBooksReceiveActionBuilder receiveGetAllBooks() { return new GetAllBooksReceiveActionBuilder(this); } - public GetBookSendActionBuilder sendGetBook() { + public GetBookSendActionBuilder sendGetBook() { return new GetBookSendActionBuilder(this); } - public GetBookReceiveActionBuilder receiveGetBook() { + public GetBookReceiveActionBuilder receiveGetBook() { return new GetBookReceiveActionBuilder(this); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java new file mode 100644 index 0000000000..200e911e65 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java @@ -0,0 +1,32 @@ +package org.citrusframework.openapi.generator.soap.bookservice.spring; + +import java.util.List; +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; +import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.citrusframework.openapi.generator.soap.bookservice.BookService; + +@Configuration +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.612584400+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class BookServiceBeanConfiguration { + + @Bean + public OpenApiRepository bookServiceOpenApiRepository() { + var openApiRepository = new OpenApiRepository(); + openApiRepository.getOpenApiSpecifications().add(OpenApiSpecification.from( + BookService.bookServiceApi())); + return openApiRepository; + } + + @Bean(name="BookServiceSoapApi") + public BookServiceSoapApi bookServiceSoapApi(@Qualifier("bookstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { + return new BookServiceSoapApi(endpoint, customizers); + } + +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java new file mode 100644 index 0000000000..d1fa6104dc --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java @@ -0,0 +1,50 @@ +package org.citrusframework.openapi.generator.soap.bookservice.spring; + +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; +import org.citrusframework.openapi.testapi.SoapApiReceiveMessageActionBuilder; +import org.citrusframework.openapi.generator.soap.bookservice.request.BookServiceSoapApi; +import org.citrusframework.openapi.testapi.spring.SoapApiReceiveMessageActionParser; +import org.citrusframework.openapi.testapi.spring.SoapApiSendMessageActionParser; +import org.citrusframework.openapi.generator.soap.bookservice.BookService; +import org.citrusframework.openapi.testapi.GeneratedApi; +import org.springframework.beans.factory.xml.NamespaceHandlerSupport; + +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-10-28T13:20:44.612584400+01:00[Europe/Zurich]", comments = "Generator version: 7.5.0") +public class BookServiceNamespaceHandler extends NamespaceHandlerSupport { + + private final OpenApiSpecification openApiSpecification = OpenApiSpecification.from( + BookService.bookServiceApi()); + + @Override + public void init() { + + registerOperationParsers(BookServiceSoapApi.class,"add-book", + BookServiceSoapApi.AddBookSendActionBuilder.class, + BookServiceSoapApi.AddBookReceiveActionBuilder.class); + + registerOperationParsers(BookServiceSoapApi.class,"get-all-books", + BookServiceSoapApi.GetAllBooksSendActionBuilder.class, + BookServiceSoapApi.GetAllBooksReceiveActionBuilder.class); + + registerOperationParsers(BookServiceSoapApi.class,"get-book", + BookServiceSoapApi.GetBookSendActionBuilder.class, + BookServiceSoapApi.GetBookReceiveActionBuilder.class); + } + + private void registerOperationParsers(Class apiClass, String elementName, + Class sendBeanClass, + Class receiveBeanClass) { + + SoapApiSendMessageActionParser sendParser = new SoapApiSendMessageActionParser( + apiClass, + sendBeanClass, + receiveBeanClass, + "bookstore.endpoint"); + registerBeanDefinitionParser("send-"+elementName, sendParser); + + SoapApiReceiveMessageActionParser receiveParser = new SoapApiReceiveMessageActionParser( + apiClass, receiveBeanClass, "bookstore.endpoint"); + registerBeanDefinitionParser("receive-"+elementName, receiveParser); + } +} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml index b68fc8646d..e452117071 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withMultipartTest.xml @@ -13,7 +13,7 @@ http://www.citrusframework.org/citrus-test-schema/extpetstore-api http://www.citrusframework.org/citrus-test-schema/extpetstore-api/extpetstore-api.xsd" > - + diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl index be473dad50..d16857172e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService.wsdl @@ -9,7 +9,6 @@ which can be used to add or retrieve books from a collection. - + b + d + generated-sources-mod diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-additional-properties.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-additional-properties.xml new file mode 100644 index 0000000000..896e16e063 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-additional-properties.xml @@ -0,0 +1,38 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + /base/a/b + otherOption + + + + Minimal + api/test-api.yml + a=b,c=d + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-config.xml new file mode 100644 index 0000000000..fc80fa5f45 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-config.xml @@ -0,0 +1,37 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + b + otherOption + + + + Minimal + api/test-api.yml + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-properties.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-properties.xml new file mode 100644 index 0000000000..68b7486966 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-global-properties.xml @@ -0,0 +1,37 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + true + true + + + + Minimal + api/test-api.yml + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml new file mode 100644 index 0000000000..c3675ca22c --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml @@ -0,0 +1,46 @@ + + 4.0.0 + + full-config + + + + + citrus-test-api-generator-maven-plugin + + + true + true + + + a + otherOption + + + + Minimal + api/test-api.yml + + + b + d + + + + + + + + create-test-api + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/test-classes/SpringMetaFileGeneratorTest/META-INF/spring.handlers b/test-api-generator/citrus-test-api-generator-maven-plugin/test-classes/SpringMetaFileGeneratorTest/META-INF/spring.handlers new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/test-classes/SpringMetaFileGeneratorTest/META-INF/spring.schemas b/test-api-generator/citrus-test-api-generator-maven-plugin/test-classes/SpringMetaFileGeneratorTest/META-INF/spring.schemas new file mode 100644 index 0000000000..e69de29bb2 diff --git a/test-api-generator/citrus-test-api-spring/pom.xml b/test-api-generator/citrus-test-api-spring/pom.xml deleted file mode 100644 index 85766d8441..0000000000 --- a/test-api-generator/citrus-test-api-spring/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - 4.0.0 - - org.citrusframework - citrus - 4.4.0-SNAPSHOT - ../../pom.xml - - - citrus-test-api-spring - Citrus :: Test API Spring - Citrus Test API Spring Integration - jar - - - - org.citrusframework - citrus-spring - ${project.version} - - - org.citrusframework - citrus-test-api-core - ${project.version} - - - diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index 28b98ebc7d..5da0ff0317 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -23,7 +23,6 @@ citrus-test-api-core citrus-test-api-generator-core citrus-test-api-generator-maven-plugin - citrus-test-api-spring From 948fc48afbbe3c30136db68b6d4acb13cf06dd50 Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Sun, 24 Nov 2024 21:11:26 +0100 Subject: [PATCH 34/47] chore: bump maven reactor to 4.5.0-SNAPSHOT --- catalog/citrus-bom/pom.xml | 6 +++--- pom.xml | 4 ++-- test-api-generator/citrus-test-api-core/pom.xml | 2 +- test-api-generator/citrus-test-api-generator-core/pom.xml | 2 +- .../citrus-test-api-generator-maven-plugin/pom.xml | 2 +- test-api-generator/pom.xml | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/catalog/citrus-bom/pom.xml b/catalog/citrus-bom/pom.xml index 050c95bd33..3c801b84b3 100644 --- a/catalog/citrus-bom/pom.xml +++ b/catalog/citrus-bom/pom.xml @@ -241,17 +241,17 @@ org.citrusframework citrus-test-api-core - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT org.citrusframework citrus-test-api-generator-core - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT org.citrusframework citrus-test-api-spring - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT org.citrusframework diff --git a/pom.xml b/pom.xml index a297535259..4bbc872840 100644 --- a/pom.xml +++ b/pom.xml @@ -253,7 +253,7 @@ 4.1.105.Final 4.12.0 7.9.0 - 0.2.6 + 0.2.6 4.7.6 42.7.5 3.17.4 @@ -1028,7 +1028,7 @@ org.openapitools jackson-databind-nullable - ${jackson-databind-nullable} + ${jackson-databind-nullable.version} com.fasterxml.jackson.module diff --git a/test-api-generator/citrus-test-api-core/pom.xml b/test-api-generator/citrus-test-api-core/pom.xml index 1a836fcc26..a0fbc7a1c0 100644 --- a/test-api-generator/citrus-test-api-core/pom.xml +++ b/test-api-generator/citrus-test-api-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index bd80247f48..f2de52ace1 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index fbd2024114..4e7260fb23 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -8,7 +8,7 @@ citrus-test-api-generator org.citrusframework - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index 5da0ff0317..711c2e65e7 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -6,7 +6,7 @@ org.citrusframework citrus - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT ../pom.xml From 6c5b9c2d2114c6b146597f39fa49cdacacb3f2d6 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Mon, 25 Nov 2024 13:45:53 +0100 Subject: [PATCH 35/47] feat: changes on open api feature due to first beta tests --- .../jbang/actions/JBangActionTest.java | 10 +++++ .../citrusframework/jbang/xml/JBangTest.java | 10 +++++ .../citrusframework/jbang/yaml/JBangTest.java | 10 +++++ connectors/citrus-testcontainers/pom.xml | 23 +++++++++++ .../org/citrusframework/util/TestUtils.java | 32 +++++++++++---- .../camel/integration/CamelJBangIT.java | 24 +++++++++-- .../citrusframework/camel/xml/JBangTest.java | 10 +++++ .../citrusframework/camel/yaml/JBangTest.java | 10 +++++ .../groovy/dsl/container/WaitForTest.java | 17 ++++++-- .../citrusframework/testng/TestNGHelper.java | 41 ++++++++++++++++--- .../xml/container/WaitForTest.java | 14 +++++-- .../yaml/container/WaitForTest.java | 13 ++++-- .../citrus-test-api-generator-core/pom.xml | 2 - .../main/resources/java-citrus/api.mustache | 2 +- .../src/test/resources/apis/petstore-v3.yaml | 2 +- .../rest/extpetstore/ExtPetStoreOpenApi.java | 2 +- .../rest/extpetstore/model/Category.java | 2 +- .../extpetstore/model/HistoricalData.java | 2 +- .../rest/extpetstore/model/Pet.java | 2 +- .../rest/extpetstore/model/PetIdentifier.java | 2 +- .../rest/extpetstore/model/Tag.java | 2 +- .../model/VaccinationDocumentResult.java | 2 +- .../rest/extpetstore/request/ExtPetApi.java | 2 +- .../spring/ExtPetStoreBeanConfiguration.java | 2 +- .../spring/ExtPetStoreNamespaceHandler.java | 2 +- .../rest/petstore/PetStoreOpenApi.java | 2 +- .../rest/petstore/model/Address.java | 2 +- .../rest/petstore/model/Category.java | 2 +- .../rest/petstore/model/Customer.java | 2 +- .../rest/petstore/model/ModelApiResponse.java | 2 +- .../rest/petstore/model/Order.java | 2 +- .../expectedgen/rest/petstore/model/Pet.java | 2 +- .../expectedgen/rest/petstore/model/Tag.java | 2 +- .../expectedgen/rest/petstore/model/User.java | 2 +- .../rest/petstore/request/PetApi.java | 2 +- .../rest/petstore/request/StoreApi.java | 2 +- .../rest/petstore/request/UserApi.java | 2 +- .../spring/PetStoreBeanConfiguration.java | 2 +- .../spring/PetStoreNamespaceHandler.java | 2 +- .../request/BookServiceSoapApi.java | 2 +- .../spring/BookServiceBeanConfiguration.java | 2 +- .../spring/BookServiceNamespaceHandler.java | 2 +- .../maven/plugin/TestApiGeneratorMojo.java | 3 +- .../plugin/SpringMetaFileGeneratorTest.java | 3 +- 44 files changed, 221 insertions(+), 59 deletions(-) diff --git a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/actions/JBangActionTest.java b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/actions/JBangActionTest.java index 1a80074d7c..fedf6ff504 100644 --- a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/actions/JBangActionTest.java +++ b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/actions/JBangActionTest.java @@ -21,13 +21,23 @@ import org.citrusframework.jbang.UnitTestSupport; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; +import org.citrusframework.util.TestUtils; import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class JBangActionTest extends UnitTestSupport { private final Resource helloScript = Resources.fromClasspath("org/citrusframework/jbang/hello.java"); + @BeforeClass + public static void beforeEach() { + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + } + @Test public void testScriptOrFile() { JBangAction jbang = new JBangAction.Builder() diff --git a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/xml/JBangTest.java b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/xml/JBangTest.java index 07cc310078..c4fbdc6151 100644 --- a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/xml/JBangTest.java +++ b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/xml/JBangTest.java @@ -19,13 +19,23 @@ import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.jbang.actions.JBangAction; +import org.citrusframework.util.TestUtils; import org.citrusframework.xml.XmlTestLoader; import org.citrusframework.xml.actions.XmlTestActionBuilder; import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class JBangTest extends AbstractXmlActionTest { + @BeforeClass + public static void beforeEach() { + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + } + @Test public void shouldLoadJBangActions() { XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/jbang/xml/jbang-test.xml"); diff --git a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/yaml/JBangTest.java b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/yaml/JBangTest.java index 596e61dc2b..03d272eee1 100644 --- a/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/yaml/JBangTest.java +++ b/connectors/citrus-jbang-connector/src/test/java/org/citrusframework/jbang/yaml/JBangTest.java @@ -19,13 +19,23 @@ import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.jbang.actions.JBangAction; +import org.citrusframework.util.TestUtils; import org.citrusframework.yaml.YamlTestLoader; import org.citrusframework.yaml.actions.YamlTestActionBuilder; import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class JBangTest extends AbstractYamlActionTest { + @BeforeClass + public static void beforeEach() { + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + } + @Test public void shouldLoadJBangActions() { YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/jbang/yaml/jbang-test.yaml"); diff --git a/connectors/citrus-testcontainers/pom.xml b/connectors/citrus-testcontainers/pom.xml index 06150f9b3f..03d0175dfc 100644 --- a/connectors/citrus-testcontainers/pom.xml +++ b/connectors/citrus-testcontainers/pom.xml @@ -13,6 +13,10 @@ citrus-testcontainers Citrus :: Connectors :: Testcontainers + + false + + org.citrusframework @@ -138,4 +142,23 @@ test + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipContainerTests} + + + + org.apache.maven.plugins + maven-failsafe-plugin + + ${skipContainerTests} + + + + diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java index 469d2963fe..8299a0db3d 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/TestUtils.java @@ -16,13 +16,9 @@ package org.citrusframework.util; -import org.citrusframework.CitrusSettings; -import org.citrusframework.Completable; -import org.citrusframework.context.TestContext; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -30,6 +26,12 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import org.citrusframework.CitrusSettings; +import org.citrusframework.Completable; +import org.citrusframework.context.TestContext; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility class for test cases providing several utility @@ -38,6 +40,8 @@ */ public abstract class TestUtils { + public static final String HTTPS_CITRUSFRAMEWORK_ORG = "https://citrusframework.org"; + /** Used to identify waiting task threads pool */ public static final String WAIT_THREAD_PREFIX = "citrus-waiting-"; @@ -137,4 +141,18 @@ private static Thread createWaitingThread(final Runnable runnable, TestContext c } return waitThread; } + + public static boolean isNetworkReachable() { + try { + URL url = new URL(HTTPS_CITRUSFRAMEWORK_ORG); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setConnectTimeout(5000); + connection.setReadTimeout(5000); + int responseCode = connection.getResponseCode(); + return responseCode == HttpURLConnection.HTTP_OK; + } catch (IOException e) { + return false; + } + } } diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java index a039791085..6397cc3b45 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java @@ -16,20 +16,27 @@ package org.citrusframework.camel.integration; +import static org.citrusframework.camel.dsl.CamelSupport.camel; +import static org.citrusframework.container.Catch.Builder.catchException; +import static org.citrusframework.container.FinallySequence.Builder.doFinally; + import org.citrusframework.annotations.CitrusTest; import org.citrusframework.spi.Resources; import org.citrusframework.testng.TestNGCitrusSupport; +import org.citrusframework.util.TestUtils; +import org.testng.SkipException; import org.testng.annotations.Test; -import static org.citrusframework.camel.dsl.CamelSupport.camel; -import static org.citrusframework.container.Catch.Builder.catchException; -import static org.citrusframework.container.FinallySequence.Builder.doFinally; - public class CamelJBangIT extends TestNGCitrusSupport { @Test @CitrusTest(name = "RunIntegration_SourceCode_IT") public void runIntegrationWithSourceCodeIT() { + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + given(doFinally().actions( catchException().actions(camel().jbang().stop("hello")) )); @@ -58,6 +65,15 @@ public void runIntegrationWithSourceCodeIT() { @Test @CitrusTest(name = "RunIntegration_Resource_IT") public void runIntegrationWithResourceIT() { + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + given(doFinally().actions( catchException().actions(camel().jbang().stop("route")) )); diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/JBangTest.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/JBangTest.java index 789ca41cd7..e07645dbba 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/JBangTest.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/xml/JBangTest.java @@ -25,12 +25,22 @@ import org.citrusframework.camel.actions.CamelRunIntegrationAction; import org.citrusframework.camel.actions.CamelStopIntegrationAction; import org.citrusframework.camel.actions.CamelVerifyIntegrationAction; +import org.citrusframework.util.TestUtils; import org.citrusframework.xml.XmlTestLoader; import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class JBangTest extends AbstractXmlActionTest { + @BeforeClass + public static void beforeEach() { + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + } + @Test public void shouldLoadCamelActions() throws Exception { XmlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/camel/xml/camel-jbang-test.xml"); diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/JBangTest.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/JBangTest.java index 53610b08eb..8bcb745d07 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/JBangTest.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/yaml/JBangTest.java @@ -25,12 +25,22 @@ import org.citrusframework.camel.actions.CamelRunIntegrationAction; import org.citrusframework.camel.actions.CamelStopIntegrationAction; import org.citrusframework.camel.actions.CamelVerifyIntegrationAction; +import org.citrusframework.util.TestUtils; import org.citrusframework.yaml.YamlTestLoader; import org.testng.Assert; +import org.testng.SkipException; +import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; public class JBangTest extends AbstractYamlActionTest { + @BeforeClass + public static void beforeEach() { + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); + } + } + @Test public void shouldLoadCamelActions() throws Exception { YamlTestLoader testLoader = createTestLoader("classpath:org/citrusframework/camel/yaml/camel-jbang-test.yaml"); diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java index f47ff42fdb..2deedae134 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java @@ -16,6 +16,8 @@ package org.citrusframework.groovy.dsl.container; +import static org.citrusframework.util.TestUtils.HTTPS_CITRUSFRAMEWORK_ORG; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.EchoAction; @@ -30,7 +32,9 @@ import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageStore; import org.citrusframework.message.MessageStore; +import org.citrusframework.util.TestUtils; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.Test; public class WaitForTest extends AbstractGroovyActionDslTest { @@ -42,7 +46,11 @@ public class WaitForTest extends AbstractGroovyActionDslTest { @Test public void shouldLoadWaitFor() { - String httpUrl = "https://citrusframework.org"; + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because citrus is not reachable. We are probably running behind a proxy."); + } + String filePath = "classpath:org/citrusframework/groovy/test-request-payload.xml"; MessageStore messageStore = new DefaultMessageStore(); @@ -70,11 +78,11 @@ public void shouldLoadWaitFor() { validateWaitAction(action, "10000", "2000", condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); validateWaitAction(action, DEFAULT_WAIT_TIME, DEFAULT_INTERVAL, condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl + "/doesnotexist", "404", "2000"); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG + "/doesnotexist", "404", "2000"); ((HttpCondition)condition).setMethod("GET"); validateWaitAction(action, "3000", DEFAULT_INTERVAL, condition); @@ -143,4 +151,7 @@ private void validateWaitAction(Wait action, String expectedMilliseconds, String Assert.assertEquals(((EchoAction) condition.getAction()).getMessage(), ((EchoAction)((ActionCondition) expectedCondition).getAction()).getMessage()); } } + + + } diff --git a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/TestNGHelper.java b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/TestNGHelper.java index f119dfea34..de2fcd364d 100644 --- a/runtime/citrus-testng/src/main/java/org/citrusframework/testng/TestNGHelper.java +++ b/runtime/citrus-testng/src/main/java/org/citrusframework/testng/TestNGHelper.java @@ -24,7 +24,6 @@ import java.util.Arrays; import java.util.List; import java.util.Set; - import org.citrusframework.CitrusSettings; import org.citrusframework.DefaultTestCase; import org.citrusframework.TestCaseRunner; @@ -45,6 +44,7 @@ import org.slf4j.LoggerFactory; import org.testng.IHookCallBack; import org.testng.ITestResult; +import org.testng.SkipException; public final class TestNGHelper { @@ -71,10 +71,41 @@ private TestNGHelper() { */ public static void invokeTestMethod(Object target, ITestResult testResult, Method method, TestLoader testLoader, TestContext context, int invocationCount) { - Object[] params = TestNGParameterHelper.resolveParameter(target, testResult, method, context, invocationCount); - testLoader.configureTestCase(t -> TestNGParameterHelper.injectTestParameters(method, t, params)); - testLoader.doWithTestCase(t -> ReflectionHelper.invokeMethod(method, target, params)); - testLoader.load(); + + try { + Object[] params = TestNGParameterHelper.resolveParameter(target, testResult, method, + context, invocationCount); + testLoader.configureTestCase( + t -> TestNGParameterHelper.injectTestParameters(method, t, params)); + testLoader.doWithTestCase(t -> ReflectionHelper.invokeMethod(method, target, params)); + testLoader.load(); + } catch (CitrusRuntimeException e) { + SkipException skipException = getCauseOfType(e, SkipException.class); + if (skipException != null) { + throw skipException; + } + + throw e; + } + } + + /** + * Recursively checks if the cause of the given exception matches the target exception. + * + * @param exception The exception to check. + * @param targetCause The exception cause to search for. + * @return true if the target cause is found in the exception chain, false otherwise. + */ + public static T getCauseOfType(Throwable exception, Class targetCause) { + if (exception == null) { + return null; + } + + if (targetCause.isInstance(exception)) { + return targetCause.cast(exception); + } + + return getCauseOfType(exception.getCause(), targetCause); } /** diff --git a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/container/WaitForTest.java b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/container/WaitForTest.java index 40bea3f589..5869454777 100644 --- a/runtime/citrus-xml/src/test/java/org/citrusframework/xml/container/WaitForTest.java +++ b/runtime/citrus-xml/src/test/java/org/citrusframework/xml/container/WaitForTest.java @@ -16,6 +16,8 @@ package org.citrusframework.xml.container; +import static org.citrusframework.util.TestUtils.HTTPS_CITRUSFRAMEWORK_ORG; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.EchoAction; @@ -28,9 +30,11 @@ import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageStore; import org.citrusframework.message.MessageStore; +import org.citrusframework.util.TestUtils; import org.citrusframework.xml.XmlTestLoader; import org.citrusframework.xml.actions.AbstractXmlActionTest; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.Test; public class WaitForTest extends AbstractXmlActionTest { @@ -42,7 +46,11 @@ public class WaitForTest extends AbstractXmlActionTest { @Test public void shouldLoadWaitFor() { - String httpUrl = "https://citrusframework.org"; + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because citrus is not reachable. We are probably running behind a proxy."); + } + String filePath = "classpath:org/citrusframework/xml/test-request-payload.xml"; MessageStore messageStore = new DefaultMessageStore(); @@ -70,11 +78,11 @@ public void shouldLoadWaitFor() { validateWaitAction(action, "10000", "2000", condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); validateWaitAction(action, DEFAULT_WAIT_TIME, DEFAULT_INTERVAL, condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl + "/doesnotexist", "404", "2000"); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG + "/doesnotexist", "404", "2000"); ((HttpCondition)condition).setMethod("GET"); validateWaitAction(action, "3000", DEFAULT_INTERVAL, condition); diff --git a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/container/WaitForTest.java b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/container/WaitForTest.java index 83933741b8..cb758c371d 100644 --- a/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/container/WaitForTest.java +++ b/runtime/citrus-yaml/src/test/java/org/citrusframework/yaml/container/WaitForTest.java @@ -16,6 +16,8 @@ package org.citrusframework.yaml.container; +import static org.citrusframework.util.TestUtils.HTTPS_CITRUSFRAMEWORK_ORG; + import org.citrusframework.TestCase; import org.citrusframework.TestCaseMetaInfo; import org.citrusframework.actions.EchoAction; @@ -28,9 +30,11 @@ import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.DefaultMessageStore; import org.citrusframework.message.MessageStore; +import org.citrusframework.util.TestUtils; import org.citrusframework.yaml.YamlTestLoader; import org.citrusframework.yaml.actions.AbstractYamlActionTest; import org.testng.Assert; +import org.testng.SkipException; import org.testng.annotations.Test; public class WaitForTest extends AbstractYamlActionTest { @@ -42,7 +46,10 @@ public class WaitForTest extends AbstractYamlActionTest { @Test public void shouldLoadWaitFor() { - String httpUrl = "https://citrusframework.org"; + + if (!TestUtils.isNetworkReachable()) { + throw new SkipException("Test skipped because citrus is not reachable. We are probably running behind a proxy."); + } String filePath = "classpath:org/citrusframework/yaml/test-request-payload.xml"; MessageStore messageStore = new DefaultMessageStore(); @@ -70,11 +77,11 @@ public void shouldLoadWaitFor() { validateWaitAction(action, "10000", "2000", condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG, DEFAULT_RESPONSE_CODE, DEFAULT_TIMEOUT); validateWaitAction(action, DEFAULT_WAIT_TIME, DEFAULT_INTERVAL, condition); action = (Wait) result.getTestAction(actionIndex++); - condition = getHttpCondition(httpUrl + "/doesnotexist", "404", "2000"); + condition = getHttpCondition(HTTPS_CITRUSFRAMEWORK_ORG + "/doesnotexist", "404", "2000"); ((HttpCondition)condition).setMethod("GET"); validateWaitAction(action, "3000", DEFAULT_INTERVAL, condition); diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index f2de52ace1..5ea32baa45 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -234,7 +234,6 @@ ${project.basedir}/src/test/resources/apis/petstore-v3.yaml - rootContextPath=/api/v3 org.citrusframework.openapi.generator.rest.petstore org.citrusframework.openapi.generator.rest.petstore.request @@ -252,7 +251,6 @@ ${project.basedir}/src/test/resources/apis/petstore-extended-v3.yaml - rootContextPath=/api/v3/ext org.citrusframework.openapi.generator.rest.extpetstore org.citrusframework.openapi.generator.rest.extpetstore.request diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 758f216a2c..441c05043b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -213,7 +213,7 @@ public class {{classname}} implements GeneratedApi private static final String METHOD = "{{httpMethod}}"; - private static final String ENDPOINT = "{{rootContextPath}}{{path}}"; + private static final String ENDPOINT = "{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}"; private static final String OPERATION_NAME = "{{operationId}}"; {{#hasApiKeyAuth}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml index 6e38ce59fc..8312d0e5a5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-v3.yaml @@ -21,7 +21,7 @@ externalDocs: description: Find out more about Swagger url: http://swagger.io servers: - - url: /api/v3 + - url: http://localhost:9000/api/v3 tags: - name: pet description: Everything about your Pets diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStoreOpenApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStoreOpenApi.java index 7b718ddf18..a170a880f7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStoreOpenApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/ExtPetStoreOpenApi.java @@ -5,6 +5,6 @@ public class ExtPetStoreOpenApi { public static final OpenApiSpecification extPetStoreSpecification = OpenApiSpecification - .from(ExtPetStoreOpenApi.class.getResource("ExtPetStore_openApi.yaml")).withRootContext("/api/v3/ext"); + .from(ExtPetStoreOpenApi.class.getResource("ExtPetStore_openApi.yaml")); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index ab4d304e55..55049b07f8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:19.250811+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index 3eae1cd296..f9e0df6955 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -25,7 +25,7 @@ /** * Additional historical data for a vaccination report, not contained in internal storage. */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class HistoricalData { private LocalDate lastVaccinationDate; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index efa1d0484f..e96c640952 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java index a0d8d01f2b..c9e216c35d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java @@ -24,7 +24,7 @@ /** * PetIdentifier */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetIdentifier { private String _name; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index fa1812d9d0..4a3d8ce7fc 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 429f6c4d71..9718fa1003 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -24,7 +24,7 @@ /** * VaccinationDocumentResult */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class VaccinationDocumentResult { private String documentId; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index 76084a33e5..c3b3a5f146 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -42,7 +42,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.model.VaccinationDocumentResult; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:19.250811+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index d7932a6512..1d2dd76533 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:19.250811+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index 75087dba7b..5525418d45 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -12,7 +12,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:24.834965400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStoreOpenApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStoreOpenApi.java index 4ef8b2f372..5565d7b5e7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStoreOpenApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/PetStoreOpenApi.java @@ -5,6 +5,6 @@ public class PetStoreOpenApi { public static final OpenApiSpecification petStoreSpecification = OpenApiSpecification - .from(PetStoreOpenApi.class.getResource("petStore_openApi.yaml")).withRootContext("/api/v3"); + .from(PetStoreOpenApi.class.getResource("petStore_openApi.yaml")); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index 03ab005413..06800d5d54 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -24,7 +24,7 @@ /** * Address */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:17.563204500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Address { private String street; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index 4a11c5a39b..63614e1e3e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:17.563204500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index 7b97537cc5..c98b31df30 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -28,7 +28,7 @@ /** * Customer */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:17.563204500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Customer { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index debf1914a1..15e666dfee 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -24,7 +24,7 @@ /** * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ModelApiResponse { private Integer code; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index 7121812e9a..9d2db02a4f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -25,7 +25,7 @@ /** * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Order { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index 6c559b7187..564342da9d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index 9ea1673749..d55bbfc147 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index 5f8a707919..c351448931 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -24,7 +24,7 @@ /** * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class User { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index 7b8ff5ddb0..f4a0df5fab 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Pet; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 0cc32fcbf3..1f82bc08ab 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -36,7 +36,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Order; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class StoreApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index 3d95fb5f83..ea7bd796db 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.User; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class UserApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index d0977edc57..41ac4c33c5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -17,7 +17,7 @@ import org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index ab552013cf..acc353b014 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -14,7 +14,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-19T06:57:22.933962900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index 8c03fdf46f..787fac3f6a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:20.169378200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceSoapApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java index 04921c434c..013ba6bad6 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.soap.bookservice.BookServiceOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:20.169378200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java index 79dab026da..4a3c422f8e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java @@ -10,7 +10,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-23T14:15:20.169378200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index 4e82c50f6c..655d0dcba1 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -22,6 +22,7 @@ import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_ENDPOINT; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.API_TYPE; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.PREFIX; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.ROOT_CONTEXT_PATH; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.TARGET_XMLNS_NAMESPACE; import static org.springframework.util.ReflectionUtils.findField; import static org.springframework.util.ReflectionUtils.makeAccessible; @@ -262,7 +263,7 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept properties.addAll(apiConfig.additionalProperties); } apiConfig.additionalProperties = properties; - apiConfig.additionalProperties.add(String.format("%s=%s",CodeGenMojoWrapper.ROOT_CONTEXT_PATH, apiConfig.rootContextPath)); + apiConfig.additionalProperties.add(String.format("%s=%s", ROOT_CONTEXT_PATH, apiConfig.rootContextPath)); } propagateBuildContext(codeGenMojo); diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java index 5288bb40e2..7208ddeae7 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java @@ -13,7 +13,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) @@ -39,7 +38,7 @@ void generateMetaFiles() throws MojoExecutionException { MavenProject mavenProject = mock(); doReturn(new File(userDir)).when(mavenProject).getBasedir(); doReturn(mavenProject).when(testApiGeneratorMojo).getMavenProject(); - doReturn("SpringMetaFileGeneratorTest/META-INF").when(testApiGeneratorMojo).metaInfFolder(); + doReturn("/test-classes/SpringMetaFileGeneratorTest/META-INF").when(testApiGeneratorMojo).metaInfFolder(); ApiConfig apiConfig = new ApiConfig(); apiConfig.setPrefix("PrefixA"); From 6252e9d9fa0a52f36995aa2a778fad482e884713 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Thu, 5 Dec 2024 15:46:08 +0100 Subject: [PATCH 36/47] feat: changes on open api feature due to first beta tests --- .../citrusframework/openapi/AutoFillType.java | 22 ++ .../openapi/OpenApiSettings.java | 32 ++- .../openapi/OpenApiSpecification.java | 20 +- .../OpenApiClientRequestActionBuilder.java | 211 ++++++++++------- .../OpenApiClientResponseActionBuilder.java | 38 ++-- .../OpenApiServerResponseActionBuilder.java | 213 +++++++++++------- .../openapi/model/OasModelHelper.java | 26 +-- .../openapi/model/v3/Oas30ModelHelper.java | 23 +- .../citrusframework/openapi/yaml/OpenApi.java | 21 +- .../openapi/OpenApiSettingsTest.java | 117 ++++++---- .../openapi/OpenApiSpecificationTest.java | 4 - ...penApiClientRequestMessageBuilderTest.java | 53 ++++- .../openapi/groovy/OpenApiClientTest.java | 3 +- .../openapi/integration/OpenApiClientIT.java | 5 + .../openapi/integration/OpenApiServerIT.java | 25 ++ .../random/RandomObjectGeneratorTest.java | 1 + .../openapi/xml/OpenApiClientTest.java | 3 +- .../openapi/yaml/OpenApiClientTest.java | 3 +- ...e-derivation-for-message-builder-test.json | 8 + .../openapi/ping/ping-api.yaml | 2 +- .../common/DefaultTestLoader.java | 20 +- .../citrusframework/util/SystemProvider.java | 4 + .../camel/integration/CamelJBangIT.java | 4 - .../http/message/HttpMessage.java | 4 + pom.xml | 2 +- .../groovy/dsl/container/WaitForTest.java | 3 - .../junit/jupiter/CitrusExtension.java | 29 ++- .../testapi/ApiActionBuilderCustomizer.java | 4 +- .../testapi/GeneratedApiOperationInfo.java | 6 + .../testapi/OpenApiParameterFormatter.java | 8 +- .../openapi/testapi/ParameterStyle.java | 1 + .../RestApiSendMessageActionBuilder.java | 14 +- .../SoapApiReceiveMessageActionBuilder.java | 8 +- .../SoapApiSendMessageActionBuilder.java | 19 +- .../RestApiReceiveMessageActionParser.java | 9 + .../RestApiSendMessageActionParser.java | 16 +- .../SoapApiSendMessageActionParser.java | 26 ++- .../main/resources/java-citrus/api.mustache | 70 +++--- .../resources/java-citrus/api_soap.mustache | 41 +++- .../openapi/generator/GeneratedRestApiIT.java | 9 +- .../openapi/generator/GeneratedSoapApiIT.java | 5 + .../rest/extpetstore/model/Category.java | 2 +- .../extpetstore/model/HistoricalData.java | 2 +- .../rest/extpetstore/model/Pet.java | 2 +- .../rest/extpetstore/model/PetIdentifier.java | 2 +- .../rest/extpetstore/model/Tag.java | 2 +- .../model/VaccinationDocumentResult.java | 2 +- .../rest/extpetstore/request/ExtPetApi.java | 162 ++++++------- .../spring/ExtPetStoreBeanConfiguration.java | 2 +- .../spring/ExtPetStoreNamespaceHandler.java | 2 +- .../rest/petstore/model/Address.java | 2 +- .../rest/petstore/model/Category.java | 2 +- .../rest/petstore/model/Customer.java | 2 +- .../rest/petstore/model/ModelApiResponse.java | 2 +- .../rest/petstore/model/Order.java | 2 +- .../expectedgen/rest/petstore/model/Pet.java | 2 +- .../expectedgen/rest/petstore/model/Tag.java | 2 +- .../expectedgen/rest/petstore/model/User.java | 2 +- .../rest/petstore/request/PetApi.java | 34 +-- .../rest/petstore/request/StoreApi.java | 18 +- .../rest/petstore/request/UserApi.java | 30 +-- .../spring/PetStoreBeanConfiguration.java | 2 +- .../spring/PetStoreNamespaceHandler.java | 2 +- .../request/BookServiceSoapApi.java | 123 ++++++++-- .../spring/BookServiceBeanConfiguration.java | 2 +- .../spring/BookServiceNamespaceHandler.java | 2 +- ...withNestedReceiveDefaultClientSoapTest.xml | 75 ++++++ .../maven/plugin/TestApiGeneratorMojo.java | 198 +++++++++++----- .../TestApiGeneratorMojoIntegrationTest.java | 19 +- .../pom-soap-from-wsdl-config.xml | 33 +++ .../src/test/resources/api/BookDatatypes.xsd | 67 ++++++ .../src/test/resources/api/BookService.wsdl | 113 ++++++++++ test-api-generator/pom.xml | 4 - 73 files changed, 1436 insertions(+), 612 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/AutoFillType.java create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveDefaultClientSoapTest.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-from-wsdl-config.xml create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookDatatypes.xsd create mode 100644 test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookService.wsdl diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/AutoFillType.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/AutoFillType.java new file mode 100644 index 0000000000..a842e00cdc --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/AutoFillType.java @@ -0,0 +1,22 @@ +package org.citrusframework.openapi; + +/** + * Enum representing different types of auto-fill behavior for OpenAPI parameters/body. + * This enum defines how missing or required parameters/body should be auto-filled. + */ +public enum AutoFillType { + /** + * No auto-fill will be performed for any parameters/body. + */ + NONE, + + /** + * Auto-fill will be applied only to required parameters/body that are missing. + */ + REQUIRED, + + /** + * Auto-fill will be applied to all parameters/body, whether they are required or not. + */ + ALL +} diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java index 6422a03a63..ab4dab92f5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java @@ -28,9 +28,6 @@ public class OpenApiSettings { public static final String GENERATE_OPTIONAL_FIELDS_PROPERTY = "citrus.openapi.generate.optional.fields"; public static final String GENERATE_OPTIONAL_FIELDS_ENV = "CITRUS_OPENAPI_GENERATE_OPTIONAL_FIELDS"; - public static final String VALIDATE_OPTIONAL_FIELDS_PROPERTY = "citrus.openapi.validate.optional.fields"; - public static final String VALIDATE_OPTIONAL_FIELDS_ENV = "CITRUS_OPENAPI_VALIDATE_OPTIONAL_FIELDS"; - public static final String REQUEST_VALIDATION_ENABLED_PROPERTY = "citrus.openapi.validation.enabled.request"; public static final String REQUEST_VALIDATION_ENABLED_ENV = "CITRUS_OPENAPI_VALIDATION_DISABLE_REQUEST"; @@ -40,6 +37,12 @@ public class OpenApiSettings { public static final String NEGLECT_OPEN_API_BASE_PATH_PROPERTY = "citrus.openapi.neglect.base.path"; public static final String NEGLECT_OPEN_API_BASE_PATH_ENV = "CITRUS_OPENAPI_NEGLECT_BASE_PATH"; + public static final String REQUEST_AUTO_FILL_RANDOM_VALUES = "citrus.openapi.request.fill.random.values"; + public static final String REQUEST_AUTO_FILL_RANDOM_VALUES_ENV = "CITRUS_OPENAPI_REQUEST_FILL_RANDOM_VALUES"; + + public static final String RESPONSE_AUTO_FILL_RANDOM_VALUES = "citrus.openapi.response.fill.random.values"; + public static final String RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV = "CITRUS_OPENAPI_RESPONSE_FILL_RANDOM_VALUES"; + private OpenApiSettings() { // static access only } @@ -49,11 +52,6 @@ public static boolean isGenerateOptionalFieldsGlobally() { System.getenv(GENERATE_OPTIONAL_FIELDS_ENV) : "true")); } - public static boolean isValidateOptionalFieldsGlobally() { - return parseBoolean(System.getProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) != null ? - System.getenv(VALIDATE_OPTIONAL_FIELDS_ENV) : "true")); - } - public static boolean isRequestValidationEnabledGlobally() { return parseBoolean(System.getProperty( REQUEST_VALIDATION_ENABLED_PROPERTY, System.getenv(REQUEST_VALIDATION_ENABLED_ENV) != null ? @@ -71,4 +69,22 @@ public static boolean isNeglectBasePathGlobally() { NEGLECT_OPEN_API_BASE_PATH_PROPERTY, System.getenv(NEGLECT_OPEN_API_BASE_PATH_ENV) != null ? System.getenv(NEGLECT_OPEN_API_BASE_PATH_ENV) : "false")); } + + /** + * The default AutoFillType for request is set to REQUIRED to support backwards compatibility. + */ + public static AutoFillType getRequestAutoFillRandomValues() { + return AutoFillType.valueOf(System.getProperty( + REQUEST_AUTO_FILL_RANDOM_VALUES, System.getenv(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV) != null ? + System.getenv(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV) : AutoFillType.REQUIRED.name())); + } + + /** + * The default AutoFillType for response is set to REQUIRED to support backwards compatibility. + */ + public static AutoFillType getResponseAutoFillRandomValues() { + return AutoFillType.valueOf(System.getProperty( + RESPONSE_AUTO_FILL_RANDOM_VALUES, System.getenv(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV) != null ? + System.getenv(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV) : AutoFillType.REQUIRED.name())); + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index 68cecb0a17..c89a9beae2 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -24,7 +24,6 @@ import static org.citrusframework.openapi.OpenApiSettings.isNeglectBasePathGlobally; import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; -import static org.citrusframework.openapi.OpenApiSettings.isValidateOptionalFieldsGlobally; import static org.citrusframework.openapi.model.OasModelHelper.getBasePath; import static org.citrusframework.util.StringUtils.appendSegmentToUrlPath; import static org.citrusframework.util.StringUtils.hasText; @@ -142,7 +141,6 @@ public class OpenApiSpecification { private OasDocument openApiDoc; private OpenApiValidationContext openApiValidationContext; private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); - private boolean validateOptionalFields = isValidateOptionalFieldsGlobally(); /** * Flag to indicate, whether request validation is enabled on api level. Api level overrules @@ -254,7 +252,7 @@ public static OpenApiSpecification fromString(String openApi) { } public String getUid() { - return uid; + return uid; } public synchronized OasDocument getOpenApiDoc(TestContext context) { @@ -470,14 +468,6 @@ public void setGenerateOptionalFields(boolean generateOptionalFields) { this.generateOptionalFields = generateOptionalFields; } - public boolean isValidateOptionalFields() { - return validateOptionalFields; - } - - public void setValidateOptionalFields(boolean validateOptionalFields) { - this.validateOptionalFields = validateOptionalFields; - } - public String getRootContextPath() { return rootContextPath; } @@ -536,11 +526,15 @@ public Optional getOperation(String operationId, TestConte // This is ugly, but we need not make sure that the openApiDoc is initialized, which might // happen, when instance is created with org.citrusframework.openapi.OpenApiSpecification.from(java.lang.String) + initOpenApiDoc(context); + + return Optional.ofNullable(operationIdToOperationPathAdapter.get(operationId)); + } + + public void initOpenApiDoc(TestContext context) { if (openApiDoc == null) { getOpenApiDoc(context); } - - return Optional.ofNullable(operationIdToOperationPathAdapter.get(operationId)); } public OpenApiSpecification withRootContext(String rootContextPath) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index e0d09443dd..a14a48e931 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -16,9 +16,17 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.openapi.OpenApiMessageType.REQUEST; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.citrusframework.util.StringUtils.isNotEmpty; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasParameter; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.List; +import java.util.Locale; +import java.util.Optional; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; @@ -27,6 +35,8 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.message.HttpMessageBuilder; import org.citrusframework.message.Message; +import org.citrusframework.openapi.AutoFillType; +import org.citrusframework.openapi.OpenApiSettings; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; @@ -35,15 +45,6 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import java.util.List; -import java.util.Locale; -import java.util.Optional; - -import static org.citrusframework.openapi.OpenApiMessageType.REQUEST; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; -import static org.citrusframework.util.StringUtils.isNotEmpty; - /** * @since 4.1 */ @@ -54,31 +55,42 @@ public class OpenApiClientRequestActionBuilder extends HttpClientRequestActionBu private OpenApiOperationToMessageHeadersProcessor openApiOperationToMessageHeadersProcessor; private boolean schemaValidation = true; + /** * Default constructor initializes http request message builder. */ - public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, String operationId) { + public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, + String operationId) { this(new HttpMessage(), openApiSpec, operationId); } public OpenApiClientRequestActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { - this(openApiSpec, new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), httpMessage, operationId); + OpenApiSpecificationSource openApiSpec, + String operationId) { + this(openApiSpec, + new OpenApiClientRequestMessageBuilder(httpMessage, openApiSpec, operationId), + httpMessage, operationId); } public OpenApiClientRequestActionBuilder(OpenApiSpecificationSource openApiSpec, - OpenApiClientRequestMessageBuilder messageBuilder, - HttpMessage message, - String operationId) { + OpenApiClientRequestMessageBuilder messageBuilder, + HttpMessage message, + String operationId) { super(messageBuilder, message); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; } + public OpenApiClientRequestActionBuilder autoFill(AutoFillType autoFill) { + ((OpenApiClientRequestMessageBuilder) this.messageBuilderSupport.getMessageBuilder()).autoFill( + autoFill); + return this; + } + @Override public SendMessageAction doBuild() { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + referenceResolver); // Honor default enablement of schema validation OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); @@ -86,8 +98,10 @@ public SendMessageAction doBuild() { schemaValidation = openApiValidationContext.isRequestValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { - openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, REQUEST); + if (schemaValidation && !messageProcessors.contains( + openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor( + openApiSpecification, operationId, REQUEST); process(openApiOperationToMessageHeadersProcessor); } @@ -115,25 +129,35 @@ public static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilde private final String operationId; + private AutoFillType autoFill = OpenApiSettings.getRequestAutoFillRandomValues(); + public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpec, - String operationId) { + OpenApiSpecificationSource openApiSpec, + String operationId) { super(httpMessage); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; } + public OpenApiClientRequestMessageBuilder autoFill(AutoFillType autoFill) { + this.autoFill = autoFill; + return this; + } + @Override public Message build(TestContext context, String messageType) { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + context.getReferenceResolver()); + openApiSpecification.initOpenApiDoc(context); openApiSpecification.getOperation(operationId, context) - .ifPresentOrElse(operationPathAdapter -> - buildMessageFromOperation(openApiSpecification, operationPathAdapter, context), - () -> { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpecification.getSpecUrl())); - }); + .ifPresentOrElse(operationPathAdapter -> + buildMessageFromOperation(openApiSpecification, operationPathAdapter, + context), + () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); context.setVariable(openApiSpecification.getUid(), openApiSpecification); return super.build(context, messageType); @@ -148,39 +172,43 @@ public Object buildMessagePayload(TestContext context, String messageType) { } private void buildMessageFromOperation(OpenApiSpecification openApiSpecification, - OperationPathAdapter operationPathAdapter, - TestContext context) { + OperationPathAdapter operationPathAdapter, + TestContext context) { OasOperation operation = operationPathAdapter.operation(); String path = operationPathAdapter.apiPath(); - HttpMethod method = HttpMethod.valueOf(operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); + HttpMethod method = HttpMethod.valueOf( + operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); if (operation.parameters != null) { - setMissingRequiredHeadersToRandomValues(openApiSpecification, context, operation); - setMissingRequiredQueryParametersToRandomValues(context, operation); + setMissingHeadersToRandomValues(openApiSpecification, context, operation); + setMissingQueryParametersToRandomValues(openApiSpecification, context, operation); } - setMissingRequiredBodyToRandomValue(openApiSpecification, context, operation); + setMissingBodyToRandomValue(openApiSpecification, context, operation); String randomizedPath = getMessage().getPath() != null ? getMessage().getPath() : path; if (operation.parameters != null) { List pathParams = operation.parameters.stream() - .filter(p -> "path".equals(p.in)).toList(); + .filter(p -> "path".equals(p.in)).toList(); for (OasParameter parameter : pathParams) { String parameterValue; - String pathParameterValue = getDefinedPathParameter(context, parameter.getName()); + String pathParameterValue = getDefinedPathParameter(context, + parameter.getName()); if (isNotEmpty(pathParameterValue)) { parameterValue = "\\" + pathParameterValue; } else { parameterValue = createRandomValueExpression( - (OasSchema) parameter.schema); + (OasSchema) parameter.schema); } - randomizedPath = randomizedPath.replaceAll("\\{" + parameter.getName() + "}", parameterValue); + randomizedPath = randomizedPath.replaceAll("\\{" + parameter.getName() + "}", + parameterValue); } } OasModelHelper.getRequestContentType(operation) - .ifPresent(contentType -> getMessage().setHeader(HttpHeaders.CONTENT_TYPE, contentType)); + .ifPresent( + contentType -> getMessage().setHeader(HttpHeaders.CONTENT_TYPE, contentType)); getMessage().path(randomizedPath); getMessage().method(method); @@ -193,59 +221,84 @@ protected String getDefinedPathParameter(TestContext context, String name) { return null; } - private void setMissingRequiredBodyToRandomValue(OpenApiSpecification openApiSpecification, TestContext context, OasOperation operation) { - if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String payloadString && payloadString.isEmpty())) { - Optional body = OasModelHelper.getRequestBodySchema(openApiSpecification.getOpenApiDoc(context), operation); - body.ifPresent(oasSchema -> getMessage().setPayload(createOutboundPayload(oasSchema, openApiSpecification))); + private void setMissingBodyToRandomValue(OpenApiSpecification openApiSpecification, + TestContext context, OasOperation operation) { + if (getMessage().getPayload() == null || ( + getMessage().getPayload() instanceof String payloadString + && payloadString.isEmpty())) { + Optional body = OasModelHelper.getRequestBodySchema( + openApiSpecification.getOpenApiDoc(context), operation); + + body.ifPresent(oasSchema -> { + + if (autoFill == AutoFillType.ALL || autoFill == AutoFillType.REQUIRED) { + getMessage().setPayload( + createOutboundPayload(oasSchema, openApiSpecification)); + } + }); } } /** * Creates all required query parameters, if they have not already been specified. */ - private void setMissingRequiredQueryParametersToRandomValues(TestContext context, OasOperation operation) { + private void setMissingQueryParametersToRandomValues( + OpenApiSpecification openApiSpecification, TestContext context, + OasOperation operation) { operation.parameters.stream() - .filter(param -> "query".equals(param.in)) - .filter(param -> Boolean.TRUE.equals(param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> { - // If not already configured explicitly, create a random value - if (!getMessage().getQueryParams().containsKey(param.getName())) { - try { - getMessage().queryParam(param.getName(), - createRandomValueExpression(param.getName(), - (OasSchema) param.schema, - context)); - } catch (Exception e) { - // Note that exploded object query parameter representation for example, cannot properly - // be randomized. - logger.warn("Unable to set missing required query parameter to random value: {}", param); - } - } - }); + .filter(param -> "query".equals(param.in)) + // Not configured manually + .filter(param -> !getMessage().getQueryParams().containsKey(param.getName())) + // Only targeted parameters + .filter(param -> autoFill == AutoFillType.ALL || (autoFill == AutoFillType.REQUIRED + && Boolean.TRUE.equals(param.required))) + .forEach(param -> { + Object queryParameterValue = context.getVariables() + .get(param.getName()); + if (queryParameterValue == null) { + queryParameterValue = createRandomValueExpression(param.getName(), + (OasSchema) param.schema, openApiSpecification, + context); + } + try { + getMessage().queryParam(param.getName(), queryParameterValue.toString()); + } catch (Exception e) { + // Note that exploded object query parameter representation for example, cannot properly + // be randomized. + logger.warn( + "Unable to set missing required query parameter to random value: {}", + param); + } + }); } /** * Creates all required headers, if they have not already been specified. */ - private void setMissingRequiredHeadersToRandomValues(OpenApiSpecification openApiSpecification, - TestContext context, OasOperation operation) { + private void setMissingHeadersToRandomValues(OpenApiSpecification openApiSpecification, + TestContext context, OasOperation operation) { List configuredHeaders = getHeaderBuilders() - .stream() - .flatMap(b -> b.builderHeaders(context).keySet().stream()) - .toList(); + .stream() + .flatMap(b -> b.builderHeaders(context).keySet().stream()) + .toList(); operation.parameters.stream() - .filter(param -> "header".equals(param.in)) - .filter(param -> Boolean.TRUE.equals(param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> { - // If not already configured explicitly, create a random value - if (getMessage().getHeader(param.getName()) == null - && !configuredHeaders.contains(param.getName())) { - getMessage().setHeader(param.getName(), - createRandomValueExpression(param.getName(), - (OasSchema) param.schema, - openApiSpecification, context)); - } - }); + .filter(param -> "header".equals(param.in)) + // Not configured manually + .filter(param -> getMessage().getHeader(param.getName()) == null + && !configuredHeaders.contains(param.getName())) + // Only targeted parameters + .filter(param -> autoFill == AutoFillType.ALL || (autoFill == AutoFillType.REQUIRED + && Boolean.TRUE.equals(param.required))) + .forEach(param -> { + Object headerValue = context.getVariables() + .get(param.getName()); + if (headerValue == null) { + headerValue = createRandomValueExpression(param.getName(), + (OasSchema) param.schema, + openApiSpecification, context); + } + getMessage().setHeader(param.getName(), headerValue); + }); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java index 71d186915e..1fcf16e964 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java @@ -16,10 +16,21 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.message.MessageType.JSON; +import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; +import static org.citrusframework.openapi.model.OasModelHelper.resolveSchema; +import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; import jakarta.annotation.Nullable; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.ReceiveMessageAction; import org.citrusframework.context.TestContext; @@ -31,23 +42,10 @@ import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OasModelHelper; import org.citrusframework.openapi.model.OperationPathAdapter; -import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiMessageValidationContext; +import org.citrusframework.openapi.validation.OpenApiOperationToMessageHeadersProcessor; import org.citrusframework.openapi.validation.OpenApiValidationContext; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.regex.Pattern; - -import static org.citrusframework.message.MessageType.JSON; -import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; -import static org.citrusframework.openapi.model.OasModelHelper.resolveSchema; -import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; /** * @since 4.1 @@ -80,6 +78,14 @@ public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec super(messageBuilder, message); this.openApiSpecificationSource = openApiSpec; this.operationId = operationId; + + // Set json as default instead of xml. This is most common for rest. + // TODO: we need to specify the type on message builder support level. So actually we need to + // 1. determine the response from operationId and statusCode + // 2. If status code is missing, take the most probable as response as determined by OasModelHelper.getResponseForRandomGeneration + // 3. Determine message type from response and set it on builder support + // If we do not set a proper type here, validations may not even be executed. E.g. simple json message validation. + this.getMessageBuilderSupport().type(JSON); } public static void fillMessageTypeFromResponse(OpenApiSpecification openApiSpecification, @@ -95,9 +101,7 @@ public static void fillMessageTypeFromResponse(OpenApiSpecification openApiSpeci OasSchema resolvedSchema = resolveSchema(openApiSpecification.getOpenApiDoc(null), oasSchema); if (OasModelHelper.isObjectType(resolvedSchema) || OasModelHelper.isObjectArrayType(resolvedSchema)) { Collection responseTypes = OasModelHelper.getResponseTypes(operation,response); - if (responseTypes.contains(MediaType.APPLICATION_JSON_VALUE)) { - httpMessage.setHeader(HttpHeaders.CONTENT_TYPE, - MediaType.APPLICATION_JSON_VALUE); + if (responseTypes.contains(APPLICATION_JSON_VALUE)) { httpMessage.setType(JSON); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index 64f2b3bb6b..e3b8f9ba25 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -16,9 +16,28 @@ package org.citrusframework.openapi.actions; +import static java.lang.Integer.parseInt; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasResponse; import io.apicurio.datamodels.openapi.models.OasSchema; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.regex.Pattern; import org.citrusframework.CitrusSettings; import org.citrusframework.actions.SendMessageAction; import org.citrusframework.context.TestContext; @@ -30,6 +49,8 @@ import org.citrusframework.message.Message; import org.citrusframework.message.MessageHeaderBuilder; import org.citrusframework.message.builder.DefaultHeaderBuilder; +import org.citrusframework.openapi.AutoFillType; +import org.citrusframework.openapi.OpenApiSettings; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.model.OasAdapter; import org.citrusframework.openapi.model.OasModelHelper; @@ -38,26 +59,6 @@ import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.springframework.http.HttpStatus; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.regex.Pattern; - -import static java.lang.Integer.parseInt; -import static java.util.Collections.singletonList; -import static java.util.Collections.singletonMap; -import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; -import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; - /** * @since 4.1 */ @@ -72,25 +73,32 @@ public class OpenApiServerResponseActionBuilder extends HttpServerResponseAction * Default constructor initializes http response message builder. */ public OpenApiServerResponseActionBuilder(OpenApiSpecificationSource openApiSpecificationSource, - String operationId, - String statusCode, - String accept) { + String operationId, + String statusCode, + String accept) { this(new HttpMessage(), openApiSpecificationSource, operationId, statusCode, accept); } public OpenApiServerResponseActionBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, - String statusCode, - String accept) { - super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpecificationSource, operationId, statusCode, accept), httpMessage); + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode, + String accept) { + super(new OpenApiServerResponseMessageBuilder(httpMessage, openApiSpecificationSource, + operationId, statusCode, accept), httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; } + public OpenApiServerResponseActionBuilder autoFill(AutoFillType autoFill) { + ((OpenApiServerResponseMessageBuilder)this.messageBuilderSupport.getMessageBuilder()).autoFill(autoFill); + return this; + } + @Override public SendMessageAction doBuild() { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(referenceResolver); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + referenceResolver); // Honor default enablement of schema validation OpenApiValidationContext openApiValidationContext = openApiSpecification.getOpenApiValidationContext(); @@ -98,8 +106,10 @@ public SendMessageAction doBuild() { schemaValidation = openApiValidationContext.isResponseValidationEnabled(); } - if (schemaValidation && !messageProcessors.contains(openApiOperationToMessageHeadersProcessor)) { - openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor(openApiSpecification, operationId, RESPONSE); + if (schemaValidation && !messageProcessors.contains( + openApiOperationToMessageHeadersProcessor)) { + openApiOperationToMessageHeadersProcessor = new OpenApiOperationToMessageHeadersProcessor( + openApiSpecification, operationId, RESPONSE); process(openApiOperationToMessageHeadersProcessor); } @@ -121,8 +131,9 @@ protected HttpMessageBuilderSupport createMessageBuilderSupport() { return messageBuilderSupport; } - public OpenApiServerResponseActionBuilder enableRandomGeneration(boolean enable) { - ((OpenApiServerResponseMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).enableRandomGeneration(enable); + public OpenApiServerResponseActionBuilder enableRandomGeneration(AutoFillType autoFillType) { + ((OpenApiServerResponseMessageBuilder) getMessageBuilderSupport().getMessageBuilder()).autoFill( + autoFillType); return this; } @@ -134,13 +145,14 @@ private static class OpenApiServerResponseMessageBuilder extends HttpMessageBuil private final String operationId; private final String statusCode; private final String accept; - private boolean randomGenerationEnabled = true; + + private AutoFillType autoFillType = OpenApiSettings.getResponseAutoFillRandomValues(); public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, - OpenApiSpecificationSource openApiSpecificationSource, - String operationId, - String statusCode, - String accept) { + OpenApiSpecificationSource openApiSpecificationSource, + String operationId, + String statusCode, + String accept) { super(httpMessage); this.openApiSpecificationSource = openApiSpecificationSource; this.operationId = operationId; @@ -148,14 +160,16 @@ public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage, this.accept = accept; } - public OpenApiServerResponseMessageBuilder enableRandomGeneration(boolean enable) { - this.randomGenerationEnabled = enable; + // TODO: properly document autofill feature + public OpenApiServerResponseMessageBuilder autoFill(AutoFillType autoFillType) { + this.autoFillType = autoFillType; return this; } @Override public Message build(TestContext context, String messageType) { - OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(context.getReferenceResolver()); + OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve( + context.getReferenceResolver()); if (STATUS_CODE_PATTERN.matcher(statusCode).matches()) { getMessage().status(HttpStatus.valueOf(parseInt(statusCode))); } else { @@ -165,15 +179,13 @@ public Message build(TestContext context, String messageType) { List initialHeaderBuilders = new ArrayList<>(getHeaderBuilders()); getHeaderBuilders().clear(); - if (randomGenerationEnabled) { - openApiSpecification.getOperation(operationId, context) - .ifPresentOrElse(operationPathAdapter -> - fillRandomData(openApiSpecification, operationPathAdapter, context), () -> { - throw new CitrusRuntimeException( - "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( - operationId, openApiSpecification.getSpecUrl())); - }); - } + openApiSpecification.getOperation(operationId, context) + .ifPresentOrElse(operationPathAdapter -> + fillRandomData(openApiSpecification, operationPathAdapter, context), () -> { + throw new CitrusRuntimeException( + "Unable to locate operation with id '%s' in OpenAPI specification %s".formatted( + operationId, openApiSpecification.getSpecUrl())); + }); // Initial header builder need to be prepended, so that they can overwrite randomly generated headers. getHeaderBuilders().addAll(initialHeaderBuilders); @@ -181,55 +193,74 @@ public Message build(TestContext context, String messageType) { return super.build(context, messageType); } - private void fillRandomData(OpenApiSpecification openApiSpecification, OperationPathAdapter operationPathAdapter, TestContext context) { + private void fillRandomData(OpenApiSpecification openApiSpecification, + OperationPathAdapter operationPathAdapter, TestContext context) { if (operationPathAdapter.operation().responses != null) { buildResponse(context, openApiSpecification, operationPathAdapter.operation()); } } - private void buildResponse(TestContext context, OpenApiSpecification openApiSpecification, OasOperation operation) { + private void buildResponse(TestContext context, OpenApiSpecification openApiSpecification, + OasOperation operation) { Optional responseForRandomGeneration = OasModelHelper.getResponseForRandomGeneration( - openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); + openApiSpecification.getOpenApiDoc(context), operation, statusCode, null); if (responseForRandomGeneration.isPresent()) { - buildRandomHeaders(context, openApiSpecification, responseForRandomGeneration.get()); - buildRandomPayload(openApiSpecification, operation, responseForRandomGeneration.get()); + OasResponse oasResponse = responseForRandomGeneration.get(); + + if (autoFillType != AutoFillType.NONE) { + buildRandomHeaders(context, openApiSpecification, oasResponse); + buildRandomPayload(openApiSpecification, operation, oasResponse); + } + + // Always override existing headers by context variables. This way we can also override random values. + Map headers = OasModelHelper.getHeaders(oasResponse); + headers.entrySet().stream() + .filter(entry -> context.getVariables().containsKey(entry.getKey())) + .forEach((entry -> addHeaderBuilder( + new DefaultHeaderBuilder(singletonMap(entry.getKey(), + CitrusSettings.VARIABLE_PREFIX + entry.getKey() + + CitrusSettings.VARIABLE_SUFFIX))))); + } } - private void buildRandomHeaders(TestContext context, OpenApiSpecification openApiSpecification, OasResponse response) { + private void buildRandomHeaders(TestContext context, + OpenApiSpecification openApiSpecification, OasResponse response) { + if (autoFillType == AutoFillType.NONE) { + return; + } + Set filteredHeaders = new HashSet<>(getMessage().getHeaders().keySet()); - Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains(entry.getKey()); - - Map requiredHeaders = OasModelHelper.getRequiredHeaders(response); - requiredHeaders.entrySet().stream() - .filter(filteredHeadersPredicate) - .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( - singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), - entry.getValue(), - openApiSpecification, - context)))) - ); - - // Also filter the required headers, as they have already been processed - filteredHeaders.addAll(requiredHeaders.keySet()); - - Map headers = OasModelHelper.getHeaders(response); - headers.entrySet().stream() - .filter(filteredHeadersPredicate) - .filter(entry -> context.getVariables().containsKey(entry.getKey())) - .forEach((entry -> addHeaderBuilder( - new DefaultHeaderBuilder(singletonMap(entry.getKey(), - CitrusSettings.VARIABLE_PREFIX + entry.getKey() - + CitrusSettings.VARIABLE_SUFFIX))))); + Predicate> filteredHeadersPredicate = entry -> !filteredHeaders.contains( + entry.getKey()); + + Map headersToFill; + if (openApiSpecification.isGenerateOptionalFields()) { + headersToFill = OasModelHelper.getHeaders(response); + } else { + headersToFill = OasModelHelper.getRequiredHeaders(response); + } + + headersToFill.entrySet().stream() + .filter(filteredHeadersPredicate) + .forEach(entry -> addHeaderBuilder(new DefaultHeaderBuilder( + singletonMap(entry.getKey(), createRandomValueExpression(entry.getKey(), + entry.getValue(), + openApiSpecification, + context)))) + ); + } - private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOperation operation, OasResponse response) { + private void buildRandomPayload(OpenApiSpecification openApiSpecification, + OasOperation operation, OasResponse response) { Optional> schemaForMediaTypeOptional; if (statusCode.startsWith("2")) { // if status code is good, and we have an accept, try to get the media type. Note that only json and plain text can be generated randomly. - schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, accept != null ? singletonList(accept) : null); + schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, + accept != null ? singletonList(accept) : null); } else { // In the bad case, we cannot expect, that the accept type is the type which we must generate. // We request the type supported by the response and the random generator (json and plain text). @@ -238,30 +269,38 @@ private void buildRandomPayload(OpenApiSpecification openApiSpecification, OasOp if (schemaForMediaTypeOptional.isPresent()) { OasAdapter schemaForMediaType = schemaForMediaTypeOptional.get(); - if (getMessage().getPayload() == null || (getMessage().getPayload() instanceof String string && string.isEmpty())) { + if (getMessage().getPayload() == null || ( + getMessage().getPayload() instanceof String string && string.isEmpty())) { createRandomPayload(getMessage(), openApiSpecification, schemaForMediaType); } // If we have a schema and a media type and the content type has not yet been set, do it. // If schema is null, we do not set the content type, as there is no content. - if (!getMessage().getHeaders().containsKey(HttpMessageHeaders.HTTP_CONTENT_TYPE) && schemaForMediaType.adapted() != null && schemaForMediaType.node() != null) { - addHeaderBuilder(new DefaultHeaderBuilder(singletonMap(HttpMessageHeaders.HTTP_CONTENT_TYPE, schemaForMediaType.adapted()))); + if (!getMessage().getHeaders().containsKey(HttpMessageHeaders.HTTP_CONTENT_TYPE) + && schemaForMediaType.adapted() != null && schemaForMediaType.node() != null) { + addHeaderBuilder(new DefaultHeaderBuilder( + singletonMap(HttpMessageHeaders.HTTP_CONTENT_TYPE, + schemaForMediaType.adapted()))); } } } - private void createRandomPayload(HttpMessage message, OpenApiSpecification openApiSpecification, OasAdapter schemaForMediaType) { + private void createRandomPayload(HttpMessage message, + OpenApiSpecification openApiSpecification, + OasAdapter schemaForMediaType) { if (schemaForMediaType.node() == null) { // No schema means no payload, no type message.setPayload(null); } else { if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { // Schema but plain text - message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); + message.setPayload( + createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.adapted())) { // Json Schema - message.setPayload(createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); + message.setPayload( + createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index 9e95ad0950..99dba6a7c4 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -16,6 +16,14 @@ package org.citrusframework.openapi.model; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; +import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; + import io.apicurio.datamodels.combined.visitors.CombinedVisitorAdapter; import io.apicurio.datamodels.openapi.io.OasDataModelWriter; import io.apicurio.datamodels.openapi.models.OasDocument; @@ -44,10 +52,6 @@ import io.apicurio.datamodels.openapi.v3.visitors.Oas30Traverser; import io.apicurio.datamodels.openapi.visitors.OasTraverser; import jakarta.annotation.Nullable; -import org.citrusframework.openapi.model.v2.Oas20ModelHelper; -import org.citrusframework.openapi.model.v3.Oas30ModelHelper; -import org.citrusframework.util.StringUtils; - import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -59,14 +63,9 @@ import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Predicate; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; -import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; +import org.citrusframework.openapi.model.v2.Oas20ModelHelper; +import org.citrusframework.openapi.model.v3.Oas30ModelHelper; +import org.citrusframework.util.StringUtils; public final class OasModelHelper { @@ -299,7 +298,7 @@ public static Optional getResponseForRandomGeneration(OasDocument o operation.responses); // For a given status code, do not fall back - if (statusCode != null) { + if (StringUtils.isNotEmpty(statusCode)) { return Optional.ofNullable(responseMap.get(statusCode)); } @@ -605,4 +604,5 @@ public static String toJson(OasDocument openApiDoc) { oasTraverser.traverse(openApiDoc); return writer.getResult().toString(); } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index b0796ce5b0..2d80b2dbec 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -16,6 +16,13 @@ package org.citrusframework.openapi.model.v3; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toMap; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; +import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; + import io.apicurio.datamodels.core.models.common.Server; import io.apicurio.datamodels.core.models.common.ServerVariable; import io.apicurio.datamodels.openapi.models.OasSchema; @@ -26,11 +33,6 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30RequestBody; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import org.citrusframework.openapi.model.OasAdapter; -import org.citrusframework.openapi.model.OasModelHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.net.MalformedURLException; import java.net.URI; import java.util.Arrays; @@ -40,13 +42,10 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.emptySet; -import static java.util.stream.Collectors.toMap; -import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE; -import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; +import org.citrusframework.openapi.model.OasAdapter; +import org.citrusframework.openapi.model.OasModelHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public final class Oas30ModelHelper { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java index dc2f59e92b..eb8bab0b29 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/yaml/OpenApi.java @@ -24,6 +24,8 @@ import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.actions.HttpServerResponseActionBuilder; import org.citrusframework.http.message.HttpMessageHeaders; +import org.citrusframework.openapi.AutoFillType; +import org.citrusframework.openapi.OpenApiSettings; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiClientActionBuilder; import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; @@ -78,6 +80,7 @@ public void setSendRequest(ClientRequest request) { requestBuilder.name("openapi:send-request"); requestBuilder.description(description); + requestBuilder.autoFill(request.autoFill); send = new Send(requestBuilder) { @Override @@ -236,8 +239,8 @@ public void setReferenceResolver(ReferenceResolver referenceResolver) { * @return */ private OpenApiClientActionBuilder asClientBuilder() { - if (builder instanceof OpenApiClientActionBuilder) { - return (OpenApiClientActionBuilder) builder; + if (builder instanceof OpenApiClientActionBuilder openApiClientActionBuilder) { + return openApiClientActionBuilder; } throw new CitrusRuntimeException(String.format("Failed to convert '%s' to openapi client action builder", @@ -250,8 +253,8 @@ private OpenApiClientActionBuilder asClientBuilder() { * @return */ private OpenApiServerActionBuilder asServerBuilder() { - if (builder instanceof OpenApiServerActionBuilder) { - return (OpenApiServerActionBuilder) builder; + if (builder instanceof OpenApiServerActionBuilder openApiServerActionBuilder) { + return openApiServerActionBuilder; } throw new CitrusRuntimeException(String.format("Failed to convert '%s' to openapi server action builder", @@ -263,6 +266,8 @@ public static class ClientRequest { protected String uri; protected Boolean fork; + protected AutoFillType autoFill = OpenApiSettings.getRequestAutoFillRandomValues(); + protected Message.Extract extract; public String getOperation() { @@ -296,6 +301,14 @@ public Message.Extract getExtract() { public void setExtract(Message.Extract extract) { this.extract = extract; } + + public AutoFillType getAutoFill() { + return autoFill; + } + + public void setAutoFill(AutoFillType autoFill) { + this.autoFill = autoFill; + } } public static class ServerRequest { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java index dd09b7c7ab..038739dc77 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -16,38 +16,43 @@ package org.citrusframework.openapi; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; - import static org.citrusframework.openapi.OpenApiSettings.GENERATE_OPTIONAL_FIELDS_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.NEGLECT_OPEN_API_BASE_PATH_ENV; import static org.citrusframework.openapi.OpenApiSettings.NEGLECT_OPEN_API_BASE_PATH_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.REQUEST_AUTO_FILL_RANDOM_VALUES; +import static org.citrusframework.openapi.OpenApiSettings.REQUEST_AUTO_FILL_RANDOM_VALUES_ENV; import static org.citrusframework.openapi.OpenApiSettings.REQUEST_VALIDATION_ENABLED_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_AUTO_FILL_RANDOM_VALUES; +import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV; import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_VALIDATION_ENABLED_PROPERTY; -import static org.citrusframework.openapi.OpenApiSettings.VALIDATE_OPTIONAL_FIELDS_ENV; -import static org.citrusframework.openapi.OpenApiSettings.VALIDATE_OPTIONAL_FIELDS_PROPERTY; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import uk.org.webcompere.systemstubs.environment.EnvironmentVariables; + public class OpenApiSettingsTest { private static final boolean REQUEST_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isRequestValidationEnabledGlobally(); private static final boolean RESPONSE_VALIDATION_ENABLED_GLOBALLY = OpenApiSettings.isResponseValidationEnabledGlobally(); - private static final boolean VALIDATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isValidateOptionalFieldsGlobally(); private static final boolean GENERATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY = OpenApiSettings.isGenerateOptionalFieldsGlobally(); - private static final boolean NEGLECT_BASE_PATH_GLOBALLY = OpenApiSettings.isNeglectBasePathGlobally() - ; + private static final AutoFillType REQUEST_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY = OpenApiSettings.getRequestAutoFillRandomValues(); + private static final AutoFillType RESPONSE_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY = OpenApiSettings.getResponseAutoFillRandomValues(); + private static final boolean NEGLECT_BASE_PATH_GLOBALLY = OpenApiSettings.isNeglectBasePathGlobally(); + private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @BeforeMethod public void beforeMethod() { System.clearProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY); - System.clearProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY); System.clearProperty(REQUEST_VALIDATION_ENABLED_PROPERTY); System.clearProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY); System.clearProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY); + System.clearProperty(REQUEST_AUTO_FILL_RANDOM_VALUES); + System.clearProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES); } @AfterMethod @@ -60,12 +65,6 @@ public void afterMethod() throws Exception { System.setProperty(GENERATE_OPTIONAL_FIELDS_PROPERTY, "true"); } - if (!VALIDATE_OPTIONAL_FIELDS_ENABLED_GLOBALLY) { - System.clearProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY); - } else { - System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "true"); - } - if (!REQUEST_VALIDATION_ENABLED_GLOBALLY) { System.clearProperty(REQUEST_VALIDATION_ENABLED_PROPERTY); } else { @@ -83,6 +82,11 @@ public void afterMethod() throws Exception { } else { System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "true"); } + + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, + RESPONSE_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY.toString()); + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, + REQUEST_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY.toString()); } @Test @@ -185,69 +189,92 @@ public void testGenerateOptionalFieldsEnabledByDefault() { } @Test - public void testValidateOptionalFieldsEnabledByProperty() throws Exception { + public void testNeglectBasePathEnabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "true"); + assertTrue(OpenApiSettings.isNeglectBasePathGlobally()); + } + + @Test + public void testNeglectBasePathDisabledByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "false"); + assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); + } + + @Test + public void testNeglectBasePathDisabledByEnvVar() throws Exception { + environmentVariables.set(NEGLECT_OPEN_API_BASE_PATH_ENV, "false"); environmentVariables.setup(); - System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "true"); - assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); } @Test - public void testValidateOptionalFieldsDisabledByProperty() throws Exception { + public void testNeglectBasePathEnabledByEnvVar() throws Exception { + environmentVariables.set(NEGLECT_OPEN_API_BASE_PATH_ENV, "true"); environmentVariables.setup(); - System.setProperty(VALIDATE_OPTIONAL_FIELDS_PROPERTY, "false"); - assertFalse(OpenApiSettings.isValidateOptionalFieldsGlobally()); + assertTrue(OpenApiSettings.isNeglectBasePathGlobally()); } @Test - public void testValidateOptionalFieldsEnabledByEnvVar() throws Exception { - environmentVariables.set(VALIDATE_OPTIONAL_FIELDS_ENV, "true"); + public void testNeglectBasePathDisabledByDefault() { + assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); + } + + @Test + public void testRequestAutoFillRandomValuesAllByProperty() throws Exception { environmentVariables.setup(); - assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, "ALL"); + assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.ALL); } @Test - public void testValidateOptionalFieldsDisabledByEnvVar() throws Exception { - environmentVariables.set(VALIDATE_OPTIONAL_FIELDS_ENV, "false"); + public void testRequestAutoFillRandomValuesNoneByProperty() throws Exception { environmentVariables.setup(); - assertFalse(OpenApiSettings.isValidateOptionalFieldsGlobally()); + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, "NONE"); + assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.NONE); } @Test - public void testValidateOptionalFieldsEnabledByDefault() { - assertTrue(OpenApiSettings.isValidateOptionalFieldsGlobally()); + public void testRequestAutoFillRandomValuesAllByEnvVar() throws Exception { + environmentVariables.set(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV, "ALL"); + environmentVariables.setup(); + assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.ALL); } @Test - public void testNeglectBasePathEnabledByProperty() throws Exception { + public void testRequestAutoFillRandomValuesNoneByEnvVar() throws Exception { + environmentVariables.set(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV, "NONE"); environmentVariables.setup(); - System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "true"); - assertTrue(OpenApiSettings.isNeglectBasePathGlobally()); + assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.NONE); } @Test - public void testNeglectBasePathDisabledByProperty() throws Exception { + public void testResponseAutoFillRandomValuesAllByProperty() throws Exception { environmentVariables.setup(); - System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "false"); - assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, "ALL"); + assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.ALL); } @Test - public void testNeglectBasePathDisabledByEnvVar() throws Exception { - environmentVariables.set(NEGLECT_OPEN_API_BASE_PATH_ENV, "false"); + public void testResponseAutoFillRandomValuesNoneByProperty() throws Exception { environmentVariables.setup(); - assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, "NONE"); + assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.NONE); } @Test - public void testNeglectBasePathEnabledByEnvVar() throws Exception { - environmentVariables.set(NEGLECT_OPEN_API_BASE_PATH_ENV, "true"); + public void testResponseAutoFillRandomValuesAllByEnvVar() throws Exception { + environmentVariables.set(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV, "ALL"); environmentVariables.setup(); - assertTrue(OpenApiSettings.isNeglectBasePathGlobally()); + assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.ALL); } @Test - public void testNeglectBasePathDisabledByDefault() { - assertFalse(OpenApiSettings.isNeglectBasePathGlobally()); + public void testResponseAutoFillRandomValuesNoneByEnvVar() throws Exception { + environmentVariables.set(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV, "NONE"); + environmentVariables.setup(); + assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.NONE); } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index 1a75cb7d29..10f93afabc 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -381,16 +381,12 @@ public void shouldSetRootContextPathNeglectingBasePathAndReinitialize() { @Test public void shouldSeAndProvideProperties() { - openApiSpecification.setValidateOptionalFields(true); openApiSpecification.setGenerateOptionalFields(true); - assertTrue(openApiSpecification.isValidateOptionalFields()); assertTrue(openApiSpecification.isGenerateOptionalFields()); - openApiSpecification.setValidateOptionalFields(false); openApiSpecification.setGenerateOptionalFields(false); - assertFalse(openApiSpecification.isValidateOptionalFields()); assertFalse(openApiSpecification.isGenerateOptionalFields()); } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java index 1de662ca01..fea4f6c06c 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java @@ -3,6 +3,7 @@ import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; +import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.spi.Resources; import org.testng.Assert; @@ -16,11 +17,12 @@ public class OpenApiClientRequestMessageBuilderTest { Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json")); @Test - public void shouldAddRandomDataForOperation() { + public void shouldAddRandomDataForOperationWhenAutoFillAll() { Message message = openapi() .specification(petstoreSpec) .client() .send("addPet") // operationId + .autoFill(AutoFillType.ALL) .build() .getMessageBuilder() .build(new TestContext(), ""); @@ -31,8 +33,53 @@ public void shouldAddRandomDataForOperation() { Assert.assertNotNull(payload); Assert.assertTrue(payload instanceof String); // test header - Object header = httpMessage.getHeader("X-SAMPLE-HEADER"); - Assert.assertNotNull(header); + Assert.assertNotNull(httpMessage.getHeader("X-SAMPLE-HEADER")); + Assert.assertNotNull(httpMessage.getQueryParams().get("sample-param")); + Assert.assertNotNull(httpMessage.getQueryParams().get("non-required-sample-param")); + } + + @Test + public void shouldAddRandomDataForOperationWhenAutoFillRequired() { + Message message = openapi() + .specification(petstoreSpec) + .client() + .send("addPet") // operationId + .autoFill(AutoFillType.REQUIRED) + .build() + .getMessageBuilder() + .build(new TestContext(), ""); + Assert.assertTrue(message instanceof HttpMessage); + HttpMessage httpMessage = (HttpMessage) message; + // test payload + Object payload = httpMessage.getPayload(); + Assert.assertNotNull(payload); + Assert.assertTrue(payload instanceof String); + // test header + Assert.assertNotNull(httpMessage.getHeader("X-SAMPLE-HEADER")); + Assert.assertNotNull(httpMessage.getQueryParams().get("sample-param")); + Assert.assertNull(httpMessage.getQueryParams().get("non-required-sample-param")); + } + + @Test + public void shouldNotAddRandomDataForOperationWhenAutoFillNone() { + Message message = openapi() + .specification(petstoreSpec) + .client() + .send("addPet") // operationId + .autoFill(AutoFillType.NONE) + .build() + .getMessageBuilder() + .build(new TestContext(), ""); + Assert.assertTrue(message instanceof HttpMessage); + HttpMessage httpMessage = (HttpMessage) message; + // test payload + Object payload = httpMessage.getPayload(); + Assert.assertNotNull(payload); + Assert.assertTrue(payload instanceof String); + // test header + Assert.assertNull(httpMessage.getHeader("X-SAMPLE-HEADER")); + Assert.assertNull(httpMessage.getQueryParams().get("sample-param")); + Assert.assertNull(httpMessage.getQueryParams().get("non-required-sample-param")); } @Test diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index 811e29d354..7ce3343f5b 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -188,12 +188,11 @@ public void shouldLoadOpenApiClientActions() { httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); assertNotNull(httpMessageBuilder); - assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 4L); assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); assertNull(receiveMessageAction.getEndpoint()); assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index 9d99bfd231..c11171e9c8 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -34,6 +34,7 @@ import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.message.MessageType; +import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; @@ -74,6 +75,7 @@ public void shouldExecuteGetPetById() { when(openapi(petstoreSpec) .client(httpClient) .send("getPetById") + .autoFill(AutoFillType.ALL) .message() .fork(true)); @@ -105,6 +107,7 @@ public void shouldFailOnMissingNameInResponse() { when(openapi(petstoreSpec) .client(httpClient) .send("getPetById") + .autoFill(AutoFillType.ALL) .message() .fork(true)); @@ -180,6 +183,7 @@ public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { when(openapi(petstoreSpec) .client(httpClient) .send("getPetById") + .autoFill(AutoFillType.ALL) .message() .fork(true)); @@ -210,6 +214,7 @@ public void shouldProperlyExecuteGetAndAddPetFromRepository() { when(openapi(petstoreSpec) .client(httpClient) .send("addPet") + .autoFill(AutoFillType.ALL) .fork(true)); then(http().server(httpServer) diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 39573aaa0a..89831f15a2 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -23,6 +23,7 @@ import org.citrusframework.http.client.HttpClientBuilder; import org.citrusframework.http.server.HttpServer; import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiRepository; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; @@ -283,6 +284,30 @@ public void shouldFailOnMissingNameInResponse() { assertThrows(TestCaseFailedException.class, () -> then(sendMessageActionBuilder)); } + @CitrusTest + public void shouldFailOnMissingPayload() { + variable("petId", "1001"); + + when(http() + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); + + then(openapi("petstore-v3") + .server(httpServer) + .receive("getPetById")); + + OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi("petstore-v3") + .server(httpServer) + .send("getPetById", HttpStatus.OK) + .autoFill(AutoFillType.NONE); + + assertThrows(TestCaseFailedException.class, () -> then(sendMessageActionBuilder)); + } + @CitrusTest public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { variable("petId", "xxx"); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java index 86849b3464..b77ec6d8fb 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/random/RandomObjectGeneratorTest.java @@ -132,4 +132,5 @@ public void testGenerateObjectWithRecursion() { verify(randomModelBuilderSpy, never()).object(any()); } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index b63194d6d7..06478846a5 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -191,12 +191,11 @@ public void shouldLoadOpenApiClientActions() throws IOException { httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 4L); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index c8441826c6..00961c3202 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -185,12 +185,11 @@ public void shouldLoadOpenApiClientActions() { httpMessageBuilder = ((HttpMessageBuilder) receiveMessageAction.getMessageBuilder()); Assert.assertNotNull(httpMessageBuilder); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 5L); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().size(), 4L); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_STATUS_CODE), 200); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REASON_PHRASE), "OK"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(receiveMessageAction.getEndpoint()); Assert.assertEquals(receiveMessageAction.getEndpointUri(), "httpClient"); Assert.assertEquals(receiveMessageAction.getMessageProcessors().size(), 1); diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json index a3d3953ce1..f965f09a33 100644 --- a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json @@ -49,6 +49,14 @@ "schema": { "type": "string" } + }, + { + "name": "non-required-sample-param", + "required": false, + "in": "query", + "schema": { + "type": "string" + } } ], "tags": [ diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml index 29bda14fb2..4d694e28e1 100644 --- a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/ping/ping-api.yaml @@ -175,7 +175,7 @@ components: properties: type: type: string - enum: [ MultiplesType ] + enum: [ MultipleOfType ] manyPi: type: number format: double diff --git a/core/citrus-base/src/main/java/org/citrusframework/common/DefaultTestLoader.java b/core/citrus-base/src/main/java/org/citrusframework/common/DefaultTestLoader.java index 248e836dd6..690dfa5762 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/common/DefaultTestLoader.java +++ b/core/citrus-base/src/main/java/org/citrusframework/common/DefaultTestLoader.java @@ -16,10 +16,11 @@ package org.citrusframework.common; +import static org.citrusframework.TestResult.failed; + import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; - import org.citrusframework.Citrus; import org.citrusframework.CitrusContext; import org.citrusframework.DefaultTestCase; @@ -32,8 +33,6 @@ import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.TestCaseFailedException; -import static org.citrusframework.TestResult.failed; - /** * Default test loader implementation takes case on test names/packages and initializes the test runner if applicable. * Also loads the test case and provides it to registered test handlers. This way a test case can be loaded from different sources @@ -102,6 +101,11 @@ public final void load() { // This kind of exception indicates that the error has already been handled. Just throw and end test run. throw e; } catch (Exception | Error e) { + + if (e instanceof RuntimeException runtimeException && isSkipException(runtimeException)) { + throw runtimeException; + } + if (testCase == null) { testCase = runner.getTestCase(); } @@ -113,6 +117,16 @@ public final void load() { } } + /** + * Return true if the throwable is considered a skip exception that must be passed up to the + * testing framework in order to report that this test was skipped. + * + * Sublasses may override according to the framework + */ + protected boolean isSkipException(Throwable e) { + return false; + } + /** * Subclasses are supposed to overwrite this method on order to add logic how to load the test case (e.g. from XML, Json, YAML). */ diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/SystemProvider.java b/core/citrus-base/src/main/java/org/citrusframework/util/SystemProvider.java index 73483d824f..c8713a53ab 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/SystemProvider.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/SystemProvider.java @@ -29,4 +29,8 @@ public Optional getEnv(String envVarName) { public Optional getProperty(String propertyName) { return ofNullable(System.getProperty(propertyName)); } + + public void setProperty(String propertyName, String propertyValue) { + System.setProperty(propertyName, propertyValue); + } } diff --git a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java index 6397cc3b45..778fca3b0f 100644 --- a/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java +++ b/endpoints/citrus-camel/src/test/java/org/citrusframework/camel/integration/CamelJBangIT.java @@ -70,10 +70,6 @@ public void runIntegrationWithResourceIT() { throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); } - if (!TestUtils.isNetworkReachable()) { - throw new SkipException("Test skipped because network is not reachable. We are probably running behind a proxy and JBang download is not possible."); - } - given(doFinally().actions( catchException().actions(camel().jbang().stop("route")) )); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java index 9add503998..2c9fc6d1f3 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java @@ -84,6 +84,10 @@ public HttpMessage(final Message message) { public HttpMessage(final Message message, boolean forceCitrusHeaderUpdate) { super(message, forceCitrusHeaderUpdate); copyCookies(message); + + if (message instanceof HttpMessage httpMessage) { + queryParams.putAll(httpMessage.queryParams); + } } /** diff --git a/pom.xml b/pom.xml index 4bbc872840..65d546a50f 100644 --- a/pom.xml +++ b/pom.xml @@ -194,7 +194,7 @@ 1.10.15 4.9.0 1.1.27 - 2.41.0 + 2.44.1 1.8.0 3.27.2 4.2.2 diff --git a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java index 2deedae134..fdfc564c5f 100644 --- a/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java +++ b/runtime/citrus-groovy/src/test/java/org/citrusframework/groovy/dsl/container/WaitForTest.java @@ -151,7 +151,4 @@ private void validateWaitAction(Wait action, String expectedMilliseconds, String Assert.assertEquals(((EchoAction) condition.getAction()).getMessage(), ((EchoAction)((ActionCondition) expectedCondition).getAction()).getMessage()); } } - - - } diff --git a/runtime/citrus-junit5/src/main/java/org/citrusframework/junit/jupiter/CitrusExtension.java b/runtime/citrus-junit5/src/main/java/org/citrusframework/junit/jupiter/CitrusExtension.java index f32a95d7a3..7b89af2568 100644 --- a/runtime/citrus-junit5/src/main/java/org/citrusframework/junit/jupiter/CitrusExtension.java +++ b/runtime/citrus-junit5/src/main/java/org/citrusframework/junit/jupiter/CitrusExtension.java @@ -16,6 +16,17 @@ package org.citrusframework.junit.jupiter; +import static org.citrusframework.annotations.CitrusAnnotations.injectCitrusFramework; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getBaseKey; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getCitrus; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestCase; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestContext; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestLoader; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestRunner; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.requiresCitrus; +import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.setCitrus; + +import java.lang.reflect.Method; import org.citrusframework.Citrus; import org.citrusframework.CitrusContext; import org.citrusframework.CitrusInstanceManager; @@ -37,18 +48,7 @@ import org.junit.jupiter.api.extension.ReflectiveInvocationContext; import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; import org.junit.jupiter.api.extension.TestInstancePostProcessor; - -import java.lang.reflect.Method; - -import static org.citrusframework.annotations.CitrusAnnotations.injectCitrusFramework; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getBaseKey; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getCitrus; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestCase; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestContext; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestLoader; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.getTestRunner; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.requiresCitrus; -import static org.citrusframework.junit.jupiter.CitrusExtensionHelper.setCitrus; +import org.opentest4j.TestAbortedException; /** * JUnit5 extension adding {@link TestCaseRunner} support as well as Citrus annotation based resource injection @@ -77,6 +77,11 @@ public class CitrusExtension implements BeforeAllCallback, InvocationInterceptor public static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(CitrusExtension.class); private static void failTestCaseIfNotDoneYet(ExtensionContext extensionContext, Throwable throwable) { + + if (throwable instanceof TestAbortedException) { + return; + } + var testCase = getTestCase(extensionContext); var testResult = testCase.getTestResult(); diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java index 31b400d50c..534317aff3 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ApiActionBuilderCustomizer.java @@ -25,9 +25,9 @@ */ public interface ApiActionBuilderCustomizer { - default > void customizeRequestBuilder(GeneratedApi generatedApi, T builder) { + default > void customizeRequestBuilder(GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { } - default > void customizeResponseBuilder(GeneratedApi generatedApi, T builder) { + default > void customizeResponseBuilder(GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { } } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiOperationInfo.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiOperationInfo.java index 11cf1e36c0..c234611e89 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiOperationInfo.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/GeneratedApiOperationInfo.java @@ -23,6 +23,12 @@ */ public interface GeneratedApiOperationInfo { + /** + * Retrieves the {@link GeneratedApi} which owns this operation. + * @return + */ + GeneratedApi getGeneratedApi(); + /** * Retrieves the name of the OpenAPI operation. * diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java index 126816e5bb..9a4f2d3b9e 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/OpenApiParameterFormatter.java @@ -40,6 +40,7 @@ import static java.util.Collections.singletonList; import static java.util.stream.Collectors.joining; import static org.citrusframework.openapi.testapi.ParameterStyle.DEEPOBJECT; +import static org.citrusframework.openapi.testapi.ParameterStyle.NONE; class OpenApiParameterFormatter { @@ -62,6 +63,11 @@ static String formatArray(String parameterName, boolean explode, boolean isObject) { List values = toList(parameterValue, isObject); + + if (NONE.equals(parameterStyle)) { + return parameterName + "="+ (parameterValue != null ? parameterValue.toString() : null); + } + if (DEEPOBJECT.equals(parameterStyle)) { return formatDeepObject(parameterName, values); } @@ -100,7 +106,7 @@ private static FormatParameters determineFormatParameters(String parameterName, case MATRIX -> matrixFormatParameters(parameterName, explode, isObject); case LABEL -> labelFormatParameters(explode); case FORM -> formFormatParameters(parameterName, explode, isObject); - case SIMPLE, DEEPOBJECT -> DEFAULT_FORMAT_PARAMETERS; + case NONE, SIMPLE, DEEPOBJECT -> DEFAULT_FORMAT_PARAMETERS; }; } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java index c5dc997d73..a74e1131b6 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/ParameterStyle.java @@ -17,6 +17,7 @@ package org.citrusframework.openapi.testapi; public enum ParameterStyle { + NONE, SIMPLE, LABEL, MATRIX, diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java index c3209b9745..f8d2d86963 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java @@ -17,6 +17,7 @@ package org.citrusframework.openapi.testapi; import static java.lang.String.format; +import static org.citrusframework.openapi.testapi.OpenApiParameterFormatter.formatArray; import static org.citrusframework.openapi.util.OpenApiUtils.createFullPathOperationIdentifier; import static org.citrusframework.util.FileUtils.getDefaultCharset; import static org.citrusframework.util.StringUtils.isEmpty; @@ -35,6 +36,7 @@ import org.citrusframework.http.actions.HttpClientRequestActionBuilder; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; +import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder; import org.citrusframework.openapi.actions.OpenApiSpecificationSource; @@ -86,8 +88,6 @@ public RestApiSendMessageActionBuilder(GeneratedApi generatedApi, this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); - - httpMessage.path(path); name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), operationName)); @@ -139,7 +139,7 @@ protected void queryParameter(final String name, Object value, ParameterStyle pa return; } - String formatted = OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject); + String formatted = formatArray(name, value, parameterStyle, explode, isObject); String[] queryParamValues = formatted.split("&"); for (String queryParamValue : queryParamValues) { String[] keyValue = queryParamValue.split("="); @@ -160,7 +160,7 @@ protected void headerParameter(String name, Object value, ParameterStyle paramet return; } - headerParameter(name, OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject)); + headerParameter(name, formatArray(name, value, parameterStyle, explode, isObject)); } protected void cookieParameter(String name, Object value) { @@ -176,7 +176,7 @@ protected void cookieParameter(String name, Object value, ParameterStyle paramet return; } - String formatted = OpenApiParameterFormatter.formatArray(name, value, parameterStyle, explode, isObject); + String formatted = formatArray(name, value, parameterStyle, explode, isObject); String[] keyValue = formatted.split("="); // URL Encoding is mandatory especially in the case of multiple values, as multiple values @@ -261,6 +261,8 @@ public TestApiClientRequestMessageBuilder(HttpMessage httpMessage, OpenApiSpecificationSource openApiSpec, String operationId) { super(httpMessage, openApiSpec, operationId); + // Disable autofill by default, as the api enforces required parameters. + autoFill(AutoFillType.NONE); } private static void encodeArrayStyleCookies(HttpMessage message) { @@ -287,7 +289,7 @@ protected String getDefinedPathParameter(TestContext context, String name) { ParameterData parameterData = pathParameters.get(name); String formatted = name; if (parameterData != null) { - formatted = OpenApiParameterFormatter.formatArray(name, parameterData.value, parameterData.parameterStyle, + formatted = formatArray(name, parameterData.value, parameterData.parameterStyle, parameterData.explode, parameterData.isObject); } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java index 7215c19bc4..d466e562c9 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiReceiveMessageActionBuilder.java @@ -36,7 +36,7 @@ public SoapApiReceiveMessageActionBuilder(GeneratedApi generatedApi, String soap endpoint(generatedApi.getEndpoint()); - name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), soapAction)); + name(format("receive-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(), soapAction)); } public GeneratedApi getGeneratedApi() { @@ -49,6 +49,12 @@ public List getCustomizers() { @Override public ReceiveSoapMessageAction doBuild() { + + // If no endpoint was set explicitly, use the default endpoint given by api + if (getEndpoint() == null && getEndpointUri() == null) { + endpoint(generatedApi.getEndpoint()); + } + return new ReceiveSoapMessageAction(this); } } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java index bc231527ad..c3cdc19539 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/SoapApiSendMessageActionBuilder.java @@ -16,11 +16,11 @@ package org.citrusframework.openapi.testapi; -import org.citrusframework.ws.actions.SendSoapMessageAction.Builder; +import static java.lang.String.format; import java.util.List; - -import static java.lang.String.format; +import org.citrusframework.ws.actions.SendSoapMessageAction; +import org.citrusframework.ws.actions.SendSoapMessageAction.Builder; public class SoapApiSendMessageActionBuilder extends Builder { @@ -34,7 +34,7 @@ public SoapApiSendMessageActionBuilder(GeneratedApi generatedApi, String soapAct this.generatedApi = generatedApi; this.customizers = generatedApi.getCustomizers(); - endpoint(generatedApi.getEndpoint()); + getMessageBuilderSupport().soapAction(soapAction); name(format("send-%s:%s", generatedApi.getClass().getSimpleName().toLowerCase(),soapAction)); } @@ -46,4 +46,15 @@ public GeneratedApi getGeneratedApi() { public List getCustomizers() { return customizers; } + + @Override + public SendSoapMessageAction doBuild() { + + // If no endpoint was set explicitly, use the default endpoint given by api + if (getEndpoint() == null && getEndpointUri() == null) { + endpoint(generatedApi.getEndpoint()); + } + + return super.doBuild(); + } } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java index 43444bf947..fe0a9e83b4 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiReceiveMessageActionParser.java @@ -39,12 +39,14 @@ import org.springframework.beans.factory.xml.ParserContext; import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatusCode; +import org.w3c.dom.Attr; import org.w3c.dom.Element; import java.util.List; import static java.lang.Integer.parseInt; import static org.citrusframework.openapi.validation.OpenApiMessageValidationContext.Builder.openApi; +import static org.citrusframework.util.StringUtils.hasText; import static org.springframework.beans.factory.support.BeanDefinitionBuilder.genericBeanDefinition; /** @@ -121,6 +123,13 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); setDefaultEndpoint(beanDefinitionBuilder); + // By default, the type is xml. This not a common case in rest, which is why we switch to json here, + // if no explicit type is specified. + Attr type = element.getAttributeNode("type"); + if (type == null) { + beanDefinitionBuilder.addPropertyValue("messageType", "json"); + } + return beanDefinitionBuilder; } diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java index 5f109456ab..9353672ca9 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java @@ -168,7 +168,7 @@ private BeanDefinitionBuilder createTestApiActionBuilder(Element element, private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, Element receive, ParserContext parserContext, - BeanDefinitionBuilder beanDefinitionBuilder) { + BeanDefinitionBuilder sendActionBeanDefinitionBuilder) { Class> containerClass = createSequenceContainer( fork); @@ -176,13 +176,23 @@ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, BeanDefinitionBuilder sequenceBuilder = genericBeanDefinition(containerClass); RestApiReceiveMessageActionParser receiveApiResponseActionParser = getRestApiReceiveMessageActionParser( - beanDefinitionBuilder); + sendActionBeanDefinitionBuilder); BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse(receive, parserContext); + // Nested elements do not have reasonable names. + String sendName = (String) sendActionBeanDefinitionBuilder.getBeanDefinition().getPropertyValues() + .get("name"); + if (sendName != null) { + String receiveName = sendName.replace(":send", ":receive"); + if (!sendName.equals(receiveName)) { + receiveResponseBeanDefinition.getPropertyValues().add("name", receiveName); + } + } + ManagedList actions = new ManagedList<>(); - actions.add(beanDefinitionBuilder.getBeanDefinition()); + actions.add(sendActionBeanDefinitionBuilder.getBeanDefinition()); actions.add(receiveResponseBeanDefinition); sequenceBuilder.addPropertyValue("actions", actions); diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java index ebf8a31c8d..cd982a260f 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/SoapApiSendMessageActionParser.java @@ -66,6 +66,18 @@ public SoapApiSendMessageActionParser( this.defaultEndpointName = defaultEndpointName; } + @Override + public BeanDefinition parse(Element element, ParserContext parserContext) { + BeanDefinition beanDefinition = super.parse(element, parserContext); + Element receive = getChildElementByTagName(element, "receive"); + if (receive != null) { + boolean fork = parseBoolean(element.getAttribute("fork")); + return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, beanDefinition); + } + + return beanDefinition; + } + @Override public BeanDefinitionBuilder parseComponent(Element element, ParserContext parserContext) { BeanDefinitionBuilder beanDefinitionBuilder = super.parseComponent(element, parserContext); @@ -73,12 +85,6 @@ public BeanDefinitionBuilder parseComponent(Element element, ParserContext parse BeanDefinitionBuilder actionBuilder = createTestApiActionBuilder(); beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition()); - Element receive = getChildElementByTagName(element, "receive"); - if (receive != null) { - boolean fork = parseBoolean(element.getAttribute("fork")); - return wrapSendAndReceiveActionInSequence(fork, receive, parserContext, beanDefinitionBuilder); - } - return beanDefinitionBuilder; } @@ -111,10 +117,10 @@ protected Class getMessageFactory * and receiving messages and adds them to a container that executes these actions in sequence * or asynchronously, depending on the {@code fork} parameter. */ - private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, + private BeanDefinition wrapSendAndReceiveActionInSequence(boolean fork, Element receive, ParserContext parserContext, - BeanDefinitionBuilder beanDefinitionBuilder) { + BeanDefinition sendBeanDefinition) { Class> containerClass = fork ? AsyncFactoryBean.class : SequenceFactoryBean.class; @@ -125,12 +131,12 @@ private BeanDefinitionBuilder wrapSendAndReceiveActionInSequence(boolean fork, BeanDefinition receiveResponseBeanDefinition = receiveApiResponseActionParser.parse(receive, parserContext); ManagedList actions = new ManagedList<>(); - actions.add(beanDefinitionBuilder.getBeanDefinition()); + actions.add(sendBeanDefinition); actions.add(receiveResponseBeanDefinition); sequenceBuilder.addPropertyValue("actions", actions); - return sequenceBuilder; + return sequenceBuilder.getBeanDefinition(); } /** diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 441c05043b..34b5319aec 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -257,19 +257,19 @@ public class {{classname}} implements GeneratedApi super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Specification, METHOD, ENDPOINT, OPERATION_NAME); {{#requiredNonBodyParams}} {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} {{/requiredNonBodyParams}} } @@ -286,19 +286,19 @@ public class {{classname}} implements GeneratedApi super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Specification, METHOD, ENDPOINT, OPERATION_NAME); {{#requiredNonBodyParams}} {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} {{/requiredNonBodyParams}} } @@ -330,19 +330,19 @@ public class {{classname}} implements GeneratedApi super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Specification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); {{#requiredNonBodyParams}} {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}{{^isArray}}Expression{{/isArray}}){{/isBinary}} {{^isBinary}}{{paramName}}{{^isArray}}Expression{{/isArray}}{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}{{^isArray}}Expression{{/isArray}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} {{/requiredNonBodyParams}} } @@ -353,19 +353,19 @@ public class {{classname}} implements GeneratedApi }} public {{operationIdCamelCase}}SendActionBuilder {{paramName}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} return this; } @@ -376,19 +376,19 @@ public class {{classname}} implements GeneratedApi }} public {{operationIdCamelCase}}SendActionBuilder {{paramName}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} return this; } @@ -403,19 +403,19 @@ public class {{classname}} implements GeneratedApi }} public {{operationIdCamelCase}}SendActionBuilder {{paramName}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} - pathParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + pathParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} return this; } @@ -429,19 +429,19 @@ public class {{classname}} implements GeneratedApi }} public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}({{#isArray}}{{baseType}}...{{/isArray}}{{^isArray}}{{dataType}} {{/isArray}}{{paramName}}) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} pathParameter("{{baseName}}", {{paramName}}); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}){{/isBinary}} {{^isBinary}}{{paramName}}{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} } {{^isBaseTypeString}} @@ -455,19 +455,19 @@ public class {{classname}} implements GeneratedApi }} public {{operationIdCamelCase}}SendActionBuilder {{paramName}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} pathParameter("{{baseName}}", {{paramName}}Expression); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} return this; } @@ -482,19 +482,19 @@ public class {{classname}} implements GeneratedApi }} public void set{{#lambda.titlecase}}{{paramName}}{{/lambda.titlecase}}(String{{#isArray}}...{{/isArray}}{{^isArray}} {{/isArray}}{{paramName}}Expression) { {{#isQueryParam}} - queryParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + queryParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isQueryParam}} {{#isPathParam}} pathParameter("{{baseName}}", {{paramName}}Expression); {{/isPathParam}} {{#isHeaderParam}} - headerParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + headerParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isHeaderParam}} {{#isFormParam}} formParameter("{{baseName}}", {{#isBinary}}toBinary({{paramName}}Expression){{/isBinary}} {{^isBinary}}{{paramName}}Expression{{/isBinary}}); {{/isFormParam}} {{#isCookieParam}} - cookieParameter("{{baseName}}", {{paramName}}Expression, ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}, {{isExplode}}, {{schema.isModel}}); + cookieParameter("{{baseName}}", {{paramName}}Expression, {{#style}}ParameterStyle.{{#lambda.uppercase}}{{style}}{{/lambda.uppercase}}{{/style}}{{^style}}ParameterStyle.NONE{{/style}}, {{isExplode}}, {{#schema.isModel}}{{schema.isModel}}{{/schema.isModel}}{{^schema.isModel}}false{{/schema.isModel}}); {{/isCookieParam}} } {{/isBaseTypeString}} @@ -585,7 +585,7 @@ public class {{classname}} implements GeneratedApi {{/authMethods}} if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -628,7 +628,7 @@ public class {{classname}} implements GeneratedApi public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache index 4371a2a3bb..c0b7fb0ca7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -23,6 +23,7 @@ import static java.util.Collections.emptyMap; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.citrusframework.openapi.testapi.GeneratedApiOperationInfo; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.endpoint.Endpoint; @@ -106,7 +107,8 @@ public class {{classname}} implements GeneratedApi {{/operations}} {{#operations}} {{#operation}} - public static class {{operationIdCamelCase}}SendActionBuilder extends {{requestBuilderClassName}} { + public static class {{operationIdCamelCase}}SendActionBuilder extends {{requestBuilderClassName}} implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "{{summary}}"; @@ -114,18 +116,34 @@ public class {{classname}} implements GeneratedApi super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public SendSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); } } - public static class {{operationIdCamelCase}}ReceiveActionBuilder extends {{responseBuilderClassName}} { + public static class {{operationIdCamelCase}}ReceiveActionBuilder extends {{responseBuilderClassName}} implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "{{summary}}"; @@ -133,11 +151,26 @@ public class {{classname}} implements GeneratedApi super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public ReceiveSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java index 17496e65a9..7f1e6f2171 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -57,6 +57,7 @@ import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; import org.citrusframework.openapi.testapi.GeneratedApi; +import org.citrusframework.openapi.testapi.GeneratedApiOperationInfo; import org.citrusframework.spi.Resources; import org.citrusframework.validation.json.JsonPathVariableExtractor; import org.citrusframework.validation.script.ScriptValidationContext; @@ -225,15 +226,15 @@ public ApiActionBuilderCustomizer petApiCustomizer() { @Override public > void customizeRequestBuilder( - GeneratedApi generatedApi, T builder) { - ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApi, + GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { + ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApiOperationInfo, builder); } @Override public > void customizeResponseBuilder( - GeneratedApi generatedApi, T builder) { - ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApi, + GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { + ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApiOperationInfo, builder); } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java index 0169704ee1..afe766a7e3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java @@ -75,6 +75,11 @@ class SoapApi { void xml() { } + @Test + @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withNestedReceiveDefaultClientSoapTest") + void withNestedReceiveInXmlWithDefaultClientTest() { + } + @Test void java(@CitrusResource TestCaseRunner runner) { String request = """ diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index 55049b07f8..edbebe147d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index f9e0df6955..f4e5a7ef52 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -25,7 +25,7 @@ /** * Additional historical data for a vaccination report, not contained in internal storage. */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class HistoricalData { private LocalDate lastVaccinationDate; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index e96c640952..6469cd773d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java index c9e216c35d..137609393f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java @@ -24,7 +24,7 @@ /** * PetIdentifier */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetIdentifier { private String _name; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index 4a3d8ce7fc..e1cc351373 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 9718fa1003..7843d96a8c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -24,7 +24,7 @@ /** * VaccinationDocumentResult */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class VaccinationDocumentResult { private String documentId; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index c3b3a5f146..313b22828d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -42,7 +42,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.model.VaccinationDocumentResult; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetApi implements GeneratedApi { @@ -1054,7 +1054,7 @@ public void setSchema(String schemaExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1097,7 +1097,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1138,7 +1138,7 @@ public static class GetPetByIdWithApiKeyAuthenticationSendActionBuilder extends public GetPetByIdWithApiKeyAuthenticationSendActionBuilder(ExtPetApi extPetApi, Long petId, Boolean allDetails) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); } /** @@ -1250,7 +1250,7 @@ public SendMessageAction doBuild() { cookieParameter("api_key_cookie", getOrDefault(apiKeyCookie, defaultApiKeyCookie, base64EncodeApiKey)); if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1293,7 +1293,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1326,7 +1326,7 @@ public static class GetPetByIdWithBasicAuthenticationSendActionBuilder extends public GetPetByIdWithBasicAuthenticationSendActionBuilder(ExtPetApi extPetApi, Long petId, Boolean allDetails) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); } /** @@ -1431,7 +1431,7 @@ public SendMessageAction doBuild() { addBasicAuthHeader(basicUsername, basicPassword, getMessageBuilderSupport()); if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1474,7 +1474,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1502,7 +1502,7 @@ public static class GetPetByIdWithBearerAuthenticationSendActionBuilder extends public GetPetByIdWithBearerAuthenticationSendActionBuilder(ExtPetApi extPetApi, Long petId, Boolean allDetails) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); + queryParameter("allDetails", allDetails, ParameterStyle.FORM, true, false); } /** @@ -1592,7 +1592,7 @@ public SendMessageAction doBuild() { } if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1635,7 +1635,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1700,7 +1700,7 @@ public GetPetByUuidSendActionBuilder petUuid(UUID petUuid) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1743,7 +1743,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1830,7 +1830,7 @@ public void setOptTrxId(String optTrxId) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1873,7 +1873,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1895,7 +1895,7 @@ public static class GetPetWithDeepObjectTypeQuerySendActionBuilder extends */ public GetPetWithDeepObjectTypeQuerySendActionBuilder(ExtPetApi extPetApi, PetIdentifier petId) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); - queryParameter("petId", petId, ParameterStyle.DEEPOBJECT, true, true); + queryParameter("petId", petId, ParameterStyle.DEEPOBJECT, true, true); } /** @@ -1943,7 +1943,7 @@ public GetPetWithDeepObjectTypeQuerySendActionBuilder petId(String petIdExpressi public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1986,7 +1986,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2056,7 +2056,7 @@ public GetPetWithFormExplodedStyleCookieSendActionBuilder petId(String...petIdEx public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2099,7 +2099,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2169,7 +2169,7 @@ public GetPetWithFormObjectStyleCookieSendActionBuilder petId(String petIdExpres public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2212,7 +2212,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2282,7 +2282,7 @@ public GetPetWithFormStyleCookieSendActionBuilder petId(String...petIdExpression public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2325,7 +2325,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2347,7 +2347,7 @@ public static class GetPetWithFormStyleExplodedObjectQuerySendActionBuilder exte */ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder(ExtPetApi extPetApi, PetIdentifier petId) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); - queryParameter("petId", petId, ParameterStyle.FORM, true, true); + queryParameter("petId", petId, ParameterStyle.FORM, true, true); } /** @@ -2395,7 +2395,7 @@ public GetPetWithFormStyleExplodedObjectQuerySendActionBuilder petId(String petI public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2438,7 +2438,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2460,7 +2460,7 @@ public static class GetPetWithFormStyleExplodedQuerySendActionBuilder extends */ public GetPetWithFormStyleExplodedQuerySendActionBuilder(ExtPetApi extPetApi, List petId) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); - queryParameter("petId", petId, ParameterStyle.FORM, true, false); + queryParameter("petId", petId, ParameterStyle.FORM, true, false); } /** @@ -2508,7 +2508,7 @@ public GetPetWithFormStyleExplodedQuerySendActionBuilder petId(String...petIdExp public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2551,7 +2551,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2573,7 +2573,7 @@ public static class GetPetWithFormStyleObjectQuerySendActionBuilder extends */ public GetPetWithFormStyleObjectQuerySendActionBuilder(ExtPetApi extPetApi, PetIdentifier petId) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); - queryParameter("petId", petId, ParameterStyle.FORM, false, true); + queryParameter("petId", petId, ParameterStyle.FORM, false, true); } /** @@ -2621,7 +2621,7 @@ public GetPetWithFormStyleObjectQuerySendActionBuilder petId(String petIdExpress public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2664,7 +2664,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2686,7 +2686,7 @@ public static class GetPetWithFormStyleQuerySendActionBuilder extends */ public GetPetWithFormStyleQuerySendActionBuilder(ExtPetApi extPetApi, List petId) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); - queryParameter("petId", petId, ParameterStyle.FORM, false, false); + queryParameter("petId", petId, ParameterStyle.FORM, false, false); } /** @@ -2734,7 +2734,7 @@ public GetPetWithFormStyleQuerySendActionBuilder petId(String...petIdExpression) public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2777,7 +2777,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2847,7 +2847,7 @@ public GetPetWithLabelStyleArraySendActionBuilder petId(String...petIdExpression public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -2890,7 +2890,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -2960,7 +2960,7 @@ public GetPetWithLabelStyleArrayExplodedSendActionBuilder petId(String...petIdEx public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3003,7 +3003,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3073,7 +3073,7 @@ public GetPetWithLabelStyleObjectSendActionBuilder petId(String petIdExpression) public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3116,7 +3116,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3186,7 +3186,7 @@ public GetPetWithLabelStyleObjectExplodedSendActionBuilder petId(String petIdExp public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3229,7 +3229,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3299,7 +3299,7 @@ public GetPetWithMatrixStyleArraySendActionBuilder petId(String...petIdExpressio public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3342,7 +3342,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3412,7 +3412,7 @@ public GetPetWithMatrixStyleArrayExplodedSendActionBuilder petId(String...petIdE public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3455,7 +3455,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3525,7 +3525,7 @@ public GetPetWithMatrixStyleObjectSendActionBuilder petId(String petIdExpression public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3568,7 +3568,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3638,7 +3638,7 @@ public GetPetWithMatrixStyleObjectExplodedSendActionBuilder petId(String petIdEx public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3681,7 +3681,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3751,7 +3751,7 @@ public GetPetWithSimpleStyleArraySendActionBuilder petId(String...petIdExpressio public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3794,7 +3794,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3864,7 +3864,7 @@ public GetPetWithSimpleStyleArrayExplodedSendActionBuilder petId(String...petIdE public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -3907,7 +3907,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -3977,7 +3977,7 @@ public GetPetWithSimpleStyleExplodedHeaderSendActionBuilder petId(String...petId public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4020,7 +4020,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4090,7 +4090,7 @@ public GetPetWithSimpleStyleExplodedObjectHeaderSendActionBuilder petId(String p public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4133,7 +4133,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4203,7 +4203,7 @@ public GetPetWithSimpleStyleHeaderSendActionBuilder petId(String...petIdExpressi public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4246,7 +4246,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4316,7 +4316,7 @@ public GetPetWithSimpleStyleObjectSendActionBuilder petId(String petIdExpression public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4359,7 +4359,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4429,7 +4429,7 @@ public GetPetWithSimpleStyleObjectExplodedSendActionBuilder petId(String petIdEx public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4472,7 +4472,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4542,7 +4542,7 @@ public GetPetWithSimpleStyleObjectHeaderSendActionBuilder petId(String petIdExpr public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4585,7 +4585,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4649,7 +4649,7 @@ public PostVaccinationDocumentSendActionBuilder filename(String filename) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4692,7 +4692,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4802,7 +4802,7 @@ public void setVaccinationDate(String vaccinationDateExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -4845,7 +4845,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -4868,10 +4868,10 @@ public static class UpdatePetWithArrayQueryDataSendActionBuilder extends public UpdatePetWithArrayQueryDataSendActionBuilder(ExtPetApi extPetApi, Long petId, String _name, String status, List tags, List nicknames, String sampleStringHeader) { super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false); - queryParameter("name", _name, ParameterStyle.FORM, true, false); - queryParameter("status", status, ParameterStyle.FORM, true, false); - queryParameter("tags", tags, ParameterStyle.FORM, true, false); - queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); + queryParameter("name", _name, ParameterStyle.FORM, true, false); + queryParameter("status", status, ParameterStyle.FORM, true, false); + queryParameter("tags", tags, ParameterStyle.FORM, true, false); + queryParameter("nicknames", nicknames, ParameterStyle.FORM, true, false); headerParameter("sampleStringHeader", sampleStringHeader, ParameterStyle.SIMPLE, false, false); } @@ -4973,7 +4973,7 @@ public void setSampleIntHeader(String sampleIntHeaderExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -5016,7 +5016,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -5150,7 +5150,7 @@ public void setNicknames(String...nicknames) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -5193,7 +5193,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index 1d2dd76533..f42ef2cd4d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index 5525418d45..361cf6497a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -12,7 +12,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:56.748927500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index 06800d5d54..972cd4144b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -24,7 +24,7 @@ /** * Address */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Address { private String street; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index 63614e1e3e..4e8859292f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index c98b31df30..34249bf7a0 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -28,7 +28,7 @@ /** * Customer */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Customer { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index 15e666dfee..eabd3f8b1b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -24,7 +24,7 @@ /** * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ModelApiResponse { private Integer code; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index 9d2db02a4f..cd61b599f2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -25,7 +25,7 @@ /** * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Order { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index 564342da9d..11076f71c8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index d55bbfc147..bc19008e1f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index c351448931..69daf58d73 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -24,7 +24,7 @@ /** * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class User { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index f4a0df5fab..75856c891f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Pet; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetApi implements GeneratedApi { @@ -286,7 +286,7 @@ public AddPetSendActionBuilder(PetApi petApi, TestApiClientRequestMessageBuilder public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -329,7 +329,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -408,7 +408,7 @@ public void setApiKey(String apiKey) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -451,7 +451,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -507,7 +507,7 @@ public void setStatus(String status) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -550,7 +550,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -606,7 +606,7 @@ public void setTags(String...tags) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -649,7 +649,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -741,7 +741,7 @@ public SendMessageAction doBuild() { headerParameter("api_key", getOrDefault(apiKey, defaultApiKey, base64EncodeApiKey)); if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -784,7 +784,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -831,7 +831,7 @@ public UpdatePetSendActionBuilder(PetApi petApi, TestApiClientRequestMessageBuil public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -874,7 +874,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -962,7 +962,7 @@ public void setStatus(String status) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1005,7 +1005,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -1098,7 +1098,7 @@ public void setBody(String bodyExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -1141,7 +1141,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 1f82bc08ab..97fcceb73c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -36,7 +36,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Order; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class StoreApi implements GeneratedApi { @@ -231,7 +231,7 @@ public DeleteOrderSendActionBuilder orderId(String orderIdExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -274,7 +274,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -343,7 +343,7 @@ public SendMessageAction doBuild() { headerParameter("api_key", getOrDefault(apiKey, defaultApiKey, base64EncodeApiKey)); if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -386,7 +386,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -456,7 +456,7 @@ public GetOrderByIdSendActionBuilder orderId(String orderIdExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -499,7 +499,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -560,7 +560,7 @@ public void setOrder(String orderExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -603,7 +603,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index ea7bd796db..a91eb94870 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.User; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class UserApi implements GeneratedApi { @@ -252,7 +252,7 @@ public void setUser(String userExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -295,7 +295,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -356,7 +356,7 @@ public void setUser(String...userExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -399,7 +399,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -456,7 +456,7 @@ public DeleteUserSendActionBuilder username(String username) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -499,7 +499,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -556,7 +556,7 @@ public GetUserByNameSendActionBuilder username(String username) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -599,7 +599,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -664,7 +664,7 @@ public void setPassword(String password) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -707,7 +707,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -754,7 +754,7 @@ public LogoutUserSendActionBuilder(UserApi userApi, TestApiClientRequestMessageB public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -797,7 +797,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -868,7 +868,7 @@ public void setUser(String userExpression) { public SendMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); @@ -911,7 +911,7 @@ public String getPath() { public ReceiveMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index 41ac4c33c5..f75e2da7f9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -17,7 +17,7 @@ import org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index acc353b014..757b44706b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -14,7 +14,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:55.767401300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index 787fac3f6a..75053e1592 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -6,6 +6,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.citrusframework.openapi.testapi.GeneratedApiOperationInfo; import org.citrusframework.ws.actions.ReceiveSoapMessageAction; import org.citrusframework.ws.actions.SendSoapMessageAction; import org.citrusframework.endpoint.Endpoint; @@ -15,7 +16,7 @@ import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceSoapApi implements GeneratedApi { @@ -90,7 +91,8 @@ public GetBookReceiveActionBuilder receiveGetBook() { return new GetBookReceiveActionBuilder(this); } - public static class AddBookSendActionBuilder extends SoapApiSendMessageActionBuilder { + public static class AddBookSendActionBuilder extends SoapApiSendMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/AddBook"; @@ -98,18 +100,34 @@ public AddBookSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public SendSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); } } - public static class AddBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + public static class AddBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/AddBook"; @@ -117,11 +135,26 @@ public AddBookReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public ReceiveSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -129,7 +162,8 @@ public ReceiveSoapMessageAction doBuild() { } - public static class GetAllBooksSendActionBuilder extends SoapApiSendMessageActionBuilder { + public static class GetAllBooksSendActionBuilder extends SoapApiSendMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetAllBooks"; @@ -137,18 +171,34 @@ public GetAllBooksSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public SendSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); } } - public static class GetAllBooksReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + public static class GetAllBooksReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetAllBooks"; @@ -156,11 +206,26 @@ public GetAllBooksReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public ReceiveSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); @@ -168,7 +233,8 @@ public ReceiveSoapMessageAction doBuild() { } - public static class GetBookSendActionBuilder extends SoapApiSendMessageActionBuilder { + public static class GetBookSendActionBuilder extends SoapApiSendMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetBook"; @@ -176,18 +242,34 @@ public GetBookSendActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public SendSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); } return super.doBuild(); } } - public static class GetBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder { + public static class GetBookReceiveActionBuilder extends SoapApiReceiveMessageActionBuilder implements + GeneratedApiOperationInfo { private static final String SOAP_ACTION = "http://www.citrusframework.com/BookService/GetBook"; @@ -195,11 +277,26 @@ public GetBookReceiveActionBuilder(BookServiceSoapApi bookServiceSoapApi) { super(bookServiceSoapApi, SOAP_ACTION); } + @Override + public String getOperationName() { + return SOAP_ACTION; + } + + @Override + public String getMethod() { + return "POST"; + } + + @Override + public String getPath() { + return SOAP_ACTION; + } + @Override public ReceiveSoapMessageAction doBuild() { if (getCustomizers() != null) { - getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(getGeneratedApi(), this)); + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); } return super.doBuild(); diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java index 013ba6bad6..1c40475f53 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.soap.bookservice.BookServiceOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java index 4a3c422f8e..a47bd113e9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java @@ -10,7 +10,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-11-25T13:12:57.221987500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveDefaultClientSoapTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveDefaultClientSoapTest.xml new file mode 100644 index 0000000000..a7f65cbb36 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withNestedReceiveDefaultClientSoapTest.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + + + J.R. Tolkien + 0815 + Lord of the Rings + + + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index 655d0dcba1..eb4e0fe59a 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -30,7 +30,13 @@ import com.google.common.annotations.VisibleForTesting; import java.io.File; +import java.io.IOException; import java.lang.reflect.Field; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -44,28 +50,31 @@ import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; +import org.citrusframework.openapi.generator.WsdlToOpenApiTransformer; +import org.citrusframework.openapi.generator.exception.WsdlToOpenApiTransformationException; import org.citrusframework.util.StringUtils; import org.openapitools.codegen.plugin.CodeGenMojo; import org.sonatype.plexus.build.incremental.BuildContext; import org.sonatype.plexus.build.incremental.DefaultBuildContext; /** - * The Citrus OpenAPI Generator Maven Plugin is designed to facilitate the integration of multiple OpenAPI specifications - * into the Citrus testing framework by automatically generating necessary test classes and XSDs. This plugin wraps the - * {@code CodeGenMojo} and extends its functionality to support multiple API configurations. + * The Citrus OpenAPI Generator Maven Plugin is designed to facilitate the integration of multiple + * OpenAPI specifications into the Citrus testing framework by automatically generating necessary + * test classes and XSDs. This plugin wraps the {@code CodeGenMojo} and extends its functionality to + * support multiple API configurations. *

        - * Features: - * - Multiple API Configurations: Easily configure multiple OpenAPI specifications to generate test APIs with specific prefixes. - * - Citrus Integration: Generates classes and XSDs tailored for use within the Citrus framework, streamlining the process - * of creating robust integration tests. + * Features: - Multiple API Configurations: Easily configure multiple OpenAPI specifications to + * generate test APIs with specific prefixes. - Citrus Integration: Generates classes and XSDs + * tailored for use within the Citrus framework, streamlining the process of creating robust + * integration tests. *

        */ @Mojo( - name = "create-test-api", - defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, - requiresDependencyCollection = ResolutionScope.TEST, - requiresDependencyResolution = ResolutionScope.TEST, - threadSafe = true + name = "create-test-api", + defaultPhase = LifecyclePhase.GENERATE_TEST_SOURCES, + requiresDependencyCollection = ResolutionScope.TEST, + requiresDependencyResolution = ResolutionScope.TEST, + threadSafe = true ) public class TestApiGeneratorMojo extends AbstractMojo { @@ -79,23 +88,25 @@ public class TestApiGeneratorMojo extends AbstractMojo { public static final ApiType DEFAULT_API_TYPE = ApiType.REST; /** - * Marker fragment in the schema name of a generated schema. Used to distinguish generated from non generated values, when manipulating - * spring meta-data files. + * Marker fragment in the schema name of a generated schema. Used to distinguish generated from + * non generated values, when manipulating spring meta-data files. */ public static final String CITRUS_TEST_SCHEMA = "citrus-test-schema"; /** - * Marker text to mark the next line of a spring.handlers or spring.schemas file not to be removed by the generator. + * Marker text to mark the next line of a spring.handlers or spring.schemas file not to be + * removed by the generator. */ public static final String CITRUS_TEST_SCHEMA_KEEP_HINT = "citrus-test-schema-keep"; /** - * Specifies the default target namespace template. When changing the default value, it's important to maintain the 'citrus-test-schema' - * part, as this name serves to differentiate between generated and non-generated schemas. This differentiation aids in the creation of + * Specifies the default target namespace template. When changing the default value, it's + * important to maintain the 'citrus-test-schema' part, as this name serves to differentiate + * between generated and non-generated schemas. This differentiation aids in the creation of * supporting Spring files such as 'spring.handlers' and 'spring.schemas'. */ public static final String DEFAULT_TARGET_NAMESPACE_TEMPLATE = - "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; + "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; /** * TODO: document this @@ -105,27 +116,32 @@ public class TestApiGeneratorMojo extends AbstractMojo { public static final String DEFAULT_META_INF_FOLDER = "src/test/resources/META-INF"; /** - * sourceFolder: specifies the location to which the sources are generated. Defaults to 'generated-test-sources'. + * sourceFolder: specifies the location to which the sources are generated. Defaults to + * 'generated-test-sources'. */ public static final String SOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.source.folder"; /** - * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-test-resources'. + * resourceFolder: specifies the location to which the resources are generated. Defaults to + * 'generated-test-resources'. */ public static final String RESOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.resource.folder"; /** - * schemaFolder: specifies the location for the generated xsd schemas. Defaults to 'schema/xsd/%VERSION%' + * schemaFolder: specifies the location for the generated xsd schemas. Defaults to + * 'schema/xsd/%VERSION%' */ public static final String API_SCHEMA_FOLDER = "citrus.test.api.generator.schema.folder"; /** - * metaInfFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. + * metaInfFolder: specifies the location to which the resources are generated. Defaults to + * 'generated-resources'. */ public static final String META_INF_FOLDER = "citrus.test.api.generator.meta.inf.folder"; /** - * resourceFolder: specifies the location to which the resources are generated. Defaults to 'generated-resources'. + * resourceFolder: specifies the location to which the resources are generated. Defaults to + * 'generated-resources'. */ public static final String GENERATE_SPRING_INTEGRATION_FILES = "citrus.test.api.generator.generate.spring.integration.files"; @@ -179,14 +195,15 @@ static String replaceDynamicVars(String text, String prefix, String version) { } return text.replace("%PREFIX%", prefix) - .replace(".%VERSION%", version != null ? "." + version : "") - .replace("/%VERSION%", version != null ? "/" + version : "") - .replace("-%VERSION%", version != null ? "-" + version : "") - .replace("%VERSION%", version != null ? version : ""); + .replace(".%VERSION%", version != null ? "." + version : "") + .replace("/%VERSION%", version != null ? "/" + version : "") + .replace("-%VERSION%", version != null ? "-" + version : "") + .replace("%VERSION%", version != null ? version : ""); } /** - * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text, performing a toLowerCase on the prefix. + * Replace the placeholders '%PREFIX%' and '%VERSION%' in the given text, performing a + * toLowerCase on the prefix. */ static String replaceDynamicVarsToLowerCase(String text, String prefix, String version) { return replaceDynamicVars(text, prefix.toLowerCase(), version); @@ -235,25 +252,25 @@ public void execute() throws MojoExecutionException { } @VisibleForTesting - void delegateExecution(CodeGenMojo codeGenMojo) { - try { - codeGenMojo.execute(); - } catch (MojoExecutionException e) { - throw new RuntimeException(e); - } + void delegateExecution(CodeGenMojo codeGenMojo) throws MojoExecutionException { + codeGenMojo.execute(); } CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionException { + + if (apiConfig.getSource().toUpperCase().trim().endsWith(".WSDL")) { + apiConfig.source = convertToOpenApi(apiConfig.getSource()); + } CodeGenMojo codeGenMojo = new CodeGenMojoWrapper() - .resourceFolder(resourceFolder) - .sourceFolder(sourceFolder) - .schemaFolder(schemaFolder(apiConfig)) - .output(new File(mavenProject.getBuild().getDirectory())) - .mojoExecution(mojoExecution) - .project(mavenProject) - .inputSpec(apiConfig.getSource()) - .globalProperties(globalProperties) - .configOptions(apiConfig.toConfigOptionsProperties(globalConfigOptions)); + .resourceFolder(resourceFolder) + .sourceFolder(sourceFolder) + .schemaFolder(schemaFolder(apiConfig)) + .output(new File(mavenProject.getBuild().getDirectory())) + .mojoExecution(mojoExecution) + .project(mavenProject) + .inputSpec(apiConfig.getSource()) + .globalProperties(globalProperties) + .configOptions(apiConfig.toConfigOptionsProperties(globalConfigOptions)); codeGenMojo.setPluginContext(getPluginContext()); @@ -263,7 +280,8 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept properties.addAll(apiConfig.additionalProperties); } apiConfig.additionalProperties = properties; - apiConfig.additionalProperties.add(String.format("%s=%s", ROOT_CONTEXT_PATH, apiConfig.rootContextPath)); + apiConfig.additionalProperties.add( + format("%s=%s", ROOT_CONTEXT_PATH, apiConfig.rootContextPath)); } propagateBuildContext(codeGenMojo); @@ -272,6 +290,54 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept return codeGenMojo; } + private String convertToOpenApi(String source) throws MojoExecutionException { + String apiFile = source; + String path = source.replace("\\", "/"); + + int lastSegmentIndex = path.lastIndexOf("/"); + if (lastSegmentIndex > 0) { + apiFile = path.substring(lastSegmentIndex + 1); + } + + File resourceFile; + if (new File(source).isAbsolute()) { + resourceFile = new File(source); + if (!resourceFile.exists()) { + throw new MojoExecutionException( + "File not found at the provided absolute path: " + source); + } + } else { + URL resourceUrl = getClass().getClassLoader().getResource(source); + if (resourceUrl == null) { + throw new MojoExecutionException("Resource not found in classpath: " + source); + } + resourceFile = new File(resourceUrl.getFile()); + } + + File tmpDir = new File(mavenProject.getBuild().getDirectory() + "/wsdlToOpenApi"); + if (!tmpDir.exists() && !tmpDir.mkdirs()) { + throw new MojoExecutionException( + "Unable to create directory for temporary storage of converted WSDL: " + + tmpDir.getAbsolutePath()); + } + + try { + WsdlToOpenApiTransformer transformer = new WsdlToOpenApiTransformer( + resourceFile.toURI()); + + String openApiContent = transformer.transformToOpenApi(); + + Path openApiPath = Paths.get(tmpDir.getAbsolutePath(), apiFile); + Files.writeString(openApiPath, openApiContent, StandardOpenOption.CREATE, + StandardOpenOption.TRUNCATE_EXISTING); + + return openApiPath.toString(); + } catch (WsdlToOpenApiTransformationException | IOException e) { + throw new MojoExecutionException( + String.format("Unable to transform WSDL %s to OpenAPI", source), e); + } + } + /** * Reflectively inject the buildContext. This is set by maven and needs to be propagated into * the plugin, that actually performs the work. @@ -279,28 +345,34 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept private void propagateBuildContext(CodeGenMojo codeGenMojo) { Field buildContextField = findField(CodeGenMojo.class, "buildContext"); - makeAccessible(requireNonNull(buildContextField, "Could not retrieve 'buildContext' field from CodeGenMojo delegate.")); + makeAccessible(requireNonNull(buildContextField, + "Could not retrieve 'buildContext' field from CodeGenMojo delegate.")); setField(buildContextField, codeGenMojo, buildContext); } /** * Reflectively inject the additionProperties. */ - private void propagateAdditionalProperties(CodeGenMojo codeGenMojo, List additionalProperties) { + private void propagateAdditionalProperties(CodeGenMojo codeGenMojo, + List additionalProperties) { Field buildContextField = findField(CodeGenMojo.class, "additionalProperties"); - makeAccessible(requireNonNull(buildContextField, "Could not retrieve 'additionalProperties' field from CodeGenMojo delegate.")); + makeAccessible(requireNonNull(buildContextField, + "Could not retrieve 'additionalProperties' field from CodeGenMojo delegate.")); setField(buildContextField, codeGenMojo, additionalProperties); } - private void validateApiConfig(int apiIndex, ApiConfig apiConfig) throws MojoExecutionException { + private void validateApiConfig(int apiIndex, ApiConfig apiConfig) + throws MojoExecutionException { requireNonBlankParameter("prefix", apiIndex, apiConfig.getPrefix()); requireNonBlankParameter("source", apiIndex, apiConfig.getSource()); } - private void requireNonBlankParameter(String name, int index, String parameterValue) throws MojoExecutionException { + private void requireNonBlankParameter(String name, int index, String parameterValue) + throws MojoExecutionException { if (isBlank(parameterValue)) { - throw new MojoExecutionException(format("Required parameter '%s' not set for api at index '%d'!", name, index)); + throw new MojoExecutionException( + format("Required parameter '%s' not set for api at index '%d'!", name, index)); } } @@ -311,20 +383,22 @@ public enum ApiType { // TODO: document all configuration properties /** - * Note that the default values are not properly set by maven processor. Therefore, the default values have been assigned additionally - * on field level. + * Note that the default values are not properly set by maven processor. Therefore, the default + * values have been assigned additionally on field level. */ public static class ApiConfig { public static final String DEFAULT_ENDPOINT = "PREFIX_ENDPOINT"; /** - * prefix: specifies the prefixed used for the test api. Typically, an acronym for the application which is being tested. + * prefix: specifies the prefixed used for the test api. Typically, an acronym for the + * application which is being tested. */ public static final String API_PREFIX_PROPERTY = "citrus.test.api.generator.prefix"; /** - * rootContextPath: specifies the context path that will be prepended to all OpenAPI operation paths. + * rootContextPath: specifies the context path that will be prepended to all OpenAPI + * operation paths. */ public static final String ROOT_CONTEXT_PATH = "citrus.test.api.generator.root-context-path"; @@ -349,8 +423,9 @@ public static class ApiConfig { public static final String API_TYPE_PROPERTY = "citrus.test.api.generator.type"; /** - * useTags: specifies whether tags should be used by the generator. Defaults to 'true'. If useTags is set to true, the generator - * will organize the generated code based on the tags defined in your API specification. + * useTags: specifies whether tags should be used by the generator. Defaults to 'true'. If + * useTags is set to true, the generator will organize the generated code based on the tags + * defined in your API specification. */ public static final String API_USE_TAGS_PROPERTY = "citrus.test.api.generator.use.tags"; @@ -501,7 +576,8 @@ public void setTargetXmlnsNamespace(String targetXmlnsNamespace) { } public String qualifiedEndpoint() { - return DEFAULT_ENDPOINT.equals(endpoint) ? getPrefix().toLowerCase() + "Endpoint" : endpoint; + return DEFAULT_ENDPOINT.equals(endpoint) ? getPrefix().toLowerCase() + "Endpoint" + : endpoint; } public void setRootContextPath(String rootContextPath) { @@ -523,13 +599,13 @@ Map toConfigOptionsProperties(Map globalConfigOptions) { configOptionsProperties.put(API_ENDPOINT, qualifiedEndpoint()); configOptionsProperties.put(API_TYPE, type.toString()); configOptionsProperties.put(TARGET_XMLNS_NAMESPACE, - replaceDynamicVarsToLowerCase(targetXmlnsNamespace, prefix, version)); + replaceDynamicVarsToLowerCase(targetXmlnsNamespace, prefix, version)); configOptionsProperties.put("invokerPackage", - replaceDynamicVarsToLowerCase(invokerPackage, prefix, version)); + replaceDynamicVarsToLowerCase(invokerPackage, prefix, version)); configOptionsProperties.put("apiPackage", - replaceDynamicVarsToLowerCase(apiPackage, prefix, version)); + replaceDynamicVarsToLowerCase(apiPackage, prefix, version)); configOptionsProperties.put("modelPackage", - replaceDynamicVarsToLowerCase(modelPackage, prefix, version)); + replaceDynamicVarsToLowerCase(modelPackage, prefix, version)); configOptionsProperties.put("useTags", useTags); if (globalConfigOptions != null) { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java index 9bf749eb20..c3fd48809b 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -115,7 +115,9 @@ static Stream executeMojoWithConfigurations() { Map.of("a", "b", "c", "d", "other", "otherOption"), emptyList()), arguments("pom-with-additional-properties", null, emptyMap(), emptyMap(), - List.of("a=b", "c=d")) + List.of("a=b", "c=d")), + arguments("pom-soap-from-wsdl-config", null, + emptyMap(), emptyMap(), emptyList()) ); } @@ -212,16 +214,19 @@ private void writeSomeValuesToSpringMetaFiles(List apiConfigs) { } private void assertFilesGenerated(ApiConfig apiConfig) { - for (String filePathTemplate : STANDARD_FILE_PATH_TEMPLATES) { - String filePath = resolveFilePath(apiConfig, filePathTemplate); - assertThat(new File(filePath)).isFile().exists(); - } - if (TRUE.equals(getField(fixture, "generateSpringIntegrationFiles"))) { - for (String filePathTemplate : SPRING_META_FILE_TEMPLATES) { + if (apiConfig.getSource().contains("test-api.yml")) { + for (String filePathTemplate : STANDARD_FILE_PATH_TEMPLATES) { String filePath = resolveFilePath(apiConfig, filePathTemplate); assertThat(new File(filePath)).isFile().exists(); } + + if (TRUE.equals(getField(fixture, "generateSpringIntegrationFiles"))) { + for (String filePathTemplate : SPRING_META_FILE_TEMPLATES) { + String filePath = resolveFilePath(apiConfig, filePathTemplate); + assertThat(new File(filePath)).isFile().exists(); + } + } } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-from-wsdl-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-from-wsdl-config.xml new file mode 100644 index 0000000000..abfa885518 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-soap-from-wsdl-config.xml @@ -0,0 +1,33 @@ + + 4.0.0 + + soap-config + + + + + citrus-test-api-generator-maven-plugin + + + + FromWsdl + api/BookService.wsdl + SOAP + + + + + + + create-test-api + + + + + + + diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookDatatypes.xsd b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookDatatypes.xsd new file mode 100644 index 0000000000..3a735e7dd8 --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookDatatypes.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookService.wsdl b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookService.wsdl new file mode 100644 index 0000000000..d16857172e --- /dev/null +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/api/BookService.wsdl @@ -0,0 +1,113 @@ + + + Definition for a web service called BookService, + which can be used to add or retrieve books from a collection. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + This binding defines the SOAP over HTTP transport for BookService operations. + + + This operation retrieves details for a specific book identified by its ID. + + Detailed Soap Operation documentation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index 711c2e65e7..853782c8c0 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -15,10 +15,6 @@ Citrus Test API Generator pom - - true - - citrus-test-api-core citrus-test-api-generator-core From cedca03d41e711f7eb3228dcc2cb6ceb546656f9 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Wed, 11 Dec 2024 16:44:19 +0100 Subject: [PATCH 37/47] feat: add option to specify OpenApiValidationPolicy --- .../openapi/OpenApiRepository.java | 16 +- .../openapi/OpenApiSettings.java | 23 +- .../openapi/OpenApiSpecification.java | 128 ++++-- .../openapi/actions/OpenApiActionBuilder.java | 9 +- .../OpenApiValidationContextLoader.java | 132 +++++- .../validation/OpenApiValidationPolicy.java | 31 ++ .../openapi/OpenApiRepositoryTest.java | 54 ++- .../openapi/OpenApiSettingsTest.java | 52 ++- .../openapi/OpenApiSpecificationTest.java | 87 +++- ...penApiClientRequestMessageBuilderTest.java | 4 +- .../openapi/faulty/faulty-ping-api.yaml | 422 ++++++++++++++++++ 11 files changed, 867 insertions(+), 91 deletions(-) create mode 100644 connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationPolicy.java create mode 100644 connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/faulty/faulty-ping-api.yaml diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index edf2bb0496..65607479e4 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; import org.slf4j.Logger; @@ -60,6 +61,8 @@ public class OpenApiRepository extends BaseRepository { private boolean responseValidationEnabled = true; + private OpenApiValidationPolicy openApiValidationPolicy = OpenApiSettings.getOpenApiValidationPolicy(); + public OpenApiRepository() { super(DEFAULT_NAME); } @@ -137,6 +140,16 @@ public void setResponseValidationEnabled(boolean responseValidationEnabled) { this.responseValidationEnabled = responseValidationEnabled; } + public OpenApiValidationPolicy getOpenApiValidationPolicy() { + return openApiValidationPolicy; + } + + public void setOpenApiValidationPolicy( + OpenApiValidationPolicy openApiValidationPolicy) { + this.openApiValidationPolicy = openApiValidationPolicy; + } + + /** * Adds an OpenAPI Specification specified by the given resource to the repository. If an alias * is determined from the resource name, it is added to the specification. @@ -145,7 +158,8 @@ public void setResponseValidationEnabled(boolean responseValidationEnabled) { */ @Override public void addRepository(Resource openApiResource) { - OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource); + OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource, + openApiValidationPolicy); determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java index ab4dab92f5..c984edd1c6 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSettings.java @@ -18,6 +18,8 @@ import static java.lang.Boolean.parseBoolean; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; + /** * The {@code OpenApiSettings} class provides configuration settings for enabling or disabling * OpenAPI request and response validation globally. The settings can be controlled through @@ -37,12 +39,15 @@ public class OpenApiSettings { public static final String NEGLECT_OPEN_API_BASE_PATH_PROPERTY = "citrus.openapi.neglect.base.path"; public static final String NEGLECT_OPEN_API_BASE_PATH_ENV = "CITRUS_OPENAPI_NEGLECT_BASE_PATH"; - public static final String REQUEST_AUTO_FILL_RANDOM_VALUES = "citrus.openapi.request.fill.random.values"; + public static final String REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY = "citrus.openapi.request.fill.random.values"; public static final String REQUEST_AUTO_FILL_RANDOM_VALUES_ENV = "CITRUS_OPENAPI_REQUEST_FILL_RANDOM_VALUES"; - public static final String RESPONSE_AUTO_FILL_RANDOM_VALUES = "citrus.openapi.response.fill.random.values"; + public static final String RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY = "citrus.openapi.response.fill.random.values"; public static final String RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV = "CITRUS_OPENAPI_RESPONSE_FILL_RANDOM_VALUES"; + public static final String OPEN_API_VALIDATION_POLICY_PROPERTY = "citrus.openapi.validation.policy"; + public static final String OPEN_API_VALIDATION_POLICY_ENV = "CITRUS_OPENAPI_VALIDATION_POLICY"; + private OpenApiSettings() { // static access only } @@ -75,7 +80,7 @@ public static boolean isNeglectBasePathGlobally() { */ public static AutoFillType getRequestAutoFillRandomValues() { return AutoFillType.valueOf(System.getProperty( - REQUEST_AUTO_FILL_RANDOM_VALUES, System.getenv(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV) != null ? + REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY, System.getenv(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV) != null ? System.getenv(REQUEST_AUTO_FILL_RANDOM_VALUES_ENV) : AutoFillType.REQUIRED.name())); } @@ -84,7 +89,17 @@ public static AutoFillType getRequestAutoFillRandomValues() { */ public static AutoFillType getResponseAutoFillRandomValues() { return AutoFillType.valueOf(System.getProperty( - RESPONSE_AUTO_FILL_RANDOM_VALUES, System.getenv(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV) != null ? + RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY, System.getenv(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV) != null ? System.getenv(RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV) : AutoFillType.REQUIRED.name())); } + + /** + * The default OpenApiValidationPolicy for OpenAPI parsed for validation purposes. + */ + public static OpenApiValidationPolicy getOpenApiValidationPolicy() { + return OpenApiValidationPolicy.valueOf(System.getProperty( + OPEN_API_VALIDATION_POLICY_PROPERTY, System.getenv(OPEN_API_VALIDATION_POLICY_ENV) != null ? + System.getenv(OPEN_API_VALIDATION_POLICY_ENV) : OpenApiValidationPolicy.REPORT.name())); + } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index c89a9beae2..9b8f8143a8 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -53,6 +53,7 @@ import org.citrusframework.openapi.util.OpenApiUtils; import org.citrusframework.openapi.validation.OpenApiValidationContext; import org.citrusframework.openapi.validation.OpenApiValidationContextLoader; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.citrusframework.spi.Resource; import org.citrusframework.spi.Resources; import org.slf4j.Logger; @@ -115,7 +116,8 @@ public class OpenApiSpecification { private String requestUrl; /** - * Flag indicating whether the base path should be excluded when constructing the complete operation path. + * Flag indicating whether the base path should be excluded when constructing the complete + * operation path. *

        * If set to {@code true}, the base path will be omitted from the final URL path construction. * This allows for more flexible path handling where the base path is not required. @@ -129,12 +131,13 @@ public class OpenApiSpecification { * The optional root context path to which the OpenAPI is hooked. *

        * This path is prepended to the base path specified in the OpenAPI configuration. If no root - * context path is specified, only the base path and additional segments are used when constructing - * the complete URL path. + * context path is specified, only the base path and additional segments are used when + * constructing the complete URL path. *

        * * @see #neglectBasePath for information on excluding the base path - * @see #getFullPath(OasPathItem) for how this path is used in constructing the full operation path + * @see #getFullPath(OasPathItem) for how this path is used in constructing the full operation + * path */ private String rootContextPath; @@ -155,21 +158,65 @@ public class OpenApiSpecification { */ private boolean apiResponseValidationEnabled = isResponseValidationEnabledGlobally(); + /** + * The policy that determines how OpenAPI validation errors are handled. + */ + private final OpenApiValidationPolicy openApiValidationPolicy; + + public OpenApiSpecification() { + this(OpenApiSettings.getOpenApiValidationPolicy()); + } + + public OpenApiSpecification(OpenApiValidationPolicy openApiValidationPolicy) { + this.openApiValidationPolicy = openApiValidationPolicy; + } + + /** + * Creates an OpenAPI specification instance from the given URL applying the default validation policy. + * + * @param specUrl the URL pointing to the OpenAPI specification to load + * @return an OpenApiSpecification instance populated with the document and validation context + */ + public static OpenApiSpecification from(String specUrl) { - OpenApiSpecification specification = new OpenApiSpecification(); + return from(specUrl, OpenApiSettings.getOpenApiValidationPolicy()); + } + + /** + * Creates an OpenAPI specification instance from the given url string. + * + * @param specUrl the URL pointing to the OpenAPI specification to load + * @param openApiValidationPolicy the validation policy to apply to the loaded OpenApi + * @return an OpenApiSpecification instance populated with the document and validation context + */ + public static OpenApiSpecification from(String specUrl, + OpenApiValidationPolicy openApiValidationPolicy) { + OpenApiSpecification specification = new OpenApiSpecification(openApiValidationPolicy); specification.setSpecUrl(specUrl); return specification; } /** - * Creates an OpenAPI specification instance from the given URL. + * Creates an OpenAPI specification instance from the given URL applying the default validation policy. * - * @param specUrl the URL pointing to the OpenAPI specification to load + * @param specUrl the URL pointing to the OpenAPI specification to load * @return an OpenApiSpecification instance populated with the document and validation context */ public static OpenApiSpecification from(URL specUrl) { - OpenApiSpecification specification = new OpenApiSpecification(); + return from(specUrl, OpenApiSettings.getOpenApiValidationPolicy()); + } + + /** + * Creates an OpenAPI specification instance from the given URL. + * + * @param specUrl the URL pointing to the OpenAPI specification to load + * @param openApiValidationPolicy the validation policy to apply to the loaded OpenApi + * @return an OpenApiSpecification instance populated with the document and validation context + */ + public static OpenApiSpecification from(URL specUrl, + OpenApiValidationPolicy openApiValidationPolicy) { + OpenApiSpecification specification = new OpenApiSpecification(openApiValidationPolicy); OasDocument openApiDoc; OpenApiValidationContext openApiValidationContext; if (specUrl.getProtocol().startsWith(HTTPS)) { @@ -178,7 +225,8 @@ public static OpenApiSpecification from(URL specUrl) { specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); - openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl); + openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl, + openApiValidationPolicy); } specification.setSpecUrl(specUrl.toString()); @@ -194,17 +242,32 @@ public static OpenApiSpecification from(URL specUrl) { } /** - * Creates an OpenAPI specification instance from the specified resource. + * Creates an OpenAPI specification instance from the specified resource, applying the default + * validation strategy. * * @param resource the file resource containing the OpenAPI specification to load * @return an OpenApiSpecification instance populated with the document and validation context */ public static OpenApiSpecification from(Resource resource) { - OpenApiSpecification specification = new OpenApiSpecification(); + return from(resource, OpenApiSettings.getOpenApiValidationPolicy()); + } + + /** + * Creates an OpenAPI specification instance from the specified resource. + * + * @param resource the file resource containing the OpenAPI specification to + * load + * @param openApiValidationPolicy the validation policy to apply to the loaded OpenApi + * @return an OpenApiSpecification instance populated with the document and validation context + */ + public static OpenApiSpecification from(Resource resource, + OpenApiValidationPolicy openApiValidationPolicy) { + OpenApiSpecification specification = new OpenApiSpecification(openApiValidationPolicy); + OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); specification.setOpenApiValidationContext( - OpenApiValidationContextLoader.fromFile(resource)); + OpenApiValidationContextLoader.fromFile(resource, openApiValidationPolicy)); specification.setOpenApiDoc(openApiDoc); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -252,7 +315,7 @@ public static OpenApiSpecification fromString(String openApi) { } public String getUid() { - return uid; + return uid; } public synchronized OasDocument getOpenApiDoc(TestContext context) { @@ -293,20 +356,22 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { } else { initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); setOpenApiValidationContext( - OpenApiValidationContextLoader.fromWebResource(specWebResource)); + OpenApiValidationContextLoader.fromWebResource(specWebResource, + openApiValidationPolicy)); } if (requestUrl == null) { setRequestUrl(format("%s://%s%s%s", specWebResource.getProtocol(), specWebResource.getHost(), specWebResource.getPort() > 0 ? ":" + specWebResource.getPort() : "", - getBasePath(openApiDoc))); + getBasePath(openApiDoc))); } } else { Resource resource = Resources.create(resolvedSpecUrl); initApiDoc(() -> OpenApiResourceLoader.fromFile(resource)); - setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource)); + setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource, + openApiValidationPolicy)); if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -318,7 +383,7 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { setRequestUrl( format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), - getBasePath(openApiDoc))); + getBasePath(openApiDoc))); } } } @@ -389,7 +454,7 @@ private void initPathLookups() { * safely used. * * @param operation The {@link OperationPathAdapter} to store. - * @param pathItem The path item of the operation, including the method. + * @param pathItem The path item of the operation, including the method. */ private void storeOperationPathAdapter(OasOperation operation, OasPathItem pathItem) { @@ -475,10 +540,12 @@ public String getRootContextPath() { /** * Sets the root context path for the OpenAPI integration. *

        - * This path will be prepended to the base path when constructing the full URL path. After setting - * the root context path, the internal path lookups are re-initialized to reflect the updated configuration. + * This path will be prepended to the base path when constructing the full URL path. After + * setting the root context path, the internal path lookups are re-initialized to reflect the + * updated configuration. *

        - *

        Side Effect: Invokes {@link #initPathLookups()} to update internal path mappings based on the new root context path.

        + *

        Side Effect: Invokes {@link #initPathLookups()} to update internal path mappings + * based on the new root context path.

        * * @param rootContextPath the root context path to set * @see #rootContextPath for more details on how this path is used @@ -489,6 +556,10 @@ public void setRootContextPath(String rootContextPath) { initPathLookups(); } + public OpenApiValidationPolicy getOpenApiValidationPolicy() { + return openApiValidationPolicy; + } + public void addAlias(String alias) { aliases.add(alias); } @@ -526,7 +597,7 @@ public Optional getOperation(String operationId, TestConte // This is ugly, but we need not make sure that the openApiDoc is initialized, which might // happen, when instance is created with org.citrusframework.openapi.OpenApiSpecification.from(java.lang.String) - initOpenApiDoc(context); + initOpenApiDoc(context); return Optional.ofNullable(operationIdToOperationPathAdapter.get(operationId)); } @@ -549,8 +620,8 @@ public String getUniqueId(OasOperation oasOperation) { /** * Get the full path for the given {@link OasPathItem}. *

        - * The full path is constructed by concatenating the root context path, the base path (if applicable), - * and the path of the given {@code oasPathItem}. The resulting format is: + * The full path is constructed by concatenating the root context path, the base path (if + * applicable), and the path of the given {@code oasPathItem}. The resulting format is: *

        *
              * /rootContextPath/basePath/pathItemPath
        @@ -558,7 +629,8 @@ public String getUniqueId(OasOperation oasOperation) {
              * If the base path is to be neglected, it is excluded from the final constructed path.
              *
              * @param oasPathItem the OpenAPI path item whose full path is to be constructed
        -     * @return the full URL path, consisting of the root context path, base path, and the given path item
        +     * @return the full URL path, consisting of the root context path, base path, and the given path
        +     * item
              */
             public String getFullPath(OasPathItem oasPathItem) {
                 return appendSegmentToUrlPath(
        @@ -575,7 +647,8 @@ public String getFullPath(OasPathItem oasPathItem) {
              * {@link #neglectBasePath}), only the root context path will be used.
              * 

        * - * @return the full context path, consisting of the root context path and optionally the base path + * @return the full context path, consisting of the root context path and optionally the base + * path * @see #neglectBasePath to understand when the base path is omitted * @see #rootContextPath for the field used as the root context path */ @@ -587,7 +660,8 @@ public String getFullContextPath() { /** * Sets whether the base path should be excluded when constructing the full operation path. * - *

        Side Effect: Invokes {@link #initPathLookups()} to update internal path mappings based on the new root context path.

        + *

        Side Effect: Invokes {@link #initPathLookups()} to update internal path mappings + * based on the new root context path.

        * * @param neglectBasePath {@code true} to exclude the base path, {@code false} to include it * @see #neglectBasePath for the field description diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java index d53817e3dd..9f7c3136d3 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiActionBuilder.java @@ -16,6 +16,9 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.openapi.OpenApiSettings.getOpenApiValidationPolicy; + +import java.net.URL; import org.citrusframework.TestAction; import org.citrusframework.endpoint.Endpoint; import org.citrusframework.exceptions.CitrusRuntimeException; @@ -25,8 +28,6 @@ import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.util.ObjectHelper; -import java.net.URL; - /** * Action executes client and server operations using given OpenApi specification. * Action creates proper request and response data from given specification rules. @@ -69,11 +70,11 @@ public OpenApiActionBuilder specification(OpenApiSpecification specification) { } public OpenApiActionBuilder specification(URL specUrl) { - return specification(OpenApiSpecification.from(specUrl)); + return specification(OpenApiSpecification.from(specUrl, getOpenApiValidationPolicy())); } public OpenApiActionBuilder specification(String specUrl) { - return specification(OpenApiSpecification.from(specUrl)); + return specification(OpenApiSpecification.from(specUrl, getOpenApiValidationPolicy())); } public OpenApiClientActionBuilder client() { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java index f70022ae6c..ceb44ae74e 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java @@ -16,23 +16,45 @@ package org.citrusframework.openapi.validation; +import static java.lang.String.format; +import static java.lang.String.join; +import static java.util.Collections.emptyList; +import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.REPORT; +import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.STRICT; + import com.atlassian.oai.validator.OpenApiInteractionValidator.SpecSource; import com.atlassian.oai.validator.util.OpenApiLoader; +import io.swagger.parser.OpenAPIParser; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.parser.core.models.ParseOptions; +import io.swagger.v3.parser.core.models.SwaggerParseResult; import jakarta.annotation.Nonnull; +import java.net.URL; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.exceptions.ValidationException; import org.citrusframework.openapi.OpenApiResourceLoader; import org.citrusframework.spi.Resource; - -import java.net.URL; - -import static java.util.Collections.emptyList; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Utility class for creation of an {@link OpenApiValidationContext}. */ public final class OpenApiValidationContextLoader { + private static final Logger logger = LoggerFactory.getLogger( + OpenApiValidationContextLoader.class); + + /** + * Cache for APIS which validation errors have already been logged. Used to avoid multiple + * validation error logging for the same api. + */ + private static final Set apisWithLoggedValidationErrors = new HashSet<>(); + private OpenApiValidationContextLoader() { // Static access only } @@ -44,7 +66,9 @@ private OpenApiValidationContextLoader() { * @return the OpenApiValidationContext */ public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), emptyList(), defaultParseOptions())); + return createValidationContext(new OpenApiLoader().loadApi( + SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), emptyList(), + defaultParseOptions())); } /** @@ -53,28 +77,112 @@ public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) * @param url the URL of the OpenAPI web resource * @return the OpenApiValidationContext */ - public static OpenApiValidationContext fromWebResource(@Nonnull URL url) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), emptyList(), defaultParseOptions())); + public static OpenApiValidationContext fromWebResource(@Nonnull URL url, + OpenApiValidationPolicy openApiValidationPolicy) { + return createValidationContext( + loadOpenApi(url.toString(), + SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), + openApiValidationPolicy)); } /** * Creates an OpenApiValidationContext from an OpenAPI file. * - * @param resource the file resource containing the OpenAPI specification + * @param resource the resource containing the OpenAPI specification + * @param openApiValidationPolicy the policy used for validation of the OpenApi * @return the OpenApiValidationContext */ - public static OpenApiValidationContext fromFile(@Nonnull Resource resource) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), emptyList(), defaultParseOptions())); + public static OpenApiValidationContext fromFile(@Nonnull Resource resource, + OpenApiValidationPolicy openApiValidationPolicy) { + return createValidationContext( + loadOpenApi(resource.getLocation(), + SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), + openApiValidationPolicy)); + } + + private static OpenAPI loadOpenApi(String identifier, SpecSource specSource, + OpenApiValidationPolicy openApiValidationPolicy) { + + logger.debug("Loading OpenApi: {}", identifier); + + OpenAPIParser openAPIParser = new OpenAPIParser(); + + SwaggerParseResult swaggerParseResult; + if (specSource.isInlineSpecification()) { + swaggerParseResult = openAPIParser.readContents(specSource.getValue(), emptyList(), + defaultParseOptions()); + } else if (specSource.isSpecUrl()) { + swaggerParseResult = openAPIParser.readLocation(specSource.getValue(), emptyList(), + defaultParseOptions()); + } else { + // Try to load as a URL first... + swaggerParseResult = openAPIParser.readLocation(specSource.getValue(), emptyList(), + defaultParseOptions()); + if (swaggerParseResult == null) { + // ...then try to load as a content string + swaggerParseResult = openAPIParser.readContents(specSource.getValue(), emptyList(), + defaultParseOptions()); + } + } + + return handleSwaggerParserResult(identifier, swaggerParseResult, openApiValidationPolicy); + } + + private static OpenAPI handleSwaggerParserResult(String identifier, + SwaggerParseResult swaggerParseResult, + OpenApiValidationPolicy openApiValidationPolicy) { + logger.trace("Handling swagger parser result: {}", swaggerParseResult); + + if (swaggerParseResult == null) { + throw new CitrusRuntimeException( + "Unable to parse OpenApi from specSource: " + identifier); + } + + if (hasParseErrors(swaggerParseResult)) { + handleValidationException(identifier, openApiValidationPolicy, + swaggerParseResult.getMessages()); + } + + return swaggerParseResult.getOpenAPI(); + } + + private static boolean hasParseErrors(@Nullable final SwaggerParseResult parseResult) { + if (parseResult == null || parseResult.getOpenAPI() == null) { + return true; + } + return parseResult.getMessages() != null && !parseResult.getMessages().isEmpty(); + } + + private static void handleValidationException(String identifier, + OpenApiValidationPolicy openApiValidationPolicy, List errorMessages) { + if (REPORT.equals(openApiValidationPolicy) + && !apisWithLoggedValidationErrors.contains(identifier)) { + apisWithLoggedValidationErrors.add(identifier); + logger.warn("OpenApi '{}' has validation errors {}", identifier, errorMessages); + } else if (STRICT.equals(openApiValidationPolicy)) { + throw new ValidationException( + format( + """ + The API '%s' has failed STRICT validation: + %s + """, + identifier, + join(",", errorMessages) + ) + ); + } } /** * Creates an OpenApiValidationContext from an open api string. * - * @param resource the file resource containing the OpenAPI specification + * @param openApi the string representation of an OpenAPI * @return the OpenApiValidationContext */ public static OpenApiValidationContext fromString(@Nonnull String openApi) { - return createValidationContext(new OpenApiLoader().loadApi(SpecSource.inline(OpenApiResourceLoader.rawFromString(openApi)), emptyList(), defaultParseOptions())); + return createValidationContext(new OpenApiLoader().loadApi( + SpecSource.inline(OpenApiResourceLoader.rawFromString(openApi)), emptyList(), + defaultParseOptions())); } private static OpenApiValidationContext createValidationContext(OpenAPI openApi) { diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationPolicy.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationPolicy.java new file mode 100644 index 0000000000..878579def2 --- /dev/null +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationPolicy.java @@ -0,0 +1,31 @@ +package org.citrusframework.openapi.validation; + +/** + * Enum that defines the policy for handling OpenAPI validation errors. + * This enum controls the behavior of the system when validation errors are encountered + * during OpenAPI validation, allowing for different levels of strictness. + */ +public enum OpenApiValidationPolicy { + + /** + * No validation will be performed. + * Any validation errors will be ignored, and the system will continue + * without reporting or failing due to OpenAPI validation issues. + */ + IGNORE, + + /** + * Perform validation and report any errors. + * Validation errors will be reported, but the system will continue running. + * This option allows for debugging or monitoring purposes without halting the application. + */ + REPORT, + + /** + * Perform validation and fail if any errors are encountered. + * Validation errors will cause the application to fail startup, + * ensuring that only valid OpenAPI specifications are allowed to proceed. + */ + STRICT, +} + diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index cae6358684..5940039ec4 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -16,15 +16,6 @@ package org.citrusframework.openapi; -import org.citrusframework.spi.Resource; -import org.testng.annotations.Test; - -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.List; -import java.util.Optional; - import static java.util.Collections.singletonList; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; @@ -32,8 +23,18 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; import static org.testng.Assert.assertTrue; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.List; +import java.util.Optional; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; +import org.citrusframework.spi.Resource; +import org.testng.annotations.Test; + public class OpenApiRepositoryTest { private static final String ROOT = "/root"; @@ -42,7 +43,8 @@ public class OpenApiRepositoryTest { public void shouldInitializeOpenApiRepository() { OpenApiRepository openApiRepository = new OpenApiRepository(); openApiRepository.setRootContextPath(ROOT); - openApiRepository.setLocations(singletonList("org/citrusframework/openapi/petstore/petstore**.json")); + openApiRepository.setLocations( + singletonList("org/citrusframework/openapi/petstore/petstore**.json")); openApiRepository.initialize(); List openApiSpecifications = openApiRepository.getOpenApiSpecifications(); @@ -55,11 +57,36 @@ public void shouldInitializeOpenApiRepository() { assertEquals(openApiSpecifications.get(1).getRootContextPath(), ROOT); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(0))); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(1))); assertTrue( - SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); + SampleOpenApiProcessor.processedSpecifications.contains(openApiSpecifications.get(2))); + } + + @Test + public void shouldInitializeFaultyOpenApiRepositoryByDefault() { + OpenApiRepository openApiRepository = new OpenApiRepository(); + openApiRepository.setLocations( + singletonList("org/citrusframework/openapi/faulty/faulty-ping-api.yaml")); + openApiRepository.initialize(); + + List openApiSpecifications = openApiRepository.getOpenApiSpecifications(); + + assertNotNull(openApiSpecifications); + assertEquals(openApiSpecifications.size(), 1); + + assertNotNull(openApiSpecifications.get(0).getOpenApiDoc(null)); + } + + @Test + public void shouldFailOnFaultyOpenApiRepositoryByStrictValidation() { + OpenApiRepository openApiRepository = new OpenApiRepository(); + openApiRepository.setOpenApiValidationPolicy(OpenApiValidationPolicy.STRICT); + openApiRepository.setLocations( + singletonList("org/citrusframework/openapi/faulty/faulty-ping-api.yaml")); + + assertThrows(openApiRepository::initialize); } @Test @@ -116,4 +143,5 @@ public void shouldSetAndProvideProperties() { assertEquals(openApiRepository.getRootContextPath(), "/otherRoot"); assertEquals(openApiRepository.getLocations(), List.of("l3", "l4")); } + } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java index 038739dc77..3adcd29942 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSettingsTest.java @@ -19,16 +19,18 @@ import static org.citrusframework.openapi.OpenApiSettings.GENERATE_OPTIONAL_FIELDS_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.NEGLECT_OPEN_API_BASE_PATH_ENV; import static org.citrusframework.openapi.OpenApiSettings.NEGLECT_OPEN_API_BASE_PATH_PROPERTY; -import static org.citrusframework.openapi.OpenApiSettings.REQUEST_AUTO_FILL_RANDOM_VALUES; +import static org.citrusframework.openapi.OpenApiSettings.OPEN_API_VALIDATION_POLICY_PROPERTY; +import static org.citrusframework.openapi.OpenApiSettings.REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.REQUEST_AUTO_FILL_RANDOM_VALUES_ENV; import static org.citrusframework.openapi.OpenApiSettings.REQUEST_VALIDATION_ENABLED_PROPERTY; -import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_AUTO_FILL_RANDOM_VALUES; +import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY; import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_AUTO_FILL_RANDOM_VALUES_ENV; import static org.citrusframework.openapi.OpenApiSettings.RESPONSE_VALIDATION_ENABLED_PROPERTY; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertFalse; import static org.testng.Assert.assertTrue; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -42,6 +44,7 @@ public class OpenApiSettingsTest { private static final AutoFillType REQUEST_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY = OpenApiSettings.getRequestAutoFillRandomValues(); private static final AutoFillType RESPONSE_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY = OpenApiSettings.getResponseAutoFillRandomValues(); private static final boolean NEGLECT_BASE_PATH_GLOBALLY = OpenApiSettings.isNeglectBasePathGlobally(); + private static final OpenApiValidationPolicy OPEN_API_VALIDATION_POLICY_GLOBALLY = OpenApiSettings.getOpenApiValidationPolicy(); private final EnvironmentVariables environmentVariables = new EnvironmentVariables(); @@ -51,8 +54,9 @@ public void beforeMethod() { System.clearProperty(REQUEST_VALIDATION_ENABLED_PROPERTY); System.clearProperty(RESPONSE_VALIDATION_ENABLED_PROPERTY); System.clearProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY); - System.clearProperty(REQUEST_AUTO_FILL_RANDOM_VALUES); - System.clearProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES); + System.clearProperty(REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY); + System.clearProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY); + System.clearProperty(OPEN_API_VALIDATION_POLICY_PROPERTY); } @AfterMethod @@ -83,10 +87,12 @@ public void afterMethod() throws Exception { System.setProperty(NEGLECT_OPEN_API_BASE_PATH_PROPERTY, "true"); } - System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY, RESPONSE_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY.toString()); - System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY, REQUEST_AUTO_FILL_RANDOM_VALUES_ENABLED_GLOBALLY.toString()); + System.setProperty(OPEN_API_VALIDATION_POLICY_PROPERTY, + OPEN_API_VALIDATION_POLICY_GLOBALLY.toString()); } @Test @@ -224,14 +230,14 @@ public void testNeglectBasePathDisabledByDefault() { @Test public void testRequestAutoFillRandomValuesAllByProperty() throws Exception { environmentVariables.setup(); - System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, "ALL"); + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY, "ALL"); assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.ALL); } @Test public void testRequestAutoFillRandomValuesNoneByProperty() throws Exception { environmentVariables.setup(); - System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES, "NONE"); + System.setProperty(REQUEST_AUTO_FILL_RANDOM_VALUES_PROPERTY, "NONE"); assertEquals(OpenApiSettings.getRequestAutoFillRandomValues(), AutoFillType.NONE); } @@ -252,14 +258,14 @@ public void testRequestAutoFillRandomValuesNoneByEnvVar() throws Exception { @Test public void testResponseAutoFillRandomValuesAllByProperty() throws Exception { environmentVariables.setup(); - System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, "ALL"); + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY, "ALL"); assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.ALL); } @Test public void testResponseAutoFillRandomValuesNoneByProperty() throws Exception { environmentVariables.setup(); - System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES, "NONE"); + System.setProperty(RESPONSE_AUTO_FILL_RANDOM_VALUES_PROPERTY, "NONE"); assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.NONE); } @@ -277,4 +283,30 @@ public void testResponseAutoFillRandomValuesNoneByEnvVar() throws Exception { assertEquals(OpenApiSettings.getResponseAutoFillRandomValues(), AutoFillType.NONE); } + @Test + public void testOpenApiValidationPolicyIgnoreByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(OPEN_API_VALIDATION_POLICY_PROPERTY, "IGNORE"); + assertEquals(OpenApiSettings.getOpenApiValidationPolicy(), OpenApiValidationPolicy.IGNORE); + } + + @Test + public void testOpenApiValidationPolicyStrictByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(OPEN_API_VALIDATION_POLICY_PROPERTY, "STRICT"); + assertEquals(OpenApiSettings.getOpenApiValidationPolicy(), OpenApiValidationPolicy.STRICT); + } + + @Test + public void testOpenApiValidationPolicyReportByProperty() throws Exception { + environmentVariables.setup(); + System.setProperty(OPEN_API_VALIDATION_POLICY_PROPERTY, "REPORT"); + assertEquals(OpenApiSettings.getOpenApiValidationPolicy(), OpenApiValidationPolicy.REPORT); + } + + @Test + public void testOpenApiValidationPolicyReportByDefault() throws Exception { + environmentVariables.setup(); + assertEquals(OpenApiSettings.getOpenApiValidationPolicy(), OpenApiValidationPolicy.REPORT); + } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java index 10f93afabc..9025e528dd 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java @@ -16,7 +16,28 @@ package org.citrusframework.openapi; +import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.IGNORE; +import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.REPORT; +import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.STRICT; +import static org.citrusframework.util.FileUtils.readToString; +import static org.mockito.AdditionalAnswers.returnsFirstArg; +import static org.mockito.Mockito.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; + import io.apicurio.datamodels.openapi.models.OasDocument; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import javax.net.ssl.HttpsURLConnection; import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.http.client.HttpClient; @@ -34,24 +55,6 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import javax.net.ssl.HttpsURLConnection; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Optional; - -import static org.citrusframework.util.FileUtils.readToString; -import static org.mockito.AdditionalAnswers.returnsFirstArg; -import static org.mockito.Mockito.isA; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; - public class OpenApiSpecificationTest { private static final String PING_API_HTTP_URL_STRING = "http://org.citrus.example.com/ping-api.yaml"; @@ -181,6 +184,54 @@ public void shouldInitializeFromResource() { assertPingApi(specification); } + @Test + public void shouldInitializeFaultyFromResource() { + // Given + Resource resource = new ClasspathResource("classpath:org/citrusframework/openapi/faulty/faulty-ping-api.yaml"); + + // When + OpenApiSpecification specification = OpenApiSpecification.from(resource); + + // Then + assertNotNull(specification); + assertEquals(specification.getSpecUrl(), resource.getLocation()); + + assertNotNull(specification.getOpenApiDoc(null)); + } + + @Test + public void shouldFailOnStrictPolicy() { + // Given + Resource resource = new ClasspathResource("classpath:org/citrusframework/openapi/faulty/faulty-ping-api.yaml"); + + // When + assertThrows( () -> OpenApiSpecification.from(resource, STRICT)); + } + + @Test + public void shouldSuccessOnIgnorePolicy() { + // Given + Resource resource = new ClasspathResource("classpath:org/citrusframework/openapi/faulty/faulty-ping-api.yaml"); + + // When + OpenApiSpecification specification = OpenApiSpecification.from(resource, IGNORE); + + // Then + assertNotNull(specification.getOpenApiDoc(null)); + } + + @Test + public void shouldSuccessOnReportPolicy() { + // Given + Resource resource = new ClasspathResource("classpath:org/citrusframework/openapi/faulty/faulty-ping-api.yaml"); + + // When + OpenApiSpecification specification = OpenApiSpecification.from(resource, REPORT); + + // Then + assertNotNull(specification.getOpenApiDoc(null)); + } + @Test public void shouldReturnOpenApiDocWhenInitialized() { //Given diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java index fea4f6c06c..8bdfa20d07 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java @@ -1,5 +1,7 @@ package org.citrusframework.openapi.actions; +import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; + import org.citrusframework.context.TestContext; import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.Message; @@ -9,8 +11,6 @@ import org.testng.Assert; import org.testng.annotations.Test; -import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; - public class OpenApiClientRequestMessageBuilderTest { private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/faulty/faulty-ping-api.yaml b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/faulty/faulty-ping-api.yaml new file mode 100644 index 0000000000..25d8f64694 --- /dev/null +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/faulty/faulty-ping-api.yaml @@ -0,0 +1,422 @@ +openapi: 3.0.1 +info: + title: Ping API + description: 'A simple OpenApi defining that contains errors according to OpenApi Specification. In this case - Responses without description.' + version: 1.0 + +servers: + - url: http://localhost:9000/services/rest/ping/v1 + - url: http://localhost:9000/ping/v1 + +paths: + /ping/{id}: + put: + tags: + - ping + summary: Do the ping + operationId: doPing + parameters: + - name: id + in: path + description: Id to ping + required: true + schema: + type: integer + format: int64 + - name: q1 + in: query + description: Some queryParameter + required: true + schema: + type: integer + format: int64 + - name: api-key + in: header + description: Some header + required: true + schema: + type: string + requestBody: + description: Ping data + content: + application/json: + schema: + $ref: '#/components/schemas/PingReqType' + required: true + responses: + 200: + headers: + ping-time: + required: false + description: response time + schema: + type: integer + format: int64 + content: + application/json: + schema: + $ref: '#/components/schemas/PingRespType' + plain/text: + schema: + type: string + 405: + content: + text/plain: + schema: + type: string +components: + schemas: + DateType: + required: + - date + type: object + properties: + date: + type: string + format: date + DateTimeType: + required: + - dateTime + type: object + properties: + dateTime: + type: string + format: date-time + AllOfType: + allOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + AnyOfType: + anyOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + OneOfType: + oneOf: + - $ref: '#/components/schemas/NumbersType' + - $ref: '#/components/schemas/StringsType' + - $ref: '#/components/schemas/MultipleOfType' + - $ref: '#/components/schemas/DatesType' + discriminator: + propertyName: type + mapping: + NumbersType: '#/components/schemas/NumbersType' + StringsType: '#/components/schemas/StringsType' + MultipleOfType: '#/components/schemas/MultipleOfType' + DatesType: '#/components/schemas/DatesType' + MultipleOfType: + type: object + required: + - type + - manyPi + - even + properties: + type: + type: string + enum: [ MultipleOfType ] + manyPi: + type: number + format: double + multipleOf: 3.14159 + minimum: 0 + maximum: 31459 + even: + type: integer + format: int32 + multipleOf: 2 + minimum: -2000 + maximum: 2000 + StringsType: + type: object + required: + - type + properties: + type: + type: string + enum: [ StringsType ] + smallString: + type: string + minLength: 0 + maxLength: 10 + mediumString: + type: string + minLength: 0 + maxLength: 256 + largeString: + type: string + minLength: 0 + maxLength: 1024 + nonEmptyString: + type: string + minLength: 256 + maxLength: 512 + NumbersType: + type: object + required: + - type + - integerInt32 + - integerInt64 + - numberFloat + - numberDouble + - positiveIntegerInt32 + - negativeIntegerInt64 + - positiveNumberFloat + - negativeNumberDouble + - betweenIntegerInt32 + - betweenIntegerInt64 + - betweenNumberFloat + - betweenNumberDouble + - betweenIntegerInt32Exclude + - betweenIntegerInt64Exclude + - betweenNumberFloatExclude + - betweenNumberDoubleExclude + properties: + type: + type: string + enum: [ NumbersType ] + integerInt32: + type: integer + format: int32 + integerInt64: + type: integer + format: int64 + numberFloat: + type: number + format: float + numberDouble: + type: number + format: double + positiveIntegerInt32: + type: integer + format: int32 + minimum: 0 + negativeIntegerInt64: + type: integer + format: int64 + maximum: 0 + positiveNumberFloat: + type: number + format: float + minimum: 0 + negativeNumberDouble: + type: number + format: double + maximum: 0 + betweenIntegerInt32: + type: integer + format: int32 + minimum: 2 + maximum: 8 + betweenIntegerInt64: + type: integer + format: int64 + minimum: 2 + maximum: 3 + betweenNumberFloat: + type: number + format: float + minimum: 2 + maximum: 3 + betweenNumberDouble: + type: number + format: double + minimum: 2 + maximum: 3 + betweenIntegerInt32Exclude: + type: integer + format: int32 + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenIntegerInt64Exclude: + type: integer + format: int64 + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenNumberFloatExclude: + type: number + format: float + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + betweenNumberDoubleExclude: + type: number + format: double + minimum: 2 + maximum: 4 + exclusiveMinimum: true + exclusiveMaximum: true + DatesType: + required: + - type + - date + - dateTime + type: object + properties: + type: + type: string + enum: [ DatesType ] + date: + type: string + format: date + dateTime: + type: string + format: date-time + PingReqType: + type: object + properties: + id: + type: integer + format: int64 + Detail1: + type: object + required: + - type + properties: + type: + type: string + enum: [ Detail1Type ] + allTypes: + $ref: '#/components/schemas/NumbersType' + Detail2: + type: object + required: + - type + properties: + type: + type: string + enum: [ Detail2Type ] + allString: + $ref: '#/components/schemas/StringsType' + allDates: + $ref: '#/components/schemas/DatesType' + PingRespType: + type: object + required: + - type + properties: + type: + type: string + enum: [ PingRespType ] + id: + type: integer + format: int64 + value: + type: string + other: + anyOf: + - $ref: '#/components/schemas/Detail1' + - $ref: '#/components/schemas/Detail2' + discriminator: + propertyName: type + mapping: + Detail1Type: '#/components/schemas/Detail1' + Detail2Type: '#/components/schemas/Detail2' + BooleanType: + type: object + required: + - isActive + - isVerified + properties: + isActive: + type: boolean + isVerified: + type: boolean + EnumType: + type: object + required: + - status + properties: + status: + type: string + enum: + - ACTIVE + - INACTIVE + - PENDING + NestedType: + type: object + properties: + id: + type: integer + format: int64 + details: + $ref: '#/components/schemas/Detail1' + SimpleArrayType: + type: object + properties: + stringItems: + type: array + items: + type: string + minLength: 2 + maxLength: 5 + minItems: 10 + maxItems: 20 + numberItems: + type: array + items: + type: integer + minItems: 10 + maxItems: 20 + booleanItems: + type: array + items: + type: boolean + dateItems: + type: array + items: + type: string + format: date + ComplexArrayType: + type: object + properties: + stringItems: + type: array + items: + $ref: '#/components/schemas/StringsType' + numberItems: + type: array + items: + $ref: '#/components/schemas/NumbersType' + ArrayOfArraysType: + type: object + properties: + matrix: + type: array + items: + type: array + items: + type: integer + NullableType: + type: object + properties: + nullableString: + type: string + nullable: true + DefaultValueType: + type: object + properties: + defaultValue: + type: string + default: "defaultValue" \ No newline at end of file From 0a263e7c6cff90709dcc68cc729e657b96937d79 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Thu, 12 Dec 2024 07:44:36 +0100 Subject: [PATCH 38/47] chore: fix test errors --- .../openapi/generator/GeneratedRestApiIT.java | 58 +++++++++++-------- .../withFormUrlEncodedTest.xml | 2 +- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java index 7f1e6f2171..7dc844405e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -56,7 +56,6 @@ import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdReceiveActionBuilder; import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration; import org.citrusframework.openapi.testapi.ApiActionBuilderCustomizer; -import org.citrusframework.openapi.testapi.GeneratedApi; import org.citrusframework.openapi.testapi.GeneratedApiOperationInfo; import org.citrusframework.spi.Resources; import org.citrusframework.validation.json.JsonPathVariableExtractor; @@ -227,14 +226,16 @@ public ApiActionBuilderCustomizer petApiCustomizer() { @Override public > void customizeRequestBuilder( GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { - ApiActionBuilderCustomizer.super.customizeRequestBuilder(generatedApiOperationInfo, + ApiActionBuilderCustomizer.super.customizeRequestBuilder( + generatedApiOperationInfo, builder); } @Override public > void customizeResponseBuilder( GeneratedApiOperationInfo generatedApiOperationInfo, T builder) { - ApiActionBuilderCustomizer.super.customizeResponseBuilder(generatedApiOperationInfo, + ApiActionBuilderCustomizer.super.customizeResponseBuilder( + generatedApiOperationInfo, builder); } @@ -2925,16 +2926,21 @@ void java(@CitrusResource TestCaseRunner runner) { .message() .contentType(APPLICATION_FORM_URLENCODED_VALUE) .validate((Message message, TestContext context) -> - assertThat(message.getPayload(String.class)) - .contains("name=Thunder") - .contains("status=sold") - .contains("nicknames=Wind") - .contains("nicknames=Storm") - .contains("tags=tag2") - .contains("tags=tag2Value") - .contains("age=5") - .contains( - "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + { + Object messagePayload = message.getPayload(); + assertThat(messagePayload).isInstanceOf(Map.class); + //noinspection unchecked + assertThat( + (Map>) messagePayload).containsExactlyInAnyOrderEntriesOf( + Map.of( + "tags", List.of("tag1", "tag2Value"), + "nicknames", List.of("Wind", "Storm", + "Wei%7B%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29*%2B%2C%3B%3D%25%22%3C%3E%5E%60%7B%7C%7D%7E+%7Drd"), + "status", List.of("sold"), + "age", List.of("5"), + "owners", List.of("2"), + "name", List.of("Thunder"))); + } )); runner.then(http().server(httpServer) @@ -2976,17 +2982,21 @@ void java(@CitrusResource TestCaseRunner runner) { .put("/api/v3/ext/pet/form/1234") .message() .contentType(APPLICATION_FORM_URLENCODED_VALUE) - .validate((Message message, TestContext context) -> - assertThat(message.getPayload(String.class)) - .contains("name=Thunder") - .contains("status=sold") - .contains("nicknames=Wind") - .contains("nicknames=Storm") - .contains("tags=tag2") - .contains("tags=tag2Value") - .contains("age=5") - .contains( - "nicknames=Wei%257B%253A%252F%253F%2523%255B%255D%2540%2521%2524%2526%2527%2528%2529*%252B%252C%253B%253D%2525%2522%253C%253E%255E%2560%257B%257C%257D%257E%2B%257Drd") + .validate((Message message, TestContext context) -> { + Object messagePayload = message.getPayload(); + assertThat(messagePayload).isInstanceOf(Map.class); + //noinspection unchecked + assertThat( + (Map>) messagePayload).containsExactlyInAnyOrderEntriesOf( + Map.of( + "tags", List.of("tag1", "tag2Value"), + "nicknames", List.of("Wind", "Storm", + "Wei%7B%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29*%2B%2C%3B%3D%25%22%3C%3E%5E%60%7B%7C%7D%7E+%7Drd"), + "status", List.of("sold"), + "age", List.of("5"), + "owners", List.of("2"), + "name", List.of("Thunder"))); + } )); runner.then(http().server(httpServer) diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml index c1bef35959..b0957d3149 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withFormUrlEncodedTest.xml @@ -32,7 +32,7 @@ - + From 78d7ee729b8604c2e8046ac22b88de614150e9c3 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Fri, 13 Dec 2024 12:25:33 +0100 Subject: [PATCH 39/47] fix: accept only json and plain text for random message generation --- .../OpenApiServerResponseActionBuilder.java | 21 ++++--- .../openapi/model/OasModelHelper.java | 52 +++++++++++++-- .../openapi/model/v2/Oas20ModelHelper.java | 2 +- .../openapi/model/v3/Oas30ModelHelper.java | 2 +- .../openapi/model/OasModelHelperTest.java | 63 +++++++++++++++++++ 5 files changed, 122 insertions(+), 18 deletions(-) create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OasModelHelperTest.java diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java index e3b8f9ba25..99a304a62a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java @@ -17,7 +17,6 @@ package org.citrusframework.openapi.actions; import static java.lang.Integer.parseInt; -import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE; import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload; @@ -259,12 +258,11 @@ private void buildRandomPayload(OpenApiSpecification openApiSpecification, Optional> schemaForMediaTypeOptional; if (statusCode.startsWith("2")) { // if status code is good, and we have an accept, try to get the media type. Note that only json and plain text can be generated randomly. - schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, - accept != null ? singletonList(accept) : null); + schemaForMediaTypeOptional = OasModelHelper.getRandomizableSchema(operation, response, accept); } else { // In the bad case, we cannot expect, that the accept type is the type which we must generate. // We request the type supported by the response and the random generator (json and plain text). - schemaForMediaTypeOptional = OasModelHelper.getSchema(operation, response, null); + schemaForMediaTypeOptional = OasModelHelper.getRandomizableSchema(operation, response, null); } if (schemaForMediaTypeOptional.isPresent()) { @@ -292,16 +290,19 @@ private void createRandomPayload(HttpMessage message, // No schema means no payload, no type message.setPayload(null); } else { - if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { - // Schema but plain text - message.setPayload( - createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); - message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); - } else if (APPLICATION_JSON_VALUE.equals(schemaForMediaType.adapted())) { + String mediaTypeName = schemaForMediaType.adapted(); + + // Support any json for now. Especially: application/json, application/json;charset=UTF-8 + if (mediaTypeName.toUpperCase().contains("JSON")) { // Json Schema message.setPayload( createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, APPLICATION_JSON_VALUE); + } else if (TEXT_PLAIN_VALUE.equals(schemaForMediaType.adapted())) { + // Schema but plain text + message.setPayload( + createOutboundPayload(schemaForMediaType.node(), openApiSpecification)); + message.setHeader(HttpMessageHeaders.HTTP_CONTENT_TYPE, TEXT_PLAIN_VALUE); } } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java index 99dba6a7c4..5262bb7caf 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/OasModelHelper.java @@ -18,9 +18,9 @@ import static java.lang.String.format; import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; import static org.citrusframework.openapi.OpenApiConstants.TYPE_ARRAY; import static org.citrusframework.openapi.OpenApiConstants.TYPE_OBJECT; +import static org.citrusframework.util.StringUtils.hasText; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE; @@ -52,6 +52,7 @@ import io.apicurio.datamodels.openapi.v3.visitors.Oas30Traverser; import io.apicurio.datamodels.openapi.visitors.OasTraverser; import jakarta.annotation.Nullable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; @@ -244,6 +245,18 @@ public static Optional> getSchema(OasOperation oas throw new IllegalArgumentException(format("Unsupported operation response type: %s", response.getClass())); } + public static Optional> getRandomizableSchema(OasOperation oasOperation, OasResponse response, String acceptedMediaTypes) { + List acceptedRandomizableMediaTypes = OasModelHelper.toAcceptedRandomizableMediaTypes( + acceptedMediaTypes); + + if (oasOperation instanceof Oas20Operation oas20Operation && response instanceof Oas20Response oas20Response) { + return Oas20ModelHelper.getSchema(oas20Operation, oas20Response, acceptedRandomizableMediaTypes); + } else if (oasOperation instanceof Oas30Operation oas30Operation && response instanceof Oas30Response oas30Response) { + return Oas30ModelHelper.getSchema(oas30Operation, oas30Response, acceptedRandomizableMediaTypes); + } + throw new IllegalArgumentException(format("Unsupported operation response type: %s", response.getClass())); + } + public static Optional getParameterSchema(OasParameter parameter) { return delegate(parameter, Oas20ModelHelper::getParameterSchema, Oas30ModelHelper::getParameterSchema); } @@ -302,18 +315,21 @@ public static Optional getResponseForRandomGeneration(OasDocument o return Optional.ofNullable(responseMap.get(statusCode)); } - // Only accept responses that provide a schema for which we can actually provide a random message - Predicate acceptedSchemas = resp -> getSchema(operation, resp, accept != null ? singletonList(accept) : DEFAULT_ACCEPTED_MEDIA_TYPES).isPresent(); - // Fallback 1: Pick the default if it exists Optional response = Optional.ofNullable(responseMap.get(DEFAULT)); if (response.isEmpty()) { // Fallback 2: Pick the response object related to the first 2xx, providing an accepted schema + + // Only accept responses that provide a schema for which we can actually provide a random message. + // That is json and plain/text. We prefer json. + List acceptedMediaTypesForRandomGeneration = toAcceptedRandomizableMediaTypes(accept); + + Predicate acceptableResponseWithRandomizableSchema = resp -> getSchema(operation, resp, acceptedMediaTypesForRandomGeneration).isPresent(); response = responseMap.values().stream() .filter(r -> r.getStatusCode() != null && r.getStatusCode().startsWith("2")) .map(OasResponse.class::cast) - .filter(acceptedSchemas) + .filter(acceptableResponseWithRandomizableSchema) .findFirst(); } @@ -571,7 +587,7 @@ public void visitPathItem(OasPathItem oasPathItem) { */ public static List resolveAllTypes(@Nullable List acceptedMediaTypes) { if (acceptedMediaTypes == null) { - return null; + return emptyList(); } return acceptedMediaTypes.stream() @@ -605,4 +621,28 @@ public static String toJson(OasDocument openApiDoc) { return writer.getResult().toString(); } + /** + * Converts the given accept header value into a list of accepted media types + * that can be used for randomizable content generation. + * + *

        If the accept header is non-empty, the method resolves and filters + * the media types to include only those that contain "json" or "text/plain", as these are the + * only ones we can generate randomly. If the accept header is empty or null, it defaults to a + * predefined list of accepted media types. + * + * @param accept the value of the accept header, specifying preferred media types + * @return a list of media types suitable for randomizable content generation + */ + public static List toAcceptedRandomizableMediaTypes(String accept) { + List acceptedMediaTypesForRandomGeneration = new ArrayList<>(); + if (hasText(accept)) { + List acceptedMediaTypes = OasModelHelper.resolveAllTypes(List.of(accept)); + acceptedMediaTypes.stream().filter(mediaType -> hasText(mediaType) && mediaType.contains("json")).forEach(acceptedMediaTypesForRandomGeneration::add); + acceptedMediaTypes.stream().filter(mediaType -> hasText(mediaType) && mediaType.contains("text/plain")).forEach(acceptedMediaTypesForRandomGeneration::add); + } else { + acceptedMediaTypesForRandomGeneration.addAll(DEFAULT_ACCEPTED_MEDIA_TYPES); + } + return acceptedMediaTypesForRandomGeneration; + } + } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java index 77839fdd93..9a36de2e6a 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v2/Oas20ModelHelper.java @@ -77,7 +77,7 @@ public static Optional getSchema(Oas20Response response) { public static Optional> getSchema(Oas20Operation oas20Operation, Oas20Response response, List acceptedMediaTypes) { acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); - acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; + acceptedMediaTypes = acceptedMediaTypes.isEmpty() ? OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES : acceptedMediaTypes; OasSchema selectedSchema = response.schema; String selectedMediaType = null; diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 2d80b2dbec..413bd617d8 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -137,7 +137,7 @@ public static Optional getSchema(Oas30Response response) { public static Optional> getSchema(Oas30Operation ignoredOas30Operation, Oas30Response response, List acceptedMediaTypes) { acceptedMediaTypes = OasModelHelper.resolveAllTypes(acceptedMediaTypes); - acceptedMediaTypes = acceptedMediaTypes != null ? acceptedMediaTypes : OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES; + acceptedMediaTypes = acceptedMediaTypes.isEmpty() ? OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES : acceptedMediaTypes; Map content = response.content; if (content == null) { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OasModelHelperTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OasModelHelperTest.java new file mode 100644 index 0000000000..8ca57aaf97 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/model/OasModelHelperTest.java @@ -0,0 +1,63 @@ +package org.citrusframework.openapi.model; + +import java.util.List; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class OasModelHelperTest { + + @Test + public void testToAcceptedRandomizableMediaTypes_WithValidAcceptHeader() { + // Given + String accept = "application/json, text/plain, application/xml, application/json;charset=UTF-8"; + + // When + List result = OasModelHelper.toAcceptedRandomizableMediaTypes(accept); + + // Then + Assert.assertNotNull(result, "Result should not be null"); + Assert.assertTrue(result.contains("application/json"), "Result should contain 'application/json'"); + Assert.assertTrue(result.contains("application/json;charset=UTF-8"), "Result should contain 'text/plain'"); + Assert.assertTrue(result.contains("text/plain"), "Result should contain 'text/plain'"); + Assert.assertFalse(result.contains("application/xml"), "Result should not contain 'application/xml'"); + } + + @Test + public void testToAcceptedRandomizableMediaTypes_WithEmptyAcceptHeader() { + // Given + String accept = ""; + + // When + List result = OasModelHelper.toAcceptedRandomizableMediaTypes(accept); + + // Then + Assert.assertNotNull(result, "Result should not be null"); + Assert.assertEquals(result, OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES, "Should return the default media types"); + } + + @Test + public void testToAcceptedRandomizableMediaTypes_WithNullAcceptHeader() { + // Given + String accept = null; + + // When + List result = OasModelHelper.toAcceptedRandomizableMediaTypes(accept); + + // Then + Assert.assertNotNull(result, "Result should not be null"); + Assert.assertEquals(result, OasModelHelper.DEFAULT_ACCEPTED_MEDIA_TYPES, "Should return the default media types"); + } + + @Test + public void testToAcceptedRandomizableMediaTypes_WithUnrelatedMediaTypes() { + // Given + String accept = "image/png, application/xml"; + + // When + List result = OasModelHelper.toAcceptedRandomizableMediaTypes(accept); + + // Then + Assert.assertNotNull(result, "Result should not be null"); + Assert.assertTrue(result.isEmpty(), "Result should be empty for unrelated media types"); + } +} From 36bef5b384ead808d5ef05944a0eedb03bef973e Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Wed, 8 Jan 2025 15:01:26 +0100 Subject: [PATCH 40/47] fix: adjust paths for code generation according to CodeGenMojo Use: - generated-(test)-sources/openapi/src/main/java - generated-(test)-sources/openapi/src/main/resources - generated-(test)-sources/openapi/src/main/resources/META-INF (as default for spring artefacts) --- .../citrus-test-api-generator-core/pom.xml | 4 +- .../openapi/generator/CitrusJavaCodegen.java | 284 +++++++++--------- .../generator/CitrusJavaCodegenTest.java | 39 ++- .../pom.xml | 34 ++- .../maven/plugin/CodeGenMojoWrapper.java | 111 +++++-- .../maven/plugin/SpringMetaFileGenerator.java | 37 ++- .../maven/plugin/TestApiGeneratorMojo.java | 94 +++--- .../plugin/SpringMetaFileGeneratorTest.java | 2 +- .../TestApiGeneratorMojoIntegrationTest.java | 43 ++- .../plugin/TestApiGeneratorMojoUnitTest.java | 65 ++-- .../pom-full-config.xml | 8 +- .../pom-full-with-version-config.xml | 7 +- 12 files changed, 445 insertions(+), 283 deletions(-) diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index 5ea32baa45..7cc54e0ea1 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.5.0-SNAPSHOT + 4.5.0-PF-RC3 ../pom.xml @@ -154,7 +154,7 @@ openapi-generator ${org.openapitools.version} - Java/*Annotation*.mustache,Java/*Model*.mustache,Java/model*.mustache,Java/pojo*.mustache,Java/enum_outer_doc.mustache + Java/*Annotation*.mustache,Java/*Model*.mustache,Java/model*.mustache,Java/pojo*.mustache,Java/enum_outer_doc.mustache,Java/nullable_var_annotations.mustache diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java index e636b8e47f..4da01c693e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java @@ -67,16 +67,11 @@ public class CitrusJavaCodegen extends AbstractJavaCodegen { /** * The root context path used as prefix to the OpenAPI paths. Note that this need to be - * explicitly be defined by configuration and may differ from any server node that may - * be specified in the OpenAPI. + * explicitly be defined by configuration and may differ from any server node that may be + * specified in the OpenAPI. */ public static final String ROOT_CONTEXT_PATH = "rootContextPath"; - /** - * Property to indicate, that the base path must be neglected when building the full path for an operation. - */ - public static final String NEGLECT_BASE_PATH = "neglectBasePath"; - public static final String CODEGEN_NAME = "java-citrus"; public static final String API_TYPE_REST = "REST"; public static final String API_TYPE_SOAP = "SOAP"; @@ -85,7 +80,6 @@ public class CitrusJavaCodegen extends AbstractJavaCodegen { public static final String GENERATED_SCHEMA_FOLDER = "generatedSchemaFolder"; public static final String PREFIX = "prefix"; public static final String RESOURCE_FOLDER = "resourceFolder"; - public static final String SOURCE_FOLDER = "sourceFolder"; public static final String TARGET_XMLNS_NAMESPACE = "targetXmlnsNamespace"; public static final String REQUEST_BUILDER_CLASS = "requestBuilderClass"; public static final String RESPONSE_BUILDER_CLASS = "responseBuilderClass"; @@ -96,14 +90,12 @@ public class CitrusJavaCodegen extends AbstractJavaCodegen { protected String httpClient = API_ENDPOINT; - protected String resourceFolder = "src" + File.separator + "main" + File.separator + "resources"; + protected String resourceFolder = projectFolder + "/resources"; + protected String generatedSchemaFolder = "schema" + File.separator + "xsd"; protected String targetXmlnsNamespace; protected String apiVersion = "1.0.0"; - private String invokerFolder; - private String springFolder; - private String schemaFolder; public CitrusJavaCodegen() { super(); @@ -116,9 +108,10 @@ public CitrusJavaCodegen() { configureTypeMappings(); } - private static void postProcessSecurityParameters(CustomCodegenOperation customCodegenOperation) { + private static void postProcessSecurityParameters( + CustomCodegenOperation customCodegenOperation) { customCodegenOperation.hasApiKeyAuth = customCodegenOperation.authMethods.stream() - .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); + .anyMatch(codegenSecurity -> codegenSecurity.isApiKey); customCodegenOperation.authWithParameters = customCodegenOperation.hasApiKeyAuth; for (CodegenSecurity codegenSecurity : customCodegenOperation.authMethods) { @@ -127,7 +120,8 @@ private static void postProcessSecurityParameters(CustomCodegenOperation customC customCodegenOperation.optionalAndAuthParameterNames.add("basicAuthPassword"); customCodegenOperation.authWithParameters = true; } else if (TRUE.equals(codegenSecurity.isApiKey)) { - customCodegenOperation.optionalAndAuthParameterNames.add(camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); + customCodegenOperation.optionalAndAuthParameterNames.add( + camelize(codegenSecurity.keyParamName, LOWERCASE_FIRST_LETTER)); customCodegenOperation.authWithParameters = true; } else if (TRUE.equals(codegenSecurity.isBasicBearer)) { customCodegenOperation.optionalAndAuthParameterNames.add("basicAuthBearer"); @@ -180,30 +174,6 @@ public void setApiVersion(String apiVersion) { this.apiVersion = apiVersion; } - public String getInvokerFolder() { - return invokerFolder; - } - - public void setInvokerFolder(String invokerFolder) { - this.invokerFolder = invokerFolder; - } - - public String getSpringFolder() { - return springFolder; - } - - public void setSpringFolder(String springFolder) { - this.springFolder = springFolder; - } - - public String getSchemaFolder() { - return schemaFolder; - } - - public void setSchemaFolder(String schemaFolder) { - this.schemaFolder = schemaFolder; - } - private void configureAdditionalProperties() { additionalProperties.put("apiVersion", apiVersion); additionalProperties.put(API_TYPE, API_TYPE_REST); @@ -213,51 +183,51 @@ private void configureAdditionalProperties() { private void configureReservedWords() { Set reservedWordsTemp = reservedWords(); reservedWordsTemp.addAll( - asList( - "name", - "description", - "httpClient", - "message", - "endpoint", - "validate", - "validator", - "validators", - "process", - "selector", - "transform", - "build", - "actor", - "process") + asList( + "name", + "description", + "httpClient", + "message", + "endpoint", + "validate", + "validator", + "validators", + "process", + "selector", + "transform", + "build", + "actor", + "process") ); setReservedWordsLowerCase(new ArrayList<>(reservedWordsTemp)); } private void configureCliOptions() { cliOptions.add( - newString(API_ENDPOINT, - "Which http client should be used (default " + httpClient + ").")); + newString(API_ENDPOINT, + "Which http client should be used (default " + httpClient + ").")); cliOptions.add( - newString(API_TYPE, - "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" - ) + newString(API_TYPE, + "Specifies the type of API to be generated specify SOAP to generate a SOAP API. By default a REST API will be generated" + ) ); cliOptions.add( - newString(GENERATED_SCHEMA_FOLDER, - "The schema output directory (default " + generatedSchemaFolder + ").") + newString(GENERATED_SCHEMA_FOLDER, + "The schema output directory (default " + generatedSchemaFolder + ").") ); cliOptions.add( - newString(PREFIX, - "Add a prefix before the name of the files. First character should be upper case (default " - + apiPrefix + ")." - ) + newString(PREFIX, + "Add a prefix before the name of the files. First character should be upper case (default " + + apiPrefix + ")." + ) ); cliOptions.add(newString(PREFIX, "The api prefix (default " + apiPrefix + ").")); cliOptions.add( - newString(RESOURCE_FOLDER, - "Where the resource files are emitted (default " + resourceFolder + ").")); + newString(RESOURCE_FOLDER, + "Where the resource files are emitted (default " + resourceFolder + ").")); cliOptions.add( - newString(TARGET_XMLNS_NAMESPACE, - "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") + newString(TARGET_XMLNS_NAMESPACE, + "Xmlns namespace of the schema (default " + targetXmlnsNamespace + ").") ); } @@ -278,8 +248,8 @@ public String getHelp() { } /** - * Configures a human-friendly name for the generator. This will be used by the generator to select - * the library with the -g flag. + * Configures a human-friendly name for the generator. This will be used by the generator to + * select the library with the -g flag. * * @return the human-friendly name for the generator */ @@ -320,13 +290,13 @@ private void setupEndpoint() { private void setupApiPrefix() { if (additionalProperties.containsKey(PREFIX)) { - apiPrefix = additionalProperties.get(PREFIX).toString(); + apiPrefix = additionalProperties.get(PREFIX).toString(); additionalProperties.put(PREFIX, apiPrefix); additionalProperties.put(PREFIX + "LowerCase", apiPrefix.toLowerCase()); } else { logger.warn( - "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", - PREFIX); + "Using empty prefix for code generation. A prefix can be configured using \"{}\" property.", + PREFIX); apiPrefix = ""; } } @@ -334,11 +304,11 @@ private void setupApiPrefix() { private void setupNamespace() { if (additionalProperties.containsKey(TARGET_XMLNS_NAMESPACE)) { this.setTargetXmlnsNamespace( - additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); + additionalProperties.get(TARGET_XMLNS_NAMESPACE).toString()); } else { this.targetXmlnsNamespace = format( - "http://www.citrusframework.org/citrus-test-schema/%s-api", - apiPrefix.toLowerCase()); + "http://www.citrusframework.org/citrus-test-schema/%s-api", + apiPrefix.toLowerCase()); } additionalProperties.put(TARGET_XMLNS_NAMESPACE, targetXmlnsNamespace); } @@ -346,7 +316,7 @@ private void setupNamespace() { private void setupFolders() { if (additionalProperties.containsKey(GENERATED_SCHEMA_FOLDER)) { this.setGeneratedSchemaFolder( - additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); + additionalProperties.get(GENERATED_SCHEMA_FOLDER).toString()); } additionalProperties.put(GENERATED_SCHEMA_FOLDER, generatedSchemaFolder); @@ -355,49 +325,56 @@ private void setupFolders() { } additionalProperties.put(RESOURCE_FOLDER, resourceFolder); - invokerFolder = (sourceFolder + File.separator + invokerPackage).replace(".", File.separator); - springFolder = invokerFolder + File.separator + "spring"; - schemaFolder = resourceFolder + File.separator + generatedSchemaFolder; } private void setupApiType() { Object apiType = additionalProperties.get(API_TYPE); if (API_TYPE_REST.equals(apiType)) { - setupRestApiType(springFolder, schemaFolder); + setupRestApiType(); } else if (API_TYPE_SOAP.equals(apiType)) { - setupSoapApiType(springFolder, schemaFolder); + setupSoapApiType(); } else { throw new IllegalArgumentException(format("Unknown API_TYPE: '%s'", apiType)); } } - private void setupSoapApiType(String springFolder, String schemaFolder) { - additionalProperties.put(REQUEST_BUILDER_CLASS, SoapApiSendMessageActionBuilder.class.getName()); - additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, SoapApiSendMessageActionBuilder.class.getSimpleName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS, SoapApiReceiveMessageActionBuilder.class.getName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, SoapApiReceiveMessageActionBuilder.class.getSimpleName()); + private void setupSoapApiType() { + additionalProperties.put(REQUEST_BUILDER_CLASS, + SoapApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, + SoapApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, + SoapApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, + SoapApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", false); additionalProperties.put("isSoap", true); - addSoapSupportingFiles(springFolder, schemaFolder); - } - - private void setupRestApiType(String springFolder, String schemaFolder) { - additionalProperties.put(REQUEST_BUILDER_CLASS, RestApiSendMessageActionBuilder.class.getName()); - additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, RestApiSendMessageActionBuilder.class.getSimpleName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS, RestApiReceiveMessageActionBuilder.class.getName()); - additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, RestApiReceiveMessageActionBuilder.class.getSimpleName()); + addSoapSupportingFiles(); + } + + private void setupRestApiType() { + additionalProperties.put(REQUEST_BUILDER_CLASS, + RestApiSendMessageActionBuilder.class.getName()); + additionalProperties.put(REQUEST_BUILDER_CLASS_NAME, + RestApiSendMessageActionBuilder.class.getSimpleName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS, + RestApiReceiveMessageActionBuilder.class.getName()); + additionalProperties.put(RESPONSE_BUILDER_CLASS_NAME, + RestApiReceiveMessageActionBuilder.class.getSimpleName()); additionalProperties.put("isRest", true); additionalProperties.put("isSoap", false); - addRestSupportingFiles(springFolder, schemaFolder); + addRestSupportingFiles(); } /** - * Save a copy of the source OpenAPI as a resource, allowing it to be registered as an OpenAPI repository. + * Save a copy of the source OpenAPI as a resource, allowing it to be registered as an OpenAPI + * repository. */ private void writeApiToResourceFolder() { String directoryPath = appendSegmentToUrlPath(getOutputDir(), getResourceFolder()); - directoryPath = appendSegmentToUrlPath(directoryPath, invokerPackage.replace('.', File.separatorChar)); + directoryPath = appendSegmentToUrlPath(directoryPath, + invokerPackage.replace('.', File.separatorChar)); String filename = getApiPrefix() + "_openApi.yaml"; @@ -413,7 +390,7 @@ private void writeApiToResourceFolder() { writer.write(yamlContent); } catch (IOException e) { throw new CitrusRuntimeException( - "Unable to write OpenAPI to resource folder: " + file.getAbsolutePath()); + "Unable to write OpenAPI to resource folder: " + file.getAbsolutePath()); } } @@ -427,45 +404,47 @@ public void preprocessOpenAPI(OpenAPI openAPI) { additionalProperties.putAll(extensions); Map infoExtensions = extensions.entrySet().stream() - .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) - .collect(toMap(Entry::getKey, Entry::getValue)); + .filter(entry -> entry.getKey().toUpperCase().startsWith("X-")) + .collect(toMap(Entry::getKey, Entry::getValue)); additionalProperties.put("infoExtensions", infoExtensions); } } - private void addRestSupportingFiles(String springFolder, String schemaFolder) { - supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder, - convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); - supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); + private void addRestSupportingFiles() { + supportingFiles.add(new SupportingFile("namespace_handler.mustache", springFolder(), + convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder(), + apiPrefix.toLowerCase() + "-api.xsd")); } - private void addSoapSupportingFiles(String springFolder, String schemaFolder) { + private void addSoapSupportingFiles() { // Remove the default api template file apiTemplateFiles().remove("api.mustache"); apiTemplateFiles().put("api_soap.mustache", ".java"); - supportingFiles.add(new SupportingFile("namespace_handler_soap.mustache", springFolder, - convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); - supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder, - apiPrefix.toLowerCase() + "-api.xsd")); + supportingFiles.add(new SupportingFile("namespace_handler_soap.mustache", springFolder(), + convertFirstChartToUpperCase(apiPrefix) + "NamespaceHandler.java")); + supportingFiles.add(new SupportingFile("schema_soap.mustache", schemaFolder(), + apiPrefix.toLowerCase() + "-api.xsd")); } private void addDefaultSupportingFiles() { - supportingFiles.add(new SupportingFile("api_locator.mustache", invokerFolder, - convertFirstChartToUpperCase(apiPrefix) + "OpenApi.java")); - supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder, - convertFirstChartToUpperCase(apiPrefix) + "BeanConfiguration.java")); + supportingFiles.add(new SupportingFile("api_locator.mustache", invokerFolder(), + convertFirstChartToUpperCase(apiPrefix) + "OpenApi.java")); + supportingFiles.add(new SupportingFile("bean_configuration.mustache", springFolder(), + convertFirstChartToUpperCase(apiPrefix) + "BeanConfiguration.java")); } @Override - public CodegenParameter fromRequestBody(RequestBody body, Set imports, String bodyParameterName) { + public CodegenParameter fromRequestBody(RequestBody body, Set imports, + String bodyParameterName) { CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); return convertToCustomCodegenParameter(codegenParameter); } @Override - public CodegenParameter fromFormProperty(String name, Schema propertySchema, Set imports) { + public CodegenParameter fromFormProperty(String name, Schema propertySchema, + Set imports) { CodegenParameter codegenParameter = super.fromFormProperty(name, propertySchema, imports); return convertToCustomCodegenParameter(codegenParameter); } @@ -485,20 +464,22 @@ public CodegenParameter fromParameter(Parameter parameter, Set imports) * Converts given codegenParameter to a custom {@link CustomCodegenParameter} to provide * additional derived properties. */ - private CustomCodegenParameter convertToCustomCodegenParameter(CodegenParameter codegenParameter) { + private CustomCodegenParameter convertToCustomCodegenParameter( + CodegenParameter codegenParameter) { CustomCodegenParameter customCodegenParameter = new CustomCodegenParameter(); copyFields(CodegenParameter.class, codegenParameter, customCodegenParameter); - customCodegenParameter.isBaseTypeString = codegenParameter.isString || "String".equals(codegenParameter.baseType); + customCodegenParameter.isBaseTypeString = + codegenParameter.isString || "String".equals(codegenParameter.baseType); return customCodegenParameter; } @Override public CodegenOperation fromOperation(String path, - String httpMethod, - Operation operation, - List servers) { + String httpMethod, + Operation operation, + List servers) { CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers); return convertToCustomCodegenOperation(op); } @@ -507,33 +488,35 @@ public CodegenOperation fromOperation(String path, * Converts given codegenOperation to a custom {@link CustomCodegenOperation} to provide * additional derived properties. */ - private CustomCodegenOperation convertToCustomCodegenOperation(CodegenOperation codegenOperation) { + private CustomCodegenOperation convertToCustomCodegenOperation( + CodegenOperation codegenOperation) { CustomCodegenOperation customOperation = new CustomCodegenOperation(); copyFields(CodegenOperation.class, codegenOperation, customOperation); customOperation.requiredNonBodyParams.addAll(customOperation.requiredParams - .stream() - .filter(param -> !param.isBodyParam).toList()); + .stream() + .filter(param -> !param.isBodyParam).toList()); customOperation.needsConstructorWithAllStringParameter = - !customOperation.requiredParams.isEmpty() && - customOperation.requiredParams - .stream() - .anyMatch(param -> !param.isBodyParam && !"String".equals(param.dataType)); + !customOperation.requiredParams.isEmpty() && + customOperation.requiredParams + .stream() + .anyMatch(param -> !param.isBodyParam && !"String".equals(param.dataType)); if (customOperation.optionalParams != null) { customOperation.optionalAndAuthParameterNames.addAll( - customOperation.optionalParams.stream() - .map(codegenParameter -> toVarName(codegenParameter.nameInCamelCase)) - .toList()); + customOperation.optionalParams.stream() + .map(codegenParameter -> toVarName(codegenParameter.nameInCamelCase)) + .toList()); } return customOperation; } @Override - public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, + List allModels) { OperationsMap operationsMap = super.postProcessOperationsWithModels(objs, allModels); OperationMap operations = objs.getOperations(); @@ -541,7 +524,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List { if (codegenOperation instanceof CustomCodegenOperation customCodegenOperation - && customCodegenOperation.authMethods != null) { + && customCodegenOperation.authMethods != null) { postProcessSecurityParameters(customCodegenOperation); } }); @@ -584,19 +567,21 @@ public boolean equals(Object o) { return false; } CustomCodegenOperation that = (CustomCodegenOperation) o; - return needsConstructorWithAllStringParameter == that.needsConstructorWithAllStringParameter - && hasApiKeyAuth == that.hasApiKeyAuth - && Objects.equals(requiredNonBodyParams, that.requiredNonBodyParams) - && Objects.equals(optionalAndAuthParameterNames, that.optionalAndAuthParameterNames); + return needsConstructorWithAllStringParameter + == that.needsConstructorWithAllStringParameter + && hasApiKeyAuth == that.hasApiKeyAuth + && Objects.equals(requiredNonBodyParams, that.requiredNonBodyParams) + && Objects.equals(optionalAndAuthParameterNames, + that.optionalAndAuthParameterNames); } @Override public int hashCode() { return Objects.hash(super.hashCode(), - requiredNonBodyParams, - optionalAndAuthParameterNames, - needsConstructorWithAllStringParameter, - hasApiKeyAuth); + requiredNonBodyParams, + optionalAndAuthParameterNames, + needsConstructorWithAllStringParameter, + hasApiKeyAuth); } } @@ -639,4 +624,17 @@ public int hashCode() { return Objects.hash(super.hashCode(), isBaseTypeString); } } + + public String invokerFolder() { + return (sourceFolder + File.separator + invokerPackage.replace('.', + File.separatorChar)).replace('/', File.separatorChar); + } + + public String springFolder() { + return invokerFolder() + File.separator + "spring"; + } + + public String schemaFolder() { + return resourceFolder + File.separator + generatedSchemaFolder; + } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java index 9e2bf10779..f8f23ca1a2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java @@ -1,11 +1,21 @@ package org.citrusframework.openapi.generator; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.parameters.Parameter; import io.swagger.v3.oas.models.servers.Server; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenOperation; import org.citrusframework.openapi.generator.CitrusJavaCodegen.CustomCodegenParameter; import org.junit.jupiter.api.BeforeEach; @@ -16,17 +26,6 @@ import org.openapitools.codegen.CodegenParameter; import org.openapitools.codegen.CodegenProperty; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - /** * This test validates the code generation process. */ @@ -177,4 +176,22 @@ void testFromOperation() { .hasFieldOrPropertyWithValue("httpMethod", "GET") .hasFieldOrPropertyWithValue("path", "/path"); } + + @Test + void shouldReturnCorrectInvokerFolder() { + String expectedPath = "src/main/java/org/openapitools"; + assertThat(codegen.invokerFolder().replace('\\', '/')).isEqualTo(expectedPath); + } + + @Test + void shouldReturnCorrectSpringFolder() { + String expectedPath = "src/main/java/org/openapitools/spring"; + assertThat(codegen.springFolder().replace('\\', '/')).isEqualTo(expectedPath); + } + + @Test + void shouldReturnCorrectSchemaFolder() { + String expectedPath = "src/main/resources/schema/xsd"; + assertThat(codegen.schemaFolder().replace('\\', '/')).isEqualTo(expectedPath); + } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index 4e7260fb23..128bbf6de3 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -23,6 +23,34 @@ + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.9.0 + + true + + + + mojo-descriptor + process-classes + + descriptor + + + + help-goal + + helpmojo + + + + + + + org.apache.maven.plugins @@ -42,19 +70,17 @@ citrus-test-api-generator-core ${project.version} - org.openapitools openapi-generator ${org.openapitools.version} + compile - org.openapitools openapi-generator-maven-plugin ${org.openapitools.version} - commons-io commons-io @@ -92,7 +118,7 @@ org.apache.maven.plugin-tools maven-plugin-annotations ${maven.plugin.annotations.version} - provided + compile diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java index fc154380a2..9e89b3409d 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/CodeGenMojoWrapper.java @@ -19,13 +19,13 @@ import static java.lang.String.format; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.CODEGEN_NAME; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.GENERATED_SCHEMA_FOLDER; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.RESOURCE_FOLDER; import static org.citrusframework.openapi.generator.CitrusJavaCodegen.ROOT_CONTEXT_PATH; -import static org.citrusframework.openapi.generator.CitrusJavaCodegen.SOURCE_FOLDER; import java.io.File; +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; +import org.apache.maven.model.Resource; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; @@ -37,7 +37,7 @@ */ public class CodeGenMojoWrapper extends CodeGenMojo { - + private MavenProject localMavenProject; @SuppressWarnings("rawtypes") private final Map configOptionsProperties = new HashMap<>(); @@ -47,12 +47,42 @@ public CodeGenMojoWrapper() throws MojoExecutionException { setPrivateField("configOptions", configOptionsProperties); } + @Override + public void execute() throws MojoExecutionException { + super.execute(); + addResourceRootIfConfigured(); + } + + private void addResourceRootIfConfigured() throws MojoExecutionException { + Resource resource = new Resource(); + resource.setDirectory(getResourceRoot()); + resource.addInclude("**/*"); // Include all files by default + resource.setFiltering(false); // Ensure no filtering of resources + + if (getPrivateField("addCompileSourceRoot")) { + localMavenProject.addResource(resource); + } else if (getPrivateField("addTestCompileSourceRoot")) { + localMavenProject.addTestResource(resource); + } + } + + private String getResourceRoot() throws MojoExecutionException { + final Object resourceFolderObject = configOptionsProperties + .get(TestApiGeneratorMojo.RESOURCE_FOLDER); + final String resourceFolder = + resourceFolderObject != null ? resourceFolderObject.toString() : "src/main/resources"; + + return ((File) getPrivateField("output")).getPath() + File.separatorChar + resourceFolder; + } + + private void setFixedConfigOptions() throws MojoExecutionException { setPrivateField("generateSupportingFiles", true); setPrivateField("generatorName", CODEGEN_NAME); } public CodeGenMojoWrapper project(MavenProject mavenProject) throws MojoExecutionException { + this.localMavenProject = mavenProject; setPrivateField("project", mavenProject); return this; } @@ -74,20 +104,22 @@ public CodeGenMojoWrapper mojoExecution(MojoExecution mojoExecution) } public CodeGenMojoWrapper configOptions( - @SuppressWarnings("rawtypes") Map configProperties) { + @SuppressWarnings("rawtypes") Map configProperties) throws MojoExecutionException { //noinspection unchecked configOptionsProperties.putAll(configProperties); propagateContextPathToCodegen(); + propagateMojoConfigurationParameters(configProperties); return this; } /** - * In version 7.9 of the code generator, the basePath cannot be configured directly. Additionally, - * if the OpenAPI server specifies a hostname, that hostname becomes part of the basePath. - * This behavior is incompatible with the API generator, as the host is already provided by the Citrus endpoint. - * Therefore, the contextPath is used instead of the basePath. The contextPath is passed to the code generator - * via additional-properties to ensure proper configuration. + * In version 7.9 of the code generator, the basePath cannot be configured directly. + * Additionally, if the OpenAPI server specifies a hostname, that hostname becomes part of the + * basePath. This behavior is incompatible with the API generator, as the host is already + * provided by the Citrus endpoint. Therefore, the contextPath is used instead of the basePath. + * The contextPath is passed to the code generator via additional-properties to ensure proper + * configuration. */ private void propagateContextPathToCodegen() { // Pass in contextPath as contextPath into the generator @@ -95,12 +127,41 @@ private void propagateContextPathToCodegen() { // Note that an null value indicates "no context path". String contextPath = (String) configOptionsProperties.get(ROOT_CONTEXT_PATH); contextPath = contextPath == null ? "" : contextPath; + + // Additional properties are stored as comma separated key-value pairs. + // See org.openapitools.codegen.config.CodegenConfiguratorUtils.applyAdditionalPropertiesKvp for details. //noinspection unchecked configOptionsProperties.put("additional-properties", "rootContextPath=" + contextPath); } } + private void propagateMojoConfigurationParameters(Map configProperties) + throws MojoExecutionException { + + for (Field field : CodeGenMojo.class.getDeclaredFields()) { + String name = field.getName(); + if (configProperties.containsKey(name)) { + String valueAsString = configProperties.get(name); + Object value; + if (valueAsString != null) { + if (field.getType() == String.class) { + value = valueAsString; + } else if (field.getType() == Boolean.class || field.getType() == boolean.class) { + value = Boolean.valueOf(valueAsString); + } else if (field.getType() == File.class) { + value = new File(valueAsString); + } else { + throw new IllegalArgumentException( + format("Cannot convert '%s' to type '%s'", valueAsString, + field.getType())); + } + setPrivateField(name, value); + } + } + } + } + public CodeGenMojoWrapper globalProperties(@SuppressWarnings("rawtypes") Map globalProperties) { //noinspection unchecked this.globalProperties.putAll(globalProperties); @@ -113,18 +174,6 @@ public CodeGenMojoWrapper schemaFolder(String schemaFolder) { return this; } - public CodeGenMojoWrapper resourceFolder(String resourceFolder) { - //noinspection unchecked - configOptionsProperties.put(RESOURCE_FOLDER, resourceFolder); - return this; - } - - public CodeGenMojoWrapper sourceFolder(String sourceFolder) { - //noinspection unchecked - configOptionsProperties.put(SOURCE_FOLDER, sourceFolder); - return this; - } - // Accessibility bypass @SuppressWarnings("java:S3011") private void setPrivateField(String fieldName, Object fieldValue) @@ -139,4 +188,24 @@ private void setPrivateField(String fieldName, Object fieldValue) fieldName)); } } + + // Accessibility bypass + @SuppressWarnings("java:S3011") + private T getPrivateField(String fieldName) + throws MojoExecutionException { + try { + var field = CodeGenMojo.class.getDeclaredField(fieldName); + field.setAccessible(true); + //noinspection unchecked + return (T) field.get(this); + } catch (NoSuchFieldException | IllegalAccessException e) { + throw new MojoExecutionException( + format("Could not reflectively get value for field '%s'", fieldName)); + } + } + + public CodeGenMojoWrapper skip(Boolean skip) throws MojoExecutionException { + setPrivateField("skip", skip); + return this; + } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java index 38dbc2d366..6cf9ec3c6a 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/SpringMetaFileGenerator.java @@ -16,9 +16,12 @@ package org.citrusframework.maven.plugin; -import org.apache.maven.plugin.MojoExecutionException; -import org.citrusframework.exceptions.CitrusRuntimeException; -import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; +import static java.lang.String.format; +import static java.util.Collections.emptyList; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA_KEEP_HINT; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; +import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; import java.io.BufferedReader; import java.io.File; @@ -28,13 +31,9 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; - -import static java.lang.String.format; -import static java.util.Collections.emptyList; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.CITRUS_TEST_SCHEMA_KEEP_HINT; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; +import org.apache.maven.plugin.MojoExecutionException; +import org.citrusframework.exceptions.CitrusRuntimeException; +import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; /** * Utility class responsible for generating the Spring meta files 'spring.handlers' and 'spring.schemas', used @@ -51,6 +50,8 @@ public class SpringMetaFileGenerator { private final TestApiGeneratorMojo testApiGeneratorMojo; + private String lineEnding = "\n"; + public SpringMetaFileGenerator(TestApiGeneratorMojo testApiGeneratorMojo) { this.testApiGeneratorMojo = testApiGeneratorMojo; } @@ -72,7 +73,7 @@ public SpringMetaFileGenerator(TestApiGeneratorMojo testApiGeneratorMojo) { * @return a list of filtered lines, excluding lines indicating a generated test API * @throws CitrusRuntimeException if an error occurs while reading the file */ - private static List readAndFilterLines(File file) { + private List readAndFilterLines(File file) { if (!file.exists()) { return emptyList(); } @@ -81,6 +82,11 @@ private static List readAndFilterLines(File file) { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; while ((line = reader.readLine()) != null) { + + if (lineEnding.contains("\r")) { + lineEnding = "\r\n"; + } + if (line.contains(CITRUS_TEST_SCHEMA_KEEP_HINT)) { filteredLines.add(reader.readLine()); } else if (!line.contains(CITRUS_TEST_SCHEMA)) { @@ -95,11 +101,12 @@ private static List readAndFilterLines(File file) { } public void generateSpringIntegrationMetaFiles() throws MojoExecutionException { - String springMetafileDirectory = format("%s/%s", testApiGeneratorMojo.getMavenProject().getBasedir(), testApiGeneratorMojo.metaInfFolder()); - File metaFolder = new File(springMetafileDirectory); + + File metaFolder = new File(testApiGeneratorMojo.getMavenProject().getBasedir(), testApiGeneratorMojo.getMetaInfFolder()); + if (!metaFolder.exists() && !metaFolder.mkdirs()) { throw new CitrusRuntimeException( - format("Unable to create spring meta file directory: '%s'", springMetafileDirectory)); + format("Unable to create spring meta file directory: '%s'", testApiGeneratorMojo.getMetaInfFolder())); } try { @@ -136,7 +143,7 @@ private void writeSpringMetaFile(File springMetafileDirectory, String filename, try (FileWriter fileWriter = new FileWriter(handlerFile)) { for (String line : filteredLines) { - fileWriter.write(format("%s%n", line)); + fileWriter.write(format("%s%s", line, lineEnding)); } for (ApiConfig apiConfig : testApiGeneratorMojo.getApiConfigs()) { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java index eb4e0fe59a..26e3eb508f 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java @@ -16,6 +16,7 @@ package org.citrusframework.maven.plugin; +import static java.lang.Boolean.TRUE; import static java.lang.String.format; import static java.util.Objects.requireNonNull; import static org.apache.commons.lang3.StringUtils.isBlank; @@ -29,6 +30,7 @@ import static org.springframework.util.ReflectionUtils.setField; import com.google.common.annotations.VisibleForTesting; +import jakarta.annotation.Nonnull; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; @@ -41,6 +43,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.maven.model.Resource; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; @@ -78,8 +81,8 @@ ) public class TestApiGeneratorMojo extends AbstractMojo { - public static final String DEFAULT_SOURCE_FOLDER = "generated-test-sources"; - public static final String DEFAULT_RESOURCE_FOLDER = "generated-test-resources"; + public static final String RESOURCE_FOLDER = "resourceFolder"; + public static final String DEFAULT_BASE_PACKAGE = "org.citrusframework.automation.%PREFIX%.%VERSION%"; public static final String DEFAULT_INVOKER_PACKAGE = DEFAULT_BASE_PACKAGE; public static final String DEFAULT_API_PACKAGE = DEFAULT_BASE_PACKAGE + ".api"; @@ -108,19 +111,6 @@ public class TestApiGeneratorMojo extends AbstractMojo { public static final String DEFAULT_TARGET_NAMESPACE_TEMPLATE = "http://www.citrusframework.org/" + CITRUS_TEST_SCHEMA + "/%VERSION%/%PREFIX%-api"; - /** - * TODO: document this - * The default META-INF folder. Note that it points into the test resources, to allow for non generated - * schemas/handlers. See also {@link TestApiGeneratorMojo}#DEFAULT_TARGET_NAMESPACE_TEMPLATE. - */ - public static final String DEFAULT_META_INF_FOLDER = "src/test/resources/META-INF"; - - /** - * sourceFolder: specifies the location to which the sources are generated. Defaults to - * 'generated-test-sources'. - */ - public static final String SOURCE_FOLDER_PROPERTY = "citrus.test.api.generator.source.folder"; - /** * resourceFolder: specifies the location to which the resources are generated. Defaults to * 'generated-test-resources'. @@ -154,26 +144,25 @@ public class TestApiGeneratorMojo extends AbstractMojo { @Parameter(defaultValue = "${mojoExecution}", readonly = true) private MojoExecution mojoExecution; - @Parameter(property = SOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_SOURCE_FOLDER) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String sourceFolder = DEFAULT_SOURCE_FOLDER; - - @Parameter(property = RESOURCE_FOLDER_PROPERTY, defaultValue = DEFAULT_RESOURCE_FOLDER) - @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String resourceFolder = DEFAULT_RESOURCE_FOLDER; + @Parameter(name = "output", property = "openapi.generator.maven.plugin.output") + private File output; @Parameter(property = API_SCHEMA_FOLDER, defaultValue = DEFAULT_SCHEMA_FOLDER_TEMPLATE) @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected private String schemaFolder = DEFAULT_SCHEMA_FOLDER_TEMPLATE; - @Parameter(property = META_INF_FOLDER, defaultValue = DEFAULT_META_INF_FOLDER) + @Parameter(property = META_INF_FOLDER) @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected - private String metaInfFolder = DEFAULT_META_INF_FOLDER; + private String metaInfFolder; @Parameter(property = GENERATE_SPRING_INTEGRATION_FILES, defaultValue = "true") @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected private boolean generateSpringIntegrationFiles = true; + @Parameter(name = "skip", property = "codegen.skip", defaultValue = "false") + @SuppressWarnings({"FieldCanBeLocal", "FieldMayBeFinal"}) // Maven injected + private Boolean skip; + @Parameter private List apis; @@ -221,10 +210,6 @@ public List getApiConfigs() { return apis; } - public String metaInfFolder() { - return metaInfFolder; - } - @VisibleForTesting void setMojoExecution(MojoExecution mojoExecution) { this.mojoExecution = mojoExecution; @@ -239,18 +224,38 @@ public String schemaFolder(ApiConfig apiConfig) { @Override public void execute() throws MojoExecutionException { + for (int index = 0; index < apis.size(); index++) { ApiConfig apiConfig = apis.get(index); validateApiConfig(index, apiConfig); delegateExecution(configureCodeGenMojo(apiConfig)); - } - if (generateSpringIntegrationFiles) { + if (!TRUE.equals(skip) && generateSpringIntegrationFiles) { new SpringMetaFileGenerator(this).generateSpringIntegrationMetaFiles(); } } + @Nonnull + public String getMetaInfFolder() { + if (metaInfFolder == null) { + Path basePath = Paths.get(mavenProject.getBasedir().toURI()); + Path metaInfResourceFolderPath = Paths.get( + new File(mavenProject.getBuild().getDirectory(), + LifecyclePhase.GENERATE_TEST_SOURCES.id() + .equals(mojoExecution.getLifecyclePhase()) ? + "generated-test-sources/openapi/src/main/resources" + : "generated-sources/openapi/src/main/resources").toURI()); + Resource metaInfResource = new Resource(); + metaInfResource.setDirectory(metaInfResourceFolderPath.toString()); + mavenProject.addResource(metaInfResource); + metaInfFolder = + basePath.relativize(metaInfResourceFolderPath) + File.separator + + "META-INF"; + } + return metaInfFolder; + } + @VisibleForTesting void delegateExecution(CodeGenMojo codeGenMojo) throws MojoExecutionException { codeGenMojo.execute(); @@ -261,16 +266,19 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept if (apiConfig.getSource().toUpperCase().trim().endsWith(".WSDL")) { apiConfig.source = convertToOpenApi(apiConfig.getSource()); } + + Map apiConfigOptions = createApiConfigOptions(apiConfig); + CodeGenMojo codeGenMojo = new CodeGenMojoWrapper() - .resourceFolder(resourceFolder) - .sourceFolder(sourceFolder) .schemaFolder(schemaFolder(apiConfig)) - .output(new File(mavenProject.getBuild().getDirectory())) + .skip(skip) + .output(output) .mojoExecution(mojoExecution) .project(mavenProject) .inputSpec(apiConfig.getSource()) .globalProperties(globalProperties) - .configOptions(apiConfig.toConfigOptionsProperties(globalConfigOptions)); + .configOptions(apiConfigOptions); + codeGenMojo.setPluginContext(getPluginContext()); @@ -290,6 +298,19 @@ CodeGenMojo configureCodeGenMojo(ApiConfig apiConfig) throws MojoExecutionExcept return codeGenMojo; } + private Map createApiConfigOptions(ApiConfig apiConfig) { + Map configOptions = new HashMap<>(); + + if (LifecyclePhase.GENERATE_TEST_SOURCES.id().equals(mojoExecution.getLifecyclePhase())) { + configOptions.put("addCompileSourceRoot", "false"); + configOptions.put("addTestCompileSourceRoot", "true"); + } + + //noinspection unchecked + configOptions.putAll(apiConfig.toConfigOptionsProperties(globalConfigOptions)); + return configOptions; + } + private String convertToOpenApi(String source) throws MojoExecutionException { String apiFile = source; String path = source.replace("\\", "/"); @@ -588,6 +609,10 @@ public void setApiConfigOptions(Map apiConfigOptions) { this.apiConfigOptions = apiConfigOptions; } + public Map getApiConfigOptions() { + return apiConfigOptions; + } + public void setAdditionalProperties(List additionalProperties) { this.additionalProperties = additionalProperties; } @@ -619,6 +644,5 @@ Map toConfigOptionsProperties(Map globalConfigOptions) { return configOptionsProperties; } - } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java index 7208ddeae7..409f582cf2 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/SpringMetaFileGeneratorTest.java @@ -38,7 +38,7 @@ void generateMetaFiles() throws MojoExecutionException { MavenProject mavenProject = mock(); doReturn(new File(userDir)).when(mavenProject).getBasedir(); doReturn(mavenProject).when(testApiGeneratorMojo).getMavenProject(); - doReturn("/test-classes/SpringMetaFileGeneratorTest/META-INF").when(testApiGeneratorMojo).metaInfFolder(); + doReturn("/test-classes/SpringMetaFileGeneratorTest/META-INF").when(testApiGeneratorMojo).getMetaInfFolder(); ApiConfig apiConfig = new ApiConfig(); apiConfig.setPrefix("PrefixA"); diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java index c3fd48809b..4b6d471597 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoIntegrationTest.java @@ -13,7 +13,6 @@ import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; import static org.junit.jupiter.params.provider.Arguments.arguments; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.springframework.test.util.ReflectionTestUtils.getField; @@ -39,7 +38,6 @@ import org.citrusframework.maven.plugin.TestApiGeneratorMojo.ApiConfig; import org.citrusframework.maven.plugin.stubs.CitrusOpenApiGeneratorMavenProjectStub; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -331,16 +329,41 @@ private String resolveFilePath(ApiConfig apiConfig, String filePathTemplate) { String schemaFolder = toFolder( replaceDynamicVars((String) getField(fixture, "schemaFolder"), apiConfig.getPrefix(), apiConfig.getVersion())); - String generatedSourcesFolder = toFolder( - replaceDynamicVars((String) getField(fixture, "sourceFolder"), apiConfig.getPrefix(), - apiConfig.getVersion())); - String generatedResourcesFolder = toFolder( - replaceDynamicVars((String) getField(fixture, "resourceFolder"), apiConfig.getPrefix(), - apiConfig.getVersion())); + + + Map apiConfigOptions = apiConfig.getApiConfigOptions(); + + String targetFolder = fixture.getMavenProject().getBuild().getDirectory(); + String generatedSourcesFolder = "generated-sources/openapi/src/main/java"; + String generatedResourcesFolder = "generated-sources/openapi/src/main/resources"; + + if (apiConfigOptions != null) { + String output = apiConfigOptions.get("output"); + if (output != null) { + // Due to the special nature of the nested build directories, explicit output paths need + // to be prefixed with the path to the nested target folder - e.g. target/pom-full-config. + // These two segments are also specified in the baseFolderPath and thus need to be removed + // for proper resolution. + Path baseFolderPath = Path.of(fixture.getMavenProject().getBasedir().getPath()); + Path outputPath = Path.of(output); + targetFolder = baseFolderPath.getParent().getParent().resolve(outputPath).toString(); + } + + String sourceFolder = apiConfigOptions.get("sourceFolder"); + if (sourceFolder != null) { + generatedSourcesFolder = sourceFolder; + } + + String resourceFolder = apiConfigOptions.get("resourceFolder"); + if (resourceFolder != null) { + generatedResourcesFolder = resourceFolder; + } + + } return filePathTemplate .replace("%BASE_FOLDER%", fixture.getMavenProject().getBasedir().getPath()) - .replace("%TARGET_FOLDER%", fixture.getMavenProject().getBuild().getDirectory()) + .replace("%TARGET_FOLDER%", targetFolder) .replace("%SOURCE_FOLDER%", fixture.getMavenProject().getBuild().getSourceDirectory()) .replace("%GENERATED_SOURCES_FOLDER%", generatedSourcesFolder) .replace("%GENERATED_RESOURCES_FOLDER%", generatedResourcesFolder) @@ -350,7 +373,7 @@ private String resolveFilePath(ApiConfig apiConfig, String filePathTemplate) { .replace("%SCHEMA_FOLDER%", schemaFolder) .replace("%LOWER_PREFIX%", lowerCasePrefix) .replace("%CAMEL_PREFIX%", camelCasePrefix) - .replace("%META_INF_FOLDER%", toFolder((String) getField(fixture, "metaInfFolder"))); + .replace("%META_INF_FOLDER%", fixture.getMetaInfFolder()); } private String toFolder(String text) { diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java index c38904d6a3..9d313cc84d 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -5,11 +5,8 @@ import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_PACKAGE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_API_TYPE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_INVOKER_PACKAGE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_META_INF_FOLDER; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_MODEL_PACKAGE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_RESOURCE_FOLDER; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SCHEMA_FOLDER_TEMPLATE; -import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_SOURCE_FOLDER; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.DEFAULT_TARGET_NAMESPACE_TEMPLATE; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVars; import static org.citrusframework.maven.plugin.TestApiGeneratorMojo.replaceDynamicVarsToLowerCase; @@ -38,15 +35,17 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.openapitools.codegen.plugin.CodeGenMojo; @ExtendWith(MockitoExtension.class) -@SuppressWarnings({"JUnitMalformedDeclaration", "JUnitMixedFramework"}) +@SuppressWarnings({"JUnitMalformedDeclaration"}) class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase { - private TestApiGeneratorMojo fixture; + @InjectMocks + private TestApiGeneratorMojo fixture = new TestApiGeneratorMojo(); @Mock private Build buildMock; @@ -135,7 +134,10 @@ private static ApiConfig createFullApiConfig(String version) { apiConfig.setUseTags(false); apiConfig.setType(ApiType.SOAP); apiConfig.setVersion(version); - apiConfig.setApiConfigOptions(Map.of("optA", "A", "optB", "B")); + apiConfig.setApiConfigOptions( + Map.of("optA", "A", "optB", "B", "output", "my-target", "sourceFolder", + "mySourceFolder", + "resourceFolder", "myResourceFolder")); apiConfig.setAdditionalProperties(List.of("a=b", "c=d")); apiConfig.setRootContextPath("/a/b/c/d"); @@ -153,14 +155,13 @@ private static CodeGenMojoParams createMinimalCodeGenMojoParams(String schemaFol configOptionsControlMap.put("invokerPackage", invokerPackage); configOptionsControlMap.put("apiPackage", apiPackage); configOptionsControlMap.put("modelPackage", modelPackage); - configOptionsControlMap.put("resourceFolder", "generated-test-resources"); - configOptionsControlMap.put("sourceFolder", "generated-test-sources"); configOptionsControlMap.put("apiEndpoint", "mydefaultprefixEndpoint"); configOptionsControlMap.put("targetXmlnsNamespace", targetXmlnsNamespace); configOptionsControlMap.put("apiType", "REST"); configOptionsControlMap.put("useTags", true); - return new CodeGenMojoParams("target", "myDefaultSource", configOptionsControlMap, Collections.emptyList()); + return new CodeGenMojoParams("myDefaultSource", configOptionsControlMap, + Collections.emptyList()); } @NotNull @@ -174,24 +175,20 @@ private static CodeGenMojoParams createCustomCodeGenMojoParams(String schemaFold configOptionsControlMap.put("invokerPackage", invokerPackage); configOptionsControlMap.put("modelPackage", modelPackage); configOptionsControlMap.put("apiPackage", apiPackage); - configOptionsControlMap.put("resourceFolder", "generated-test-resources"); - configOptionsControlMap.put("sourceFolder", "generated-test-sources"); + configOptionsControlMap.put("resourceFolder", "myResourceFolder"); + configOptionsControlMap.put("sourceFolder", "mySourceFolder"); configOptionsControlMap.put("apiEndpoint", "myEndpoint"); configOptionsControlMap.put("targetXmlnsNamespace", targetXmlnsNamespace); configOptionsControlMap.put("apiType", "SOAP"); configOptionsControlMap.put("useTags", false); configOptionsControlMap.put("optA", "A"); configOptionsControlMap.put("optB", "B"); + configOptionsControlMap.put("output", "my-target"); - return new CodeGenMojoParams("target", "myCustomSource", configOptionsControlMap, + return new CodeGenMojoParams("myCustomSource", configOptionsControlMap, List.of("a=b", "c=d", "rootContextPath=/a/b/c/d")); } - @BeforeEach - void beforeEach() { - fixture = new TestApiGeneratorMojo(); - } - @ParameterizedTest @MethodSource void replaceDynamicVarsInPattern(String pattern, String prefix, String version, @@ -210,20 +207,22 @@ void replaceDynamicVarsInPattern(String pattern, String prefix, String version, @MethodSource void configureMojo(String name, ApiConfig apiConfig, CodeGenMojoParams controlParams) throws MojoExecutionException { - doReturn("target").when(buildMock).getDirectory(); - doReturn(buildMock).when(mavenProjectMock).getBuild(); fixture.setMavenProject(mavenProjectMock); fixture.setMojoExecution(mojoExecutionMock); CodeGenMojo codeGenMojo = fixture.configureCodeGenMojo(apiConfig); assertThat(getField(codeGenMojo, "project")).isEqualTo(mavenProjectMock); assertThat(getField(codeGenMojo, "mojo")).isEqualTo(mojoExecutionMock); - assertThat(((File) getField(codeGenMojo, "output"))).hasName(controlParams.output); + + if (controlParams.configOptions.get("output") != null) { + assertThat(((File) getField(codeGenMojo, "output")).getPath()).isEqualTo( + controlParams.configOptions.get("output")); + } + assertThat(getField(codeGenMojo, "inputSpec")).isEqualTo(controlParams.source); assertThat(getField(codeGenMojo, "generateSupportingFiles")).isEqualTo(TRUE); assertThat(getField(codeGenMojo, "generatorName")).isEqualTo("java-citrus"); - //noinspection unchecked if (controlParams.additionalProperties.isEmpty()) { //noinspection unchecked assertThat((List) getField(codeGenMojo, "additionalProperties")) @@ -239,8 +238,8 @@ void configureMojo(String name, ApiConfig apiConfig, CodeGenMojoParams controlPa .containsExactlyInAnyOrderEntriesOf(controlParams.configOptions); } - private record CodeGenMojoParams(String output, String source, - Map configOptions, List additionalProperties) { + private record CodeGenMojoParams(String source, Map configOptions, + List additionalProperties) { } @@ -292,21 +291,15 @@ void schemaFolderDefault() { DEFAULT_SCHEMA_FOLDER_TEMPLATE); } - @Test - void sourceFolderDefault() { - assertThat((String) getField(fixture, "sourceFolder")).isEqualTo(DEFAULT_SOURCE_FOLDER); - } - - @Test - void resourceFolderDefault() { - assertThat((String) getField(fixture, "resourceFolder")).isEqualTo( - DEFAULT_RESOURCE_FOLDER); - } - @Test void metaInfFolderDefault() { - assertThat((String) getField(fixture, "metaInfFolder")).isEqualTo( - DEFAULT_META_INF_FOLDER); + File baseDirFile = new File("/a/b/c"); + doReturn(new File(baseDirFile, "target").getPath()).when(buildMock).getDirectory(); + doReturn(buildMock).when(mavenProjectMock).getBuild(); + doReturn(baseDirFile).when(mavenProjectMock).getBasedir(); + + assertThat(fixture.getMetaInfFolder().replace("\\", "/")).isEqualTo( + ("target/generated-sources/openapi/src/main/resources/META-INF")); } } } diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml index 304d7bec62..d030deee4b 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml @@ -35,13 +35,15 @@ b d + + target/pom-full-config/target/generated-sources-mod/openapi-mod + src/main/java-mod + src/main/resource-mod - generated-sources-mod - generated-resources-mod myschema/xsd - main-mod/resources-mod/META-INF-MOD + src/main/resource-mod/META-INF-MOD diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml index 401ea5fa50..f0a12a717c 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-with-version-config.xml @@ -22,10 +22,13 @@ api/test-api.yml "http://myNamespace" v1 + + target/pom-full-with-version-config/target/generated-sources-mod/openapi-mod + src/main/java-mod + src/main/resource-mod + - generated-sources-mod - generated-resources-mod myschema/xsd main-mod/resources-mod/META-INF-MOD From 1812ab641e56153075bfe07d8f40b3f579c827fa Mon Sep 17 00:00:00 2001 From: Timon Borter Date: Thu, 9 Jan 2025 08:54:53 +0100 Subject: [PATCH 41/47] chore: bump all versions to 4.6.0-SNAPSHOT --- catalog/citrus-bom/pom.xml | 6 +++--- test-api-generator/citrus-test-api-core/pom.xml | 2 +- test-api-generator/citrus-test-api-generator-core/pom.xml | 2 +- .../citrus-test-api-generator-maven-plugin/pom.xml | 2 +- test-api-generator/pom.xml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/catalog/citrus-bom/pom.xml b/catalog/citrus-bom/pom.xml index 3c801b84b3..0659de9994 100644 --- a/catalog/citrus-bom/pom.xml +++ b/catalog/citrus-bom/pom.xml @@ -241,17 +241,17 @@ org.citrusframework citrus-test-api-core - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT org.citrusframework citrus-test-api-generator-core - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT org.citrusframework citrus-test-api-spring - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT org.citrusframework diff --git a/test-api-generator/citrus-test-api-core/pom.xml b/test-api-generator/citrus-test-api-core/pom.xml index a0fbc7a1c0..c8d9abe1e2 100644 --- a/test-api-generator/citrus-test-api-core/pom.xml +++ b/test-api-generator/citrus-test-api-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/citrus-test-api-generator-core/pom.xml b/test-api-generator/citrus-test-api-generator-core/pom.xml index 7cc54e0ea1..cc21f89f67 100644 --- a/test-api-generator/citrus-test-api-generator-core/pom.xml +++ b/test-api-generator/citrus-test-api-generator-core/pom.xml @@ -7,7 +7,7 @@ citrus-test-api-generator org.citrusframework - 4.5.0-PF-RC3 + 4.6.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml index 128bbf6de3..34b7aca69c 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/pom.xml @@ -8,7 +8,7 @@ citrus-test-api-generator org.citrusframework - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT ../pom.xml diff --git a/test-api-generator/pom.xml b/test-api-generator/pom.xml index 853782c8c0..017243f68b 100644 --- a/test-api-generator/pom.xml +++ b/test-api-generator/pom.xml @@ -6,7 +6,7 @@ org.citrusframework citrus - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT ../pom.xml From adef764db524d410f791855e98664d2bd026bea8 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Thu, 9 Jan 2025 11:00:14 +0100 Subject: [PATCH 42/47] fix: treat unparsable server urls as non existent - depending on configuration server urls are not really required - fix expected code gen for generated api test --- .../citrusframework/openapi/model/v3/Oas30ModelHelper.java | 6 +++--- .../expectedgen/rest/extpetstore/model/Category.java | 2 +- .../expectedgen/rest/extpetstore/model/HistoricalData.java | 2 +- .../expectedgen/rest/extpetstore/model/Pet.java | 2 +- .../expectedgen/rest/extpetstore/model/PetIdentifier.java | 2 +- .../expectedgen/rest/extpetstore/model/Tag.java | 2 +- .../rest/extpetstore/model/VaccinationDocumentResult.java | 2 +- .../expectedgen/rest/extpetstore/request/ExtPetApi.java | 2 +- .../extpetstore/spring/ExtPetStoreBeanConfiguration.java | 2 +- .../extpetstore/spring/ExtPetStoreNamespaceHandler.java | 2 +- .../expectedgen/rest/petstore/model/Address.java | 2 +- .../expectedgen/rest/petstore/model/Category.java | 2 +- .../expectedgen/rest/petstore/model/Customer.java | 2 +- .../expectedgen/rest/petstore/model/ModelApiResponse.java | 2 +- .../expectedgen/rest/petstore/model/Order.java | 2 +- .../expectedgen/rest/petstore/model/Pet.java | 2 +- .../expectedgen/rest/petstore/model/Tag.java | 2 +- .../expectedgen/rest/petstore/model/User.java | 2 +- .../expectedgen/rest/petstore/request/PetApi.java | 2 +- .../expectedgen/rest/petstore/request/StoreApi.java | 2 +- .../expectedgen/rest/petstore/request/UserApi.java | 2 +- .../rest/petstore/spring/PetStoreBeanConfiguration.java | 2 +- .../rest/petstore/spring/PetStoreNamespaceHandler.java | 2 +- .../soap/bookservice/request/BookServiceSoapApi.java | 2 +- .../bookservice/spring/BookServiceBeanConfiguration.java | 2 +- .../bookservice/spring/BookServiceNamespaceHandler.java | 2 +- 26 files changed, 28 insertions(+), 28 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java index 413bd617d8..ca1973d971 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/model/v3/Oas30ModelHelper.java @@ -16,6 +16,7 @@ package org.citrusframework.openapi.model.v3; +import static java.lang.String.format; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; @@ -33,7 +34,6 @@ import io.apicurio.datamodels.openapi.v3.models.Oas30RequestBody; import io.apicurio.datamodels.openapi.v3.models.Oas30Response; import io.apicurio.datamodels.openapi.v3.models.Oas30Schema; -import java.net.MalformedURLException; import java.net.URI; import java.util.Arrays; import java.util.Collection; @@ -80,8 +80,8 @@ public static List getSchemes(Oas30Document openApiDoc) { .map(serverUrl -> { try { return URI.create(serverUrl).toURL().getProtocol(); - } catch (MalformedURLException e) { - logger.warn(NO_URL_ERROR_MESSAGE, serverUrl); + } catch (Exception e) { + logger.warn(format(NO_URL_ERROR_MESSAGE, serverUrl), e); return null; } }) diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index edbebe147d..11a1afb9f8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index f4e5a7ef52..fde96ad0ae 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -25,7 +25,7 @@ /** * Additional historical data for a vaccination report, not contained in internal storage. */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class HistoricalData { private LocalDate lastVaccinationDate; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index 6469cd773d..c81d0e3837 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java index 137609393f..79db62bb29 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java @@ -24,7 +24,7 @@ /** * PetIdentifier */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetIdentifier { private String _name; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index e1cc351373..c10c692c20 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 7843d96a8c..2ee2b3ca1f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -24,7 +24,7 @@ /** * VaccinationDocumentResult */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class VaccinationDocumentResult { private String documentId; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index 313b22828d..969d47fd03 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -42,7 +42,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.model.VaccinationDocumentResult; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index f42ef2cd4d..fcd1063f29 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index 361cf6497a..d90e9f9897 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -12,7 +12,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.457218800+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index 972cd4144b..1e0b69afc3 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -24,7 +24,7 @@ /** * Address */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Address { private String street; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index 4e8859292f..b65788bb74 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index 34249bf7a0..93d3776f57 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -28,7 +28,7 @@ /** * Customer */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Customer { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index eabd3f8b1b..27a740b992 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -24,7 +24,7 @@ /** * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ModelApiResponse { private Integer code; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index cd61b599f2..9dbd21669d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -25,7 +25,7 @@ /** * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Order { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index 11076f71c8..96cc08f4f1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index bc19008e1f..319de5c72f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index 69daf58d73..63c474fdc8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -24,7 +24,7 @@ /** * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class User { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index 75856c891f..d26ecd2a76 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Pet; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 97fcceb73c..346e4740d7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -36,7 +36,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Order; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class StoreApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index a91eb94870..22c95378ef 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -37,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.User; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class UserApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index f75e2da7f9..7a2334129c 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -17,7 +17,7 @@ import org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index 757b44706b..222daac623 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -14,7 +14,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:38.788098300+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index 75053e1592..ccdf22a2ea 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -16,7 +16,7 @@ import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceSoapApi implements GeneratedApi { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java index 1c40475f53..643177200f 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.soap.bookservice.BookServiceOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceBeanConfiguration { @Bean diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java index a47bd113e9..e561cfd699 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java @@ -10,7 +10,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2024-12-05T10:01:39.805235400+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceNamespaceHandler extends NamespaceHandlerSupport { @Override From 119f3b1a8f5adff28af37ad9b95f81e4a1601aba Mon Sep 17 00:00:00 2001 From: muellerfluri Date: Wed, 15 Jan 2025 14:52:46 +0100 Subject: [PATCH 43/47] fix(api): add logger message to OpenApiSchemaValidation for httpMessages to name the path of origin --- .../validation/OpenApiSchemaValidation.java | 109 +++++++++--------- 1 file changed, 57 insertions(+), 52 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index 5ca99dbc96..d004fcdaa0 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -5,9 +5,11 @@ import com.atlassian.oai.validator.report.ValidationReport; import jakarta.annotation.Nullable; + import java.util.ArrayList; import java.util.List; import java.util.Objects; + import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -27,8 +29,8 @@ import org.slf4j.LoggerFactory; public class OpenApiSchemaValidation extends - AbstractMessageValidator implements - SchemaValidator { + AbstractMessageValidator implements + SchemaValidator { private static final Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); @@ -39,16 +41,16 @@ protected Class getRequiredValidationContextTyp @Override public void validateMessage(Message receivedMessage, - Message controlMessage, - TestContext context, - OpenApiMessageValidationContext validationContext) { + Message controlMessage, + TestContext context, + OpenApiMessageValidationContext validationContext) { // No control message validation, only schema validation validate(receivedMessage, context, validationContext); } @Override public void validate(Message message, TestContext context, - OpenApiMessageValidationContext validationContext) { + OpenApiMessageValidationContext validationContext) { logger.debug("Starting OpenApi schema validation ..."); // In case we have a redirect header, we cannot validate the message, as we have to expect, that the message has no valid response. @@ -57,14 +59,17 @@ public void validate(Message message, TestContext context, } ValidationReportData validationReportData = validate(context, - httpMessage, - findSchemaRepositories(context), - validationContext); + httpMessage, + findSchemaRepositories(context), + validationContext); if (validationReportData != null && validationReportData.report != null) { if (validationReportData.report.hasErrors()) { - logger.error("Failed to validate Json schema for message:\n{}", - message.getPayload(String.class)); + String path = "no Path because no httpMessage"; + if(message instanceof HttpMessage){ + path = ((HttpMessage) message).getPath(); + } + logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", message.getPayload(String.class), path); throw new ValidationException(constructErrorMessage(validationReportData)); } } @@ -85,9 +90,9 @@ public void validate(Message message, TestContext context, @Override public boolean supportsMessageType(String messageType, Message message) { return "JSON".equals(messageType) - || ( - message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class)) - || message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null); + || ( + message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class)) + || message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null); } private String constructErrorMessage(ValidationReportData validationReportData) { @@ -97,7 +102,7 @@ private String constructErrorMessage(ValidationReportData validationReportData) stringBuilder.append(" validation failed for operation: "); stringBuilder.append(validationReportData.operationPathAdapter); validationReportData.report.getMessages() - .forEach(message -> stringBuilder.append("\n\t").append(message)); + .forEach(message -> stringBuilder.append("\n\t").append(message)); return stringBuilder.toString(); } @@ -106,14 +111,14 @@ private String constructErrorMessage(ValidationReportData validationReportData) */ private List findSchemaRepositories(TestContext context) { return new ArrayList<>( - context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); + context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); } @Nullable private ValidationReportData validate(TestContext context, - HttpMessage message, - List schemaRepositories, - OpenApiMessageValidationContext validationContext) { + HttpMessage message, + List schemaRepositories, + OpenApiMessageValidationContext validationContext) { schemaRepositories = schemaRepositories != null ? schemaRepositories : emptyList(); @@ -121,14 +126,14 @@ private ValidationReportData validate(TestContext context, return null; } else { String operationId = validationContext.getSchema() != null ? validationContext.getSchema() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); + : (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); String specificationId = validationContext.getSchemaRepository() != null - ? validationContext.getSchemaRepository() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_SPECIFICATION_ID); + ? validationContext.getSchemaRepository() + : (String) message.getHeader(OpenApiMessageHeaders.OAS_SPECIFICATION_ID); if (isNotEmpty(specificationId) && isNotEmpty(operationId)) { return validateOpenApiOperation(context, message, schemaRepositories, - specificationId, operationId); + specificationId, operationId); } return null; @@ -137,74 +142,74 @@ private ValidationReportData validate(TestContext context, } private ValidationReportData validateOpenApiOperation(TestContext context, HttpMessage message, - List schemaRepositories, String specificationId, String operationId) { + List schemaRepositories, String specificationId, String operationId) { OpenApiSpecification openApiSpecification = schemaRepositories - .stream() - .map(repository -> repository.openApi(specificationId)) - .filter(Objects::nonNull) - .findFirst() - .orElse((OpenApiSpecification) context.getVariables().get(specificationId)); + .stream() + .map(repository -> repository.openApi(specificationId)) + .filter(Objects::nonNull) + .findFirst() + .orElse((OpenApiSpecification) context.getVariables().get(specificationId)); if (openApiSpecification == null) { throw new CitrusRuntimeException(""" - Unable to derive OpenAPI spec for operation '%s' for validation of message from available " - schema repositories. Known repository aliases are: %s""".formatted( - operationId, - OpenApiUtils.getKnownOpenApiAliases(context.getReferenceResolver()))); + Unable to derive OpenAPI spec for operation '%s' for validation of message from available " + schema repositories. Known repository aliases are: %s""".formatted( + operationId, + OpenApiUtils.getKnownOpenApiAliases(context.getReferenceResolver()))); } OperationPathAdapter operationPathAdapter = openApiSpecification.getOperation( - operationId, context) - .orElseThrow(() -> new CitrusRuntimeException( - "Unexpectedly could not resolve operation path adapter for operationId: " - + operationId)); + operationId, context) + .orElseThrow(() -> new CitrusRuntimeException( + "Unexpectedly could not resolve operation path adapter for operationId: " + + operationId)); ValidationReportData validationReportData = null; if (isRequestMessage(message)) { ValidationReport validationReport = new OpenApiRequestValidator( - openApiSpecification) - .validateRequestToReport(operationPathAdapter, message); + openApiSpecification) + .validateRequestToReport(operationPathAdapter, message); validationReportData = new ValidationReportData(operationPathAdapter, "request", - validationReport); + validationReport); } else if (isResponseMessage(message)) { ValidationReport validationReport = new OpenApiResponseValidator( - openApiSpecification) - .validateResponseToReport(operationPathAdapter, message); + openApiSpecification) + .validateResponseToReport(operationPathAdapter, message); validationReportData = new ValidationReportData(operationPathAdapter, "response", - validationReport); + validationReport); } return validationReportData; } private boolean isResponseMessage(HttpMessage message) { return OpenApiMessageHeaders.RESPONSE_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( - HttpMessageHeaders.HTTP_STATUS_CODE) != null; + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( + HttpMessageHeaders.HTTP_STATUS_CODE) != null; } private boolean isRequestMessage(HttpMessage message) { return OpenApiMessageHeaders.REQUEST_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( - HttpMessageHeaders.HTTP_STATUS_CODE) == null; + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( + HttpMessageHeaders.HTTP_STATUS_CODE) == null; } @Override public boolean canValidate(Message message, boolean schemaValidationEnabled) { return schemaValidationEnabled - && message instanceof HttpMessage httpMessage - && (isRequestMessage(httpMessage) || isResponseMessage(httpMessage)); + && message instanceof HttpMessage httpMessage + && (isRequestMessage(httpMessage) || isResponseMessage(httpMessage)); } @Override public void validate(Message message, TestContext context, String schemaRepository, - String schema) { + String schema) { if (!(message instanceof HttpMessage)) { return; } validate(message, context, - new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) - .build()); + new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) + .build()); } From 44933c7b6e96377c91f9725d8c4c0ff7e998f4f0 Mon Sep 17 00:00:00 2001 From: muellerfluri Date: Wed, 15 Jan 2025 15:01:32 +0100 Subject: [PATCH 44/47] fix(api): rename the message variable to httpMessage because a type cast took place --- .../openapi/validation/OpenApiSchemaValidation.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index d004fcdaa0..f7ff665b36 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -65,11 +65,7 @@ public void validate(Message message, TestContext context, if (validationReportData != null && validationReportData.report != null) { if (validationReportData.report.hasErrors()) { - String path = "no Path because no httpMessage"; - if(message instanceof HttpMessage){ - path = ((HttpMessage) message).getPath(); - } - logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", message.getPayload(String.class), path); + logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", httpMessage.getPayload(String.class), httpMessage.getPath()); throw new ValidationException(constructErrorMessage(validationReportData)); } } From dc44aba9fa81333355f06bb1fa976abb17691685 Mon Sep 17 00:00:00 2001 From: muellerfluri Date: Wed, 15 Jan 2025 15:15:03 +0100 Subject: [PATCH 45/47] fix(api): redo the formatting as it was --- .../validation/OpenApiSchemaValidation.java | 105 +++++++++--------- 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index f7ff665b36..05f80224ec 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -5,11 +5,9 @@ import com.atlassian.oai.validator.report.ValidationReport; import jakarta.annotation.Nullable; - import java.util.ArrayList; import java.util.List; import java.util.Objects; - import org.citrusframework.context.TestContext; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; @@ -29,8 +27,8 @@ import org.slf4j.LoggerFactory; public class OpenApiSchemaValidation extends - AbstractMessageValidator implements - SchemaValidator { + AbstractMessageValidator implements + SchemaValidator { private static final Logger logger = LoggerFactory.getLogger(OpenApiSchemaValidation.class); @@ -41,16 +39,16 @@ protected Class getRequiredValidationContextTyp @Override public void validateMessage(Message receivedMessage, - Message controlMessage, - TestContext context, - OpenApiMessageValidationContext validationContext) { + Message controlMessage, + TestContext context, + OpenApiMessageValidationContext validationContext) { // No control message validation, only schema validation validate(receivedMessage, context, validationContext); } @Override public void validate(Message message, TestContext context, - OpenApiMessageValidationContext validationContext) { + OpenApiMessageValidationContext validationContext) { logger.debug("Starting OpenApi schema validation ..."); // In case we have a redirect header, we cannot validate the message, as we have to expect, that the message has no valid response. @@ -59,13 +57,14 @@ public void validate(Message message, TestContext context, } ValidationReportData validationReportData = validate(context, - httpMessage, - findSchemaRepositories(context), - validationContext); + httpMessage, + findSchemaRepositories(context), + validationContext); if (validationReportData != null && validationReportData.report != null) { if (validationReportData.report.hasErrors()) { - logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", httpMessage.getPayload(String.class), httpMessage.getPath()); + logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", + httpMessage.getPayload(String.class), httpMessage.getPath()); throw new ValidationException(constructErrorMessage(validationReportData)); } } @@ -86,9 +85,9 @@ public void validate(Message message, TestContext context, @Override public boolean supportsMessageType(String messageType, Message message) { return "JSON".equals(messageType) - || ( - message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class)) - || message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null); + || ( + message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class)) + || message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null); } private String constructErrorMessage(ValidationReportData validationReportData) { @@ -98,7 +97,7 @@ private String constructErrorMessage(ValidationReportData validationReportData) stringBuilder.append(" validation failed for operation: "); stringBuilder.append(validationReportData.operationPathAdapter); validationReportData.report.getMessages() - .forEach(message -> stringBuilder.append("\n\t").append(message)); + .forEach(message -> stringBuilder.append("\n\t").append(message)); return stringBuilder.toString(); } @@ -107,14 +106,14 @@ private String constructErrorMessage(ValidationReportData validationReportData) */ private List findSchemaRepositories(TestContext context) { return new ArrayList<>( - context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); + context.getReferenceResolver().resolveAll(OpenApiRepository.class).values()); } @Nullable private ValidationReportData validate(TestContext context, - HttpMessage message, - List schemaRepositories, - OpenApiMessageValidationContext validationContext) { + HttpMessage message, + List schemaRepositories, + OpenApiMessageValidationContext validationContext) { schemaRepositories = schemaRepositories != null ? schemaRepositories : emptyList(); @@ -122,14 +121,14 @@ private ValidationReportData validate(TestContext context, return null; } else { String operationId = validationContext.getSchema() != null ? validationContext.getSchema() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); + : (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); String specificationId = validationContext.getSchemaRepository() != null - ? validationContext.getSchemaRepository() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_SPECIFICATION_ID); + ? validationContext.getSchemaRepository() + : (String) message.getHeader(OpenApiMessageHeaders.OAS_SPECIFICATION_ID); if (isNotEmpty(specificationId) && isNotEmpty(operationId)) { return validateOpenApiOperation(context, message, schemaRepositories, - specificationId, operationId); + specificationId, operationId); } return null; @@ -138,74 +137,74 @@ private ValidationReportData validate(TestContext context, } private ValidationReportData validateOpenApiOperation(TestContext context, HttpMessage message, - List schemaRepositories, String specificationId, String operationId) { + List schemaRepositories, String specificationId, String operationId) { OpenApiSpecification openApiSpecification = schemaRepositories - .stream() - .map(repository -> repository.openApi(specificationId)) - .filter(Objects::nonNull) - .findFirst() - .orElse((OpenApiSpecification) context.getVariables().get(specificationId)); + .stream() + .map(repository -> repository.openApi(specificationId)) + .filter(Objects::nonNull) + .findFirst() + .orElse((OpenApiSpecification) context.getVariables().get(specificationId)); if (openApiSpecification == null) { throw new CitrusRuntimeException(""" - Unable to derive OpenAPI spec for operation '%s' for validation of message from available " - schema repositories. Known repository aliases are: %s""".formatted( - operationId, - OpenApiUtils.getKnownOpenApiAliases(context.getReferenceResolver()))); + Unable to derive OpenAPI spec for operation '%s' for validation of message from available " + schema repositories. Known repository aliases are: %s""".formatted( + operationId, + OpenApiUtils.getKnownOpenApiAliases(context.getReferenceResolver()))); } OperationPathAdapter operationPathAdapter = openApiSpecification.getOperation( - operationId, context) - .orElseThrow(() -> new CitrusRuntimeException( - "Unexpectedly could not resolve operation path adapter for operationId: " - + operationId)); + operationId, context) + .orElseThrow(() -> new CitrusRuntimeException( + "Unexpectedly could not resolve operation path adapter for operationId: " + + operationId)); ValidationReportData validationReportData = null; if (isRequestMessage(message)) { ValidationReport validationReport = new OpenApiRequestValidator( - openApiSpecification) - .validateRequestToReport(operationPathAdapter, message); + openApiSpecification) + .validateRequestToReport(operationPathAdapter, message); validationReportData = new ValidationReportData(operationPathAdapter, "request", - validationReport); + validationReport); } else if (isResponseMessage(message)) { ValidationReport validationReport = new OpenApiResponseValidator( - openApiSpecification) - .validateResponseToReport(operationPathAdapter, message); + openApiSpecification) + .validateResponseToReport(operationPathAdapter, message); validationReportData = new ValidationReportData(operationPathAdapter, "response", - validationReport); + validationReport); } return validationReportData; } private boolean isResponseMessage(HttpMessage message) { return OpenApiMessageHeaders.RESPONSE_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( - HttpMessageHeaders.HTTP_STATUS_CODE) != null; + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( + HttpMessageHeaders.HTTP_STATUS_CODE) != null; } private boolean isRequestMessage(HttpMessage message) { return OpenApiMessageHeaders.REQUEST_TYPE.equals( - message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( - HttpMessageHeaders.HTTP_STATUS_CODE) == null; + message.getHeader(OpenApiMessageHeaders.OAS_MESSAGE_TYPE)) || message.getHeader( + HttpMessageHeaders.HTTP_STATUS_CODE) == null; } @Override public boolean canValidate(Message message, boolean schemaValidationEnabled) { return schemaValidationEnabled - && message instanceof HttpMessage httpMessage - && (isRequestMessage(httpMessage) || isResponseMessage(httpMessage)); + && message instanceof HttpMessage httpMessage + && (isRequestMessage(httpMessage) || isResponseMessage(httpMessage)); } @Override public void validate(Message message, TestContext context, String schemaRepository, - String schema) { + String schema) { if (!(message instanceof HttpMessage)) { return; } validate(message, context, - new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) - .build()); + new Builder().schemaValidation(true).schema(schema).schemaRepository(schemaRepository) + .build()); } From 2a8ca5d0323f0a3c5837c0a8ebe6cb5427c1e9c8 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Fri, 24 Jan 2025 15:54:59 +0100 Subject: [PATCH 46/47] fix: add draft open api documentation --- .../openapi/OpenApiRepository.java | 87 +++++++-- .../openapi/OpenApiSpecification.java | 112 +++++++---- .../OpenApiClientRequestActionBuilder.java | 3 +- .../validation/OpenApiSchemaValidation.java | 23 ++- .../OpenApiValidationContextLoader.java | 71 +------ .../openapi/OpenApiRepositoryTest.java | 2 +- .../openapi/groovy/OpenApiClientTest.java | 8 +- .../OpenApiClientApiContextPathIT.java | 155 +++++++++++++++ .../openapi/integration/OpenApiClientIT.java | 83 ++++++--- .../openapi/integration/OpenApiServerIT.java | 174 +++++++++++------ .../openapi/xml/OpenApiClientTest.java | 18 +- .../openapi/yaml/OpenApiClientTest.java | 8 +- .../org/citrusframework/util/StringUtils.java | 6 +- .../citrusframework/util/StringUtilsTest.java | 2 + src/manual/connector-openapi.adoc | 95 +++++++++- .../RestApiSendMessageActionBuilder.java | 11 +- .../main/resources/java-citrus/api.mustache | 21 ++- .../resources/java-citrus/api_soap.mustache | 21 ++- .../java-citrus/bean_configuration.mustache | 4 +- .../openapi/generator/GeneratedRestApiIT.java | 26 +++ .../resources/apis/petstore-extended-v3.yaml | 32 ++++ .../rest/extpetstore/model/Category.java | 2 +- .../extpetstore/model/HistoricalData.java | 2 +- .../rest/extpetstore/model/Pet.java | 2 +- .../rest/extpetstore/model/PetIdentifier.java | 2 +- .../rest/extpetstore/model/Tag.java | 2 +- .../model/VaccinationDocumentResult.java | 2 +- .../rest/extpetstore/request/ExtPetApi.java | 176 +++++++++++++++++- .../spring/ExtPetStoreBeanConfiguration.java | 6 +- .../spring/ExtPetStoreNamespaceHandler.java | 8 +- .../rest/petstore/model/Address.java | 2 +- .../rest/petstore/model/Category.java | 2 +- .../rest/petstore/model/Customer.java | 2 +- .../rest/petstore/model/ModelApiResponse.java | 2 +- .../rest/petstore/model/Order.java | 2 +- .../expectedgen/rest/petstore/model/Pet.java | 2 +- .../expectedgen/rest/petstore/model/Tag.java | 2 +- .../expectedgen/rest/petstore/model/User.java | 2 +- .../rest/petstore/request/PetApi.java | 23 ++- .../rest/petstore/request/StoreApi.java | 23 ++- .../rest/petstore/request/UserApi.java | 23 ++- .../spring/PetStoreBeanConfiguration.java | 14 +- .../spring/PetStoreNamespaceHandler.java | 2 +- .../request/BookServiceSoapApi.java | 23 ++- .../spring/BookServiceBeanConfiguration.java | 6 +- .../spring/BookServiceNamespaceHandler.java | 2 +- .../plugin/TestApiGeneratorMojoUnitTest.java | 3 +- .../org/citrusframework/util/XMLUtils.java | 52 +++--- .../xml/DomXmlMessageValidator.java | 52 +----- .../xml/schema/XmlSchemaValidation.java | 22 +-- 50 files changed, 1013 insertions(+), 412 deletions(-) create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientApiContextPathIT.java diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 65607479e4..788635ebeb 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -16,8 +16,12 @@ package org.citrusframework.openapi; +import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.synchronizedList; +import static org.citrusframework.openapi.OpenApiSettings.isNeglectBasePathGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; +import static org.citrusframework.openapi.OpenApiSettings.isResponseValidationEnabledGlobally; import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; @@ -28,6 +32,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.citrusframework.repository.BaseRepository; import org.citrusframework.spi.Resource; @@ -57,11 +62,22 @@ public class OpenApiRepository extends BaseRepository { */ private String rootContextPath; - private boolean requestValidationEnabled = true; + /** + * Flag to indicate whether the base path of the OpenAPI should be part of the path or not. + */ + private boolean neglectBasePath = isNeglectBasePathGlobally(); + + /** + * Flag to indicate whether OpenAPIs managed by this repository should perform request validation. + */ + private boolean requestValidationEnabled = isRequestValidationEnabledGlobally(); - private boolean responseValidationEnabled = true; + /** + * Flag to indicate whether OpenAPIs managed by this repository should perform response validation. + */ + private boolean responseValidationEnabled = isResponseValidationEnabledGlobally(); - private OpenApiValidationPolicy openApiValidationPolicy = OpenApiSettings.getOpenApiValidationPolicy(); + private OpenApiValidationPolicy validationPolicy = OpenApiSettings.getOpenApiValidationPolicy(); public OpenApiRepository() { super(DEFAULT_NAME); @@ -124,6 +140,24 @@ public void setRootContextPath(String rootContextPath) { this.rootContextPath = rootContextPath; } + public OpenApiRepository rootContextPath(String rootContextPath) { + setRootContextPath(rootContextPath); + return this; + } + + public boolean isNeglectBasePath() { + return neglectBasePath; + } + + public void setNeglectBasePath(boolean neglectBasePath) { + this.neglectBasePath = neglectBasePath; + } + + public OpenApiRepository neglectBasePath(boolean neglectBasePath) { + setNeglectBasePath(neglectBasePath); + return this; + } + public boolean isRequestValidationEnabled() { return requestValidationEnabled; } @@ -132,6 +166,11 @@ public void setRequestValidationEnabled(boolean requestValidationEnabled) { this.requestValidationEnabled = requestValidationEnabled; } + public OpenApiRepository requestValidationEnabled(boolean requestValidationEnabled) { + setRequestValidationEnabled(requestValidationEnabled); + return this; + } + public boolean isResponseValidationEnabled() { return responseValidationEnabled; } @@ -140,15 +179,24 @@ public void setResponseValidationEnabled(boolean responseValidationEnabled) { this.responseValidationEnabled = responseValidationEnabled; } - public OpenApiValidationPolicy getOpenApiValidationPolicy() { - return openApiValidationPolicy; + public OpenApiRepository responseValidationEnabled(boolean responseValidationEnabled) { + setResponseValidationEnabled(responseValidationEnabled); + return this; } - public void setOpenApiValidationPolicy( - OpenApiValidationPolicy openApiValidationPolicy) { - this.openApiValidationPolicy = openApiValidationPolicy; + public OpenApiValidationPolicy getValidationPolicy() { + return validationPolicy; } + public void setValidationPolicy( + OpenApiValidationPolicy validationPolicy) { + this.validationPolicy = validationPolicy; + } + + public OpenApiRepository validationPolicy(OpenApiValidationPolicy openApiValidationPolicy) { + setValidationPolicy(openApiValidationPolicy); + return this; + } /** * Adds an OpenAPI Specification specified by the given resource to the repository. If an alias @@ -158,14 +206,21 @@ public void setOpenApiValidationPolicy( */ @Override public void addRepository(Resource openApiResource) { - OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource, - openApiValidationPolicy); - determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); - openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); - openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); - openApiSpecification.setRootContextPath(rootContextPath); - - addRepository(openApiSpecification); + + try { + OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource, + validationPolicy); + determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); + openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); + openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); + openApiSpecification.setRootContextPath(rootContextPath); + openApiSpecification.neglectBasePath(neglectBasePath); + addRepository(openApiSpecification); + } catch (Exception e) { + logger.error(format("Unable to read OpenApiSpecification from location: %s", openApiResource.getURI())); + throw new CitrusRuntimeException(e); + } + } /** diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index 9b8f8143a8..b3e4585fe4 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -86,8 +86,10 @@ public class OpenApiSpecification { private static final String HTTP = "http"; /** - * An uid to uniquely identify this specification at runtime. The uid is based on the SHA of the - * OpenAPI document and the root context, to which it is attached. + * A unique identifier (UID) for this specification at runtime. The UID is generated based on the SHA + * of the OpenAPI document combined with the full context path to which the API is attached. + * + * @see OpenApiSpecification#determineUid for detailed information on how the UID is generated. */ private String uid; @@ -221,18 +223,16 @@ public static OpenApiSpecification from(URL specUrl, OpenApiValidationContext openApiValidationContext; if (specUrl.getProtocol().startsWith(HTTPS)) { openApiDoc = OpenApiResourceLoader.fromSecuredWebResource(specUrl); - openApiValidationContext = OpenApiValidationContextLoader.fromSecuredWebResource( - specUrl); } else { openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); - openApiValidationContext = OpenApiValidationContextLoader.fromWebResource(specUrl, - openApiValidationPolicy); } + openApiValidationContext = OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), openApiValidationPolicy); + specification.setOpenApiValidationContext(openApiValidationContext); + specification.setSpecUrl(specUrl.toString()); specification.initPathLookups(); specification.setOpenApiDoc(openApiDoc); - specification.setOpenApiValidationContext(openApiValidationContext); specification.setRequestUrl( format("%s://%s%s%s", specUrl.getProtocol(), specUrl.getHost(), specUrl.getPort() > 0 ? ":" + specUrl.getPort() : "", @@ -267,7 +267,7 @@ public static OpenApiSpecification from(Resource resource, OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); specification.setOpenApiValidationContext( - OpenApiValidationContextLoader.fromFile(resource, openApiValidationPolicy)); + OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), openApiValidationPolicy)); specification.setOpenApiDoc(openApiDoc); String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -280,7 +280,7 @@ public static OpenApiSpecification from(Resource resource, specification.setSpecUrl(resource.getLocation()); specification.setRequestUrl( format("%s://%s%s", schemeToUse, OasModelHelper.getHost(openApiDoc), - specification.rootContextPath)); + getBasePath(openApiDoc))); return specification; } @@ -314,10 +314,21 @@ public static OpenApiSpecification fromString(String openApi) { return specification; } + /** + * Get the UID of this specification. + */ public String getUid() { return uid; } + /** + * Get the unique id of the given operation. + */ + @SuppressWarnings("unused") + public String getUniqueId(OasOperation oasOperation) { + return operationToUniqueId.get(oasOperation); + } + public synchronized OasDocument getOpenApiDoc(TestContext context) { if (openApiDoc != null) { return openApiDoc; @@ -351,13 +362,8 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { URL specWebResource = toSpecUrl(resolvedSpecUrl); if (resolvedSpecUrl.startsWith(HTTPS)) { initApiDoc(() -> OpenApiResourceLoader.fromSecuredWebResource(specWebResource)); - setOpenApiValidationContext( - OpenApiValidationContextLoader.fromSecuredWebResource(specWebResource)); } else { initApiDoc(() -> OpenApiResourceLoader.fromWebResource(specWebResource)); - setOpenApiValidationContext( - OpenApiValidationContextLoader.fromWebResource(specWebResource, - openApiValidationPolicy)); } if (requestUrl == null) { @@ -370,8 +376,7 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { } else { Resource resource = Resources.create(resolvedSpecUrl); initApiDoc(() -> OpenApiResourceLoader.fromFile(resource)); - setOpenApiValidationContext(OpenApiValidationContextLoader.fromFile(resource, - openApiValidationPolicy)); + if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) @@ -388,6 +393,10 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { } } + setOpenApiValidationContext( + OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), + openApiValidationPolicy)); + return openApiDoc; } @@ -427,8 +436,7 @@ private void initPathLookups() { return; } - uid = DigestUtils.sha256Hex(OasModelHelper.toJson(openApiDoc) + rootContextPath); - aliases.add(uid); + determineUid(); operationIdToOperationPathAdapter.clear(); OasModelHelper.visitOasOperations(this.openApiDoc, (oasPathItem, oasOperation) -> { @@ -446,6 +454,14 @@ private void initPathLookups() { }); } + private void determineUid() { + if (uid != null) { + aliases.remove(uid); + } + uid = DigestUtils.sha256Hex(OasModelHelper.toJson(openApiDoc) + getFullContextPath()); + aliases.add(uid); + } + /** * Stores an {@link OperationPathAdapter} in * {@link org.citrusframework.openapi.OpenApiSpecification#operationIdToOperationPathAdapter}. @@ -470,6 +486,7 @@ private void storeOperationPathAdapter(OasOperation operation, OasPathItem pathI appendSegmentToUrlPath(fullContextPath, path), operation, uniqueOperationId); operationIdToOperationPathAdapter.put(uniqueOperationId, operationPathAdapter); + if (hasText(operation.operationId)) { operationIdToOperationPathAdapter.put(operation.operationId, operationPathAdapter); } @@ -556,8 +573,9 @@ public void setRootContextPath(String rootContextPath) { initPathLookups(); } - public OpenApiValidationPolicy getOpenApiValidationPolicy() { - return openApiValidationPolicy; + public OpenApiSpecification rootContextPath(String rootContextPath) { + setRootContextPath(rootContextPath); + return this; } public void addAlias(String alias) { @@ -608,15 +626,6 @@ public void initOpenApiDoc(TestContext context) { } } - public OpenApiSpecification withRootContext(String rootContextPath) { - setRootContextPath(rootContextPath); - return this; - } - - public String getUniqueId(OasOperation oasOperation) { - return operationToUniqueId.get(oasOperation); - } - /** * Get the full path for the given {@link OasPathItem}. *

        @@ -633,12 +642,31 @@ public String getUniqueId(OasOperation oasOperation) { * item */ public String getFullPath(OasPathItem oasPathItem) { + return appendSegmentToUrlPath(rootContextPath, + getFullBasePath(oasPathItem)); + } + + /** + * Get the full base-path for the given {@link OasPathItem}. + *

        + * The full base-path is constructed by concatenating the base path (if + * applicable), and the path of the given {@code oasPathItem}. The resulting format is: + *

        + *
        +     * /basePath/pathItemPath
        +     * 
        + * If the base path is to be neglected, it is excluded from the final constructed path. + * + * @param oasPathItem the OpenAPI path item whose full base-path is to be constructed + * @return the full base URL path, consisting of the base path, and the given path + * item + */ + public String getFullBasePath(OasPathItem oasPathItem) { return appendSegmentToUrlPath( - appendSegmentToUrlPath(rootContextPath, - neglectBasePath ? null : getBasePath(openApiDoc)), - oasPathItem.getPath()); + getApplicableBasePath(), oasPathItem.getPath()); } + /** * Constructs the full context path for the given {@link OasPathItem}. *

        @@ -654,7 +682,7 @@ public String getFullPath(OasPathItem oasPathItem) { */ public String getFullContextPath() { return appendSegmentToUrlPath(rootContextPath, - neglectBasePath ? null : getBasePath(openApiDoc)); + getApplicableBasePath()); } /** @@ -674,9 +702,23 @@ public void setNeglectBasePath(boolean neglectBasePath) { } public OpenApiSpecification neglectBasePath(boolean neglectBasePath) { - this.neglectBasePath = neglectBasePath; - initPathLookups(); + setNeglectBasePath(neglectBasePath); return this; } + /** + * Gets the base path if basePath should be applied. + */ + private String getApplicableBasePath() { + return neglectBasePath ? "" : getBasePath(openApiDoc); + } + + + /** + * Add another alias for this specification. + */ + public OpenApiSpecification alias(String alias) { + addAlias(alias); + return this; + } } diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java index a14a48e931..84f5305214 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java @@ -129,6 +129,7 @@ public static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilde private final String operationId; + // TODO: document me private AutoFillType autoFill = OpenApiSettings.getRequestAutoFillRandomValues(); public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage, @@ -175,7 +176,7 @@ private void buildMessageFromOperation(OpenApiSpecification openApiSpecification OperationPathAdapter operationPathAdapter, TestContext context) { OasOperation operation = operationPathAdapter.operation(); - String path = operationPathAdapter.apiPath(); + String path = operationPathAdapter.fullPath(); HttpMethod method = HttpMethod.valueOf( operationPathAdapter.operation().getMethod().toUpperCase(Locale.US)); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java index 05f80224ec..1118117faa 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiSchemaValidation.java @@ -1,6 +1,8 @@ package org.citrusframework.openapi.validation; import static java.util.Collections.emptyList; +import static org.citrusframework.openapi.OpenApiMessageHeaders.OAS_SPECIFICATION_ID; +import static org.citrusframework.openapi.OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID; import static org.citrusframework.util.StringUtils.isNotEmpty; import com.atlassian.oai.validator.report.ValidationReport; @@ -61,12 +63,15 @@ public void validate(Message message, TestContext context, findSchemaRepositories(context), validationContext); - if (validationReportData != null && validationReportData.report != null) { - if (validationReportData.report.hasErrors()) { - logger.error("Failed to validate Json schema for message:\n{}\nand origin path:\n{}", - httpMessage.getPayload(String.class), httpMessage.getPath()); - throw new ValidationException(constructErrorMessage(validationReportData)); + if (validationReportData != null + && validationReportData.report != null + && validationReportData.report.hasErrors()) { + if (logger.isErrorEnabled()) { + logger.error( + "Failed to validate Json schema for message:\n{}\nand origin path:\n{}", + httpMessage.getPayload(String.class), httpMessage.getPath()); } + throw new ValidationException(constructErrorMessage(validationReportData)); } logger.debug("Json schema validation successful: All values OK"); @@ -86,8 +91,8 @@ public void validate(Message message, TestContext context, public boolean supportsMessageType(String messageType, Message message) { return "JSON".equals(messageType) || ( - message != null && IsJsonPredicate.getInstance().test(message.getPayload(String.class)) - || message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID) != null); + message != null && (IsJsonPredicate.getInstance().test(message.getPayload(String.class)) + || message.getHeader(OAS_UNIQUE_OPERATION_ID) != null)); } private String constructErrorMessage(ValidationReportData validationReportData) { @@ -121,10 +126,10 @@ private ValidationReportData validate(TestContext context, return null; } else { String operationId = validationContext.getSchema() != null ? validationContext.getSchema() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_UNIQUE_OPERATION_ID); + : (String) message.getHeader(OAS_UNIQUE_OPERATION_ID); String specificationId = validationContext.getSchemaRepository() != null ? validationContext.getSchemaRepository() - : (String) message.getHeader(OpenApiMessageHeaders.OAS_SPECIFICATION_ID); + : (String) message.getHeader(OAS_SPECIFICATION_ID); if (isNotEmpty(specificationId) && isNotEmpty(operationId)) { return validateOpenApiOperation(context, message, schemaRepositories, diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java index ceb44ae74e..a2a14fe775 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/validation/OpenApiValidationContextLoader.java @@ -29,7 +29,6 @@ import io.swagger.v3.parser.core.models.ParseOptions; import io.swagger.v3.parser.core.models.SwaggerParseResult; import jakarta.annotation.Nonnull; -import java.net.URL; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -37,7 +36,6 @@ import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.exceptions.ValidationException; import org.citrusframework.openapi.OpenApiResourceLoader; -import org.citrusframework.spi.Resource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,73 +57,12 @@ private OpenApiValidationContextLoader() { // Static access only } - /** - * Creates an OpenApiValidationContext from a secured OpenAPI web resource. - * - * @param url the URL of the secured OpenAPI web resource - * @return the OpenApiValidationContext - */ - public static OpenApiValidationContext fromSecuredWebResource(@Nonnull URL url) { - return createValidationContext(new OpenApiLoader().loadApi( - SpecSource.inline(OpenApiResourceLoader.rawFromSecuredWebResource(url)), emptyList(), - defaultParseOptions())); - } - - /** - * Creates an OpenApiValidationContext from an OpenAPI web resource. - * - * @param url the URL of the OpenAPI web resource - * @return the OpenApiValidationContext - */ - public static OpenApiValidationContext fromWebResource(@Nonnull URL url, - OpenApiValidationPolicy openApiValidationPolicy) { - return createValidationContext( - loadOpenApi(url.toString(), - SpecSource.inline(OpenApiResourceLoader.rawFromWebResource(url)), - openApiValidationPolicy)); - } - - /** - * Creates an OpenApiValidationContext from an OpenAPI file. - * - * @param resource the resource containing the OpenAPI specification - * @param openApiValidationPolicy the policy used for validation of the OpenApi - * @return the OpenApiValidationContext - */ - public static OpenApiValidationContext fromFile(@Nonnull Resource resource, + public static OpenApiValidationContext fromSpec(String openApiSpecAsString, OpenApiValidationPolicy openApiValidationPolicy) { - return createValidationContext( - loadOpenApi(resource.getLocation(), - SpecSource.inline(OpenApiResourceLoader.rawFromFile(resource)), - openApiValidationPolicy)); - } - - private static OpenAPI loadOpenApi(String identifier, SpecSource specSource, - OpenApiValidationPolicy openApiValidationPolicy) { - - logger.debug("Loading OpenApi: {}", identifier); - OpenAPIParser openAPIParser = new OpenAPIParser(); - - SwaggerParseResult swaggerParseResult; - if (specSource.isInlineSpecification()) { - swaggerParseResult = openAPIParser.readContents(specSource.getValue(), emptyList(), - defaultParseOptions()); - } else if (specSource.isSpecUrl()) { - swaggerParseResult = openAPIParser.readLocation(specSource.getValue(), emptyList(), - defaultParseOptions()); - } else { - // Try to load as a URL first... - swaggerParseResult = openAPIParser.readLocation(specSource.getValue(), emptyList(), - defaultParseOptions()); - if (swaggerParseResult == null) { - // ...then try to load as a content string - swaggerParseResult = openAPIParser.readContents(specSource.getValue(), emptyList(), - defaultParseOptions()); - } - } - - return handleSwaggerParserResult(identifier, swaggerParseResult, openApiValidationPolicy); + return createValidationContext( + handleSwaggerParserResult(openApiSpecAsString, openAPIParser.readContents(openApiSpecAsString, emptyList(), + defaultParseOptions()), openApiValidationPolicy)); } private static OpenAPI handleSwaggerParserResult(String identifier, diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java index 5940039ec4..817b06825d 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java @@ -82,7 +82,7 @@ public void shouldInitializeFaultyOpenApiRepositoryByDefault() { @Test public void shouldFailOnFaultyOpenApiRepositoryByStrictValidation() { OpenApiRepository openApiRepository = new OpenApiRepository(); - openApiRepository.setOpenApiValidationPolicy(OpenApiValidationPolicy.STRICT); + openApiRepository.setValidationPolicy(OpenApiValidationPolicy.STRICT); openApiRepository.setLocations( singletonList("org/citrusframework/openapi/faulty/faulty-ping-api.yaml")); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java index 7ce3343f5b..bc9a4d14b9 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/groovy/OpenApiClientTest.java @@ -167,8 +167,8 @@ public void shouldLoadOpenApiClientActions() { assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); - assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet/${petId}"); - assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet/${petId}"); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet/${petId}"); + assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet/${petId}"); assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); assertEquals(sendMessageAction.getEndpoint(), httpClient); @@ -209,8 +209,8 @@ public void shouldLoadOpenApiClientActions() { Map requestHeaders = httpMessageBuilder.buildMessageHeaders(context); assertEquals(requestHeaders.size(), 4L); assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); - assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); - assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); + assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet"); + assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet"); assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); assertNull(sendMessageAction.getEndpointUri()); assertEquals(sendMessageAction.getEndpoint(), httpClient); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientApiContextPathIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientApiContextPathIT.java new file mode 100644 index 0000000000..f3386fcc41 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientApiContextPathIT.java @@ -0,0 +1,155 @@ +/* + * Copyright the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.citrusframework.openapi.integration; + +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; + +import org.citrusframework.annotations.CitrusTest; +import org.citrusframework.http.client.HttpClient; +import org.citrusframework.http.client.HttpClientBuilder; +import org.citrusframework.http.server.HttpServer; +import org.citrusframework.http.server.HttpServerBuilder; +import org.citrusframework.openapi.AutoFillType; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.openapi.integration.OpenApiClientIT.Config; +import org.citrusframework.spi.Resources; +import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; +import org.citrusframework.util.SocketUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ContextConfiguration; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * This integration test demonstrates how to configure and test OpenAPI specifications with different context paths + * using the Citrus framework. {@link OpenApiSpecification}s can be hooked to different context paths, with detailed control + * over how the context path is constructed. + *

        + * By default, the basePath from the OpenAPI specification is used. If the basePath is not present, the plain operation + * path is used. However, you can configure detailed control over the context path using the `contextPath` and `neglectBasePath` properties. + *

        + * The test uses these specifications with different context paths to verify the correct API paths are used in the HTTP requests and responses. + * + * @see OpenApiSpecification + * @see CitrusTest + */ +@Test +@ContextConfiguration(classes = {Config.class}) +public class OpenApiClientApiContextPathIT extends TestNGCitrusSpringSupport { + + public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; + + @Autowired + private HttpServer httpServer; + + @Autowired + private HttpClient httpClient; + + private static final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .alias("spec1"); + + private static final OpenApiSpecification petstoreSpecNeglectingBasePath = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .alias("spec2") + .neglectBasePath(true); + + private static final OpenApiSpecification petstoreSpecWithContextPath = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .alias("spec3") + .rootContextPath("/api"); + + private static final OpenApiSpecification petstoreSpecWithContextPathNeglectingBasePath = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .alias("spec4") + .neglectBasePath(true) + .rootContextPath("/api"); + + @DataProvider + public static Object[][] openApiSpecifications() { + return new Object[][]{ + {petstoreSpec, "/petstore/v3/pet"}, + {petstoreSpecNeglectingBasePath, "/pet"}, + {petstoreSpecWithContextPath, "/api/petstore/v3/pet"}, + {petstoreSpecWithContextPathNeglectingBasePath, "/api/pet"}, + }; + } + + @CitrusTest + @Test(dataProvider = "openApiSpecifications") + public void shouldExecuteGetPetById(OpenApiSpecification spec, String contextPath) { + + variable("petId", "1001"); + + when(openapi(spec) + .client(httpClient) + .send("getPetById") + .autoFill(AutoFillType.ALL) + .message() + .fork(true)); + + then(http().server(httpServer) + .receive() + .get(contextPath+"/1001") + .message() + .accept("@contains('application/json')@")); + + then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType(APPLICATION_JSON_VALUE)); + + then(openapi(spec) + .client(httpClient).receive("getPetById", OK) + .schemaValidation(true)); + + } + + + @Configuration + public static class Config { + + private final int port = SocketUtils.findAvailableTcpPort(8080); + + @Bean + public HttpServer httpServer() { + + return new HttpServerBuilder() + .port(port) + .timeout(5000L) + .autoStart(true) + .defaultStatus(HttpStatus.NO_CONTENT) + .build(); + } + + @Bean + public HttpClient httpClient() { + return new HttpClientBuilder() + .requestUrl("http://localhost:%d".formatted(port)) + .build(); + } + + } +} diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java index c11171e9c8..6b563cf507 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java @@ -36,9 +36,9 @@ import org.citrusframework.message.MessageType; import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiRepository; -import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder; import org.citrusframework.openapi.integration.OpenApiClientIT.Config; +import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.citrusframework.spi.Resources; import org.citrusframework.testng.spring.TestNGCitrusSpringSupport; import org.citrusframework.util.SocketUtils; @@ -57,9 +57,6 @@ public class OpenApiClientIT extends TestNGCitrusSpringSupport { public static final String VALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet.json"; public static final String INVALID_PET_PATH = "classpath:org/citrusframework/openapi/petstore/pet_invalid.json"; - private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( - Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); - @Autowired private HttpServer httpServer; @@ -72,7 +69,7 @@ public void shouldExecuteGetPetById() { variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi("petstore-v3") .client(httpClient) .send("getPetById") .autoFill(AutoFillType.ALL) @@ -81,7 +78,7 @@ public void shouldExecuteGetPetById() { then(http().server(httpServer) .receive() - .get("/pet/${petId}") + .get("/pet/1001") .message() .accept("@contains('application/json')@")); @@ -92,7 +89,7 @@ public void shouldExecuteGetPetById() { .body(Resources.create(VALID_PET_PATH)) .contentType(APPLICATION_JSON_VALUE)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .client(httpClient).receive("getPetById", OK) .schemaValidation(true)); @@ -104,7 +101,7 @@ public void shouldFailOnMissingNameInResponse() { variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi("petstore-v3") .client(httpClient) .send("getPetById") .autoFill(AutoFillType.ALL) @@ -124,7 +121,7 @@ public void shouldFailOnMissingNameInResponse() { .body(Resources.create(INVALID_PET_PATH)) .contentType(APPLICATION_JSON_VALUE)); - OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi(petstoreSpec) + OpenApiClientResponseActionBuilder clientResponseActionBuilder = openapi("petstore-v3") .client(httpClient).receive("getPetById", OK) .schemaValidation(true); assertThrows(() -> then(clientResponseActionBuilder)); @@ -159,6 +156,8 @@ public void shouldFailOnMissingNameInResponseWhenUsingExplicitSchemaValidation() .body(Resources.create(INVALID_PET_PATH)) .contentType(APPLICATION_JSON_VALUE)); + // We can validate an OpenAPI response against a specific schema, + // even without using open api client. HttpClientResponseActionBuilder.HttpMessageBuilderSupport receiveGetPetById = http().client( httpClient) .receive() @@ -167,7 +166,7 @@ public void shouldFailOnMissingNameInResponseWhenUsingExplicitSchemaValidation() .type(MessageType.JSON) .validate(openApi(null) .schemaValidation(true) - .schemaRepository(petstoreSpec.getUid()) + .schemaRepository("petstore-v3.json") .schema("getPetById")); assertThrows(TestCaseFailedException.class, () -> then(receiveGetPetById)); @@ -180,7 +179,7 @@ public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi("petstore-v3") .client(httpClient) .send("getPetById") .autoFill(AutoFillType.ALL) @@ -200,7 +199,7 @@ public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { .body(Resources.create(INVALID_PET_PATH)) .contentType(APPLICATION_JSON_VALUE)); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .client(httpClient).receive("getPetById", OK) .schemaValidation(false)); @@ -208,10 +207,10 @@ public void shouldSucceedOnMissingNameInResponseWithValidationDisabled() { @CitrusTest @Test - public void shouldProperlyExecuteGetAndAddPetFromRepository() { + public void shouldProperlyExecuteAddPetFromRepository() { variable("petId", "1001"); - when(openapi(petstoreSpec) + when(openapi("petstore-v3") .client(httpClient) .send("addPet") .autoFill(AutoFillType.ALL) @@ -241,7 +240,7 @@ public void shouldProperlyExecuteGetAndAddPetFromRepository() { .response(HttpStatus.CREATED) .message()); - then(openapi(petstoreSpec) + then(openapi("petstore-v3") .client(httpClient) .receive("addPet", HttpStatus.CREATED)); @@ -252,7 +251,7 @@ public void shouldProperlyExecuteGetAndAddPetFromRepository() { public void shouldFailOnMissingNameInRequest() { variable("petId", "1001"); - HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + HttpMessageBuilderSupport addPetBuilder = openapi("petstore-v3") .client(httpClient) .send("addPet") .message().body(Resources.create(INVALID_PET_PATH)); @@ -264,7 +263,7 @@ public void shouldFailOnMissingNameInRequest() { @Test public void shouldFailOnWrongQueryIdType() { variable("petId", "xxxx"); - HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + HttpMessageBuilderSupport addPetBuilder = openapi("petstore-v3") .client(httpClient) .send("addPet") .message().body(Resources.create(VALID_PET_PATH)); @@ -275,7 +274,7 @@ public void shouldFailOnWrongQueryIdType() { @Test public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { variable("petId", "xxxx"); - HttpMessageBuilderSupport addPetBuilder = openapi(petstoreSpec) + HttpMessageBuilderSupport addPetBuilder = openapi("petstore-v3") .client(httpClient) .send("addPet") .schemaValidation(false) @@ -289,9 +288,47 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { } - @DataProvider(name = "pingApiOperationDataprovider") - public static Object[][] pingApiOperationDataprovider() { - return new Object[][]{{"doPing"}, {"doPong"}, {"doPung"}}; + @DataProvider + public Object[][] aliases() { + return new Object[][] { + {"petstore-v3"}, + {"Swagger Petstore"}, + {"Swagger Petstore/1.0.1"}, + }; + } + + /** + * Using OpenApiRepository, we should be able to resolve the OpenAPI spec from the name of the + * spec file or one of its aliases. + */ + @CitrusTest + @Test(dataProvider = "aliases") + public void getPetByIdUsingOpenApiRepositoryAndAlias(String alias) { + variable("petId", "1001"); + + when(openapi(alias) + .client(httpClient) + .send("getPetById") + .autoFill(AutoFillType.ALL) + .message() + .fork(true)); + + then(http().server(httpServer) + .receive() + .get("/pet/${petId}") + .message() + .accept("@contains('application/json')@")); + + then(http().server(httpServer) + .send() + .response(OK) + .message() + .body(Resources.create(VALID_PET_PATH)) + .contentType(APPLICATION_JSON_VALUE)); + + then(openapi(alias) + .client(httpClient).receive("getPetById", OK) + .schemaValidation(true)); } @Configuration @@ -321,7 +358,9 @@ public HttpClient httpClient() { public OpenApiRepository petstoreOpenApiRepository() { return new OpenApiRepository() .locations(singletonList( - "classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); + "classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .neglectBasePath(true) + .validationPolicy(OpenApiValidationPolicy.REPORT); } } } diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java index 89831f15a2..1a1a19e820 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiServerIT.java @@ -16,6 +16,13 @@ package org.citrusframework.openapi.integration; +import static java.util.Collections.singletonList; +import static org.citrusframework.http.actions.HttpActionBuilder.http; +import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.fail; + import org.citrusframework.annotations.CitrusTest; import org.citrusframework.exceptions.TestCaseFailedException; import org.citrusframework.http.actions.HttpServerResponseActionBuilder.HttpMessageBuilderSupport; @@ -25,6 +32,7 @@ import org.citrusframework.http.server.HttpServerBuilder; import org.citrusframework.openapi.AutoFillType; import org.citrusframework.openapi.OpenApiRepository; +import org.citrusframework.openapi.OpenApiSpecification; import org.citrusframework.openapi.actions.OpenApiActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder; import org.citrusframework.openapi.actions.OpenApiServerResponseActionBuilder; @@ -37,15 +45,9 @@ import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatus; import org.springframework.test.context.ContextConfiguration; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; -import static java.util.Collections.singletonList; -import static org.citrusframework.http.actions.HttpActionBuilder.http; -import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.testng.Assert.assertThrows; -import static org.testng.Assert.fail; - @Test @ContextConfiguration(classes = {Config.class}) public class OpenApiServerIT extends TestNGCitrusSpringSupport { @@ -59,22 +61,11 @@ public class OpenApiServerIT extends TestNGCitrusSpringSupport { @Autowired private HttpClient httpClient; - @CitrusTest - public void shouldExecuteGetPetById() { - executeGetPetById(HttpStatus.OK); - } + private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json")); - /** - * Sending an open api response with a status not specified in the spec should not fail. - * This is because the OpenAPI spec does not strictly require modelling of all possible - * responses. - */ @CitrusTest - public void shouldExecuteGetPetByIdWithUnknownResponse() { - executeGetPetById(HttpStatus.CREATED); - } - - private void executeGetPetById(HttpStatus httpStatus) { + public void getPetById() { variable("petId", "1001"); when(http() @@ -85,13 +76,14 @@ private void executeGetPetById(HttpStatus httpStatus) { .accept(APPLICATION_JSON_VALUE) .fork(true)); - then(openapi("petstore-v3") + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById") .message() ); - then(openapi("petstore-v3") + HttpStatus httpStatus = HttpStatus.OK; + then(openapi(petstoreSpec) .server(httpServer) .send("getPetById", httpStatus)); @@ -115,32 +107,42 @@ private void executeGetPetById(HttpStatus httpStatus) { """)); } + /** + * Sending an open api response with a status not specified in the spec should not fail. + * This is because the OpenAPI spec does not strictly require modelling of all possible + * responses. + */ @CitrusTest - public void shouldExecuteGetPetByIdWithRandomizedId() { + public void getPetByIdWithUnknownResponse() { + variable("petId", "1001"); + when(http() - .client(httpClient) - .send() - .get("/pet/726354") - .message() - .accept(APPLICATION_JSON_VALUE) - .fork(true)); + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); - then(openapi("petstore-v3") - .server(httpServer) - .receive("getPetById") - .message() + then(openapi(petstoreSpec) + .server(httpServer) + .receive("getPetById") + .message() ); - then(openapi("petstore-v3") - .server(httpServer) - .send("getPetById", HttpStatus.OK)); + // Fake any unexpected status code, to test whether we do not run into + // validation issues. + HttpStatus httpStatus = HttpStatus.CREATED; + then(openapi(petstoreSpec) + .server(httpServer) + .send("getPetById", httpStatus)); then(http() - .client(httpClient) - .receive() - .response(HttpStatus.OK) - .message() - .body(""" + .client(httpClient) + .receive() + .response(httpStatus) + .message() + .body(""" { "id": "@isNumber()@", "name": "@notEmpty()@", @@ -155,8 +157,9 @@ public void shouldExecuteGetPetByIdWithRandomizedId() { """)); } + @CitrusTest - public void executeGetPetByIdShouldFailOnInvalidResponse() { + public void getPetByIdShouldFailOnInvalidResponse() { variable("petId", "1001"); when(http() @@ -167,11 +170,11 @@ public void executeGetPetByIdShouldFailOnInvalidResponse() { .accept(APPLICATION_JSON_VALUE) .fork(true)); - then(openapi("petstore-v3") + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById")); - HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) .server(httpServer) .send("getPetById", HttpStatus.OK) .message().body(""" @@ -191,7 +194,7 @@ public void executeGetPetByIdShouldFailOnInvalidResponse() { } @CitrusTest - public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisabled() { + public void getPetByIdShouldSucceedOnInvalidResponseWithValidationDisabled() { variable("petId", "1001"); when(http() @@ -202,11 +205,11 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable .accept(APPLICATION_JSON_VALUE) .fork(true)); - then(openapi("petstore-v3") + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById")); - HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi("petstore-v3") + HttpMessageBuilderSupport getPetByIdResponseBuilder = openapi(petstoreSpec) .server(httpServer) .send("getPetById", HttpStatus.OK) .schemaValidation(false) @@ -247,17 +250,17 @@ public void executeGetPetByIdShouldSucceedOnInvalidResponseWithValidationDisable @CitrusTest public void shouldExecuteAddPet() { - shouldExecuteAddPet(openapi("petstore-v3"), VALID_PET_PATH, true, true); + shouldExecuteAddPet(openapi(petstoreSpec), VALID_PET_PATH, true, true); } @CitrusTest public void shouldFailOnMissingNameInRequest() { - shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false, true); + shouldExecuteAddPet(openapi(petstoreSpec), INVALID_PET_PATH, false, true); } @CitrusTest public void shouldPassOnMissingNameInRequestIfValidationIsDisabled() { - shouldExecuteAddPet(openapi("petstore-v3"), INVALID_PET_PATH, false, false); + shouldExecuteAddPet(openapi(petstoreSpec), INVALID_PET_PATH, false, false); } @CitrusTest @@ -272,11 +275,11 @@ public void shouldFailOnMissingNameInResponse() { .accept(APPLICATION_JSON_VALUE) .fork(true)); - then(openapi("petstore-v3") + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById")); - OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi("petstore-v3") + OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi(petstoreSpec) .server(httpServer) .send("getPetById", HttpStatus.OK); sendMessageActionBuilder.message().body(Resources.create(INVALID_PET_PATH)); @@ -296,11 +299,11 @@ public void shouldFailOnMissingPayload() { .accept(APPLICATION_JSON_VALUE) .fork(true)); - then(openapi("petstore-v3") + then(openapi(petstoreSpec) .server(httpServer) .receive("getPetById")); - OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi("petstore-v3") + OpenApiServerResponseActionBuilder sendMessageActionBuilder = openapi(petstoreSpec) .server(httpServer) .send("getPetById", HttpStatus.OK) .autoFill(AutoFillType.NONE); @@ -321,7 +324,7 @@ public void shouldFailOnWrongQueryIdTypeWithOasDisabled() { .contentType(APPLICATION_JSON_VALUE) .fork(true)); - OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") + OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) .server(httpServer) .receive("addPet"); @@ -341,7 +344,7 @@ public void shouldSucceedOnWrongQueryIdTypeWithOasDisabled() { .contentType(APPLICATION_JSON_VALUE) .fork(true)); - OpenApiServerRequestActionBuilder addPetBuilder = openapi("petstore-v3") + OpenApiServerRequestActionBuilder addPetBuilder = openapi(petstoreSpec) .server(httpServer) .receive("addPet") .schemaValidation(false); @@ -386,6 +389,63 @@ private void shouldExecuteAddPet(OpenApiActionBuilder openapi, String requestFil } } + @DataProvider + public Object[][] aliases() { + return new Object[][] { + {"petstore-v3"}, + {"Swagger Petstore"}, + {"Swagger Petstore/1.0.1"}, + }; + } + + /** + * Using OpenApiRepository, we should be able to resolve the OpenAPI spec from the name of the + * spec file or one of its aliases. + */ + @CitrusTest + @Test(dataProvider = "aliases") + public void getPetByIdUsingOpenApiRepositoryAndAlias(String alias) { + variable("petId", "1001"); + + when(http() + .client(httpClient) + .send() + .get("/pet/${petId}") + .message() + .accept(APPLICATION_JSON_VALUE) + .fork(true)); + + then(openapi(alias) + .server(httpServer) + .receive("getPetById") + .message() + ); + + HttpStatus httpStatus = HttpStatus.OK; + then(openapi(alias) + .server(httpServer) + .send("getPetById", httpStatus)); + + then(http() + .client(httpClient) + .receive() + .response(httpStatus) + .message() + .body(""" + { + "id": "@isNumber()@", + "name": "@notEmpty()@", + "category": { + "id": "@isNumber()@", + "name": "@notEmpty()@" + }, + "photoUrls": "@notEmpty()@", + "tags": "@ignore@", + "status": "@matches(sold|pending|available)@" + } + """)); + } + @Configuration public static class Config { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java index 06478846a5..598590e947 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java @@ -76,11 +76,13 @@ public class OpenApiClientTest extends AbstractXmlActionTest { private final int port = SocketUtils.findAvailableTcpPort(8080); private final String uri = "http://localhost:" + port + "/test"; - private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); - private final Queue responses = new ArrayBlockingQueue<>(6); + private HttpServer httpServer; private HttpClient httpClient; + private final MessageQueue inboundQueue = new DefaultMessageQueue("inboundQueue"); + private final Queue responses = new ArrayBlockingQueue<>(6); + @BeforeClass public void setupEndpoints() { EndpointAdapter endpointAdapter = new DirectEndpointAdapter(new DirectSyncEndpointConfiguration()) { @@ -122,9 +124,7 @@ public void shouldLoadOpenApiClientActions() throws IOException { context.getReferenceResolver().bind("httpClient", httpClient); context.getReferenceResolver().bind("httpServer", httpServer); - String apiAsString = FileUtils.readToString(Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.yaml")); - responses.add(new HttpMessage(apiAsString)); - responses.add(new HttpMessage(apiAsString)); + responses.add(new HttpMessage(FileUtils.readToString(Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.yaml")))); responses.add(new HttpMessage(""" { "id": 1000, @@ -170,8 +170,8 @@ public void shouldLoadOpenApiClientActions() throws IOException { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet/${petId}"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet/${petId}"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet/${petId}"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet/${petId}"); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); @@ -212,8 +212,8 @@ public void shouldLoadOpenApiClientActions() throws IOException { Map requestHeaders = httpMessageBuilder.buildMessageHeaders(context); Assert.assertEquals(requestHeaders.size(), 4L); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); - Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); + Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet"); + Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet"); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java index 00961c3202..8685381ef7 100644 --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/yaml/OpenApiClientTest.java @@ -164,8 +164,8 @@ public void shouldLoadOpenApiClientActions() { Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.ID)); Assert.assertNotNull(httpMessageBuilder.getMessage().getHeaders().get(MessageHeaders.TIMESTAMP)); Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.GET.name()); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet/${petId}"); - Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet/${petId}"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet/${petId}"); + Assert.assertEquals(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet/${petId}"); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(HttpMessageHeaders.HTTP_QUERY_PARAMS)); Assert.assertNull(httpMessageBuilder.getMessage().getHeaders().get(EndpointUriResolver.ENDPOINT_URI_HEADER_NAME)); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); @@ -206,8 +206,8 @@ public void shouldLoadOpenApiClientActions() { Map requestHeaders = httpMessageBuilder.buildMessageHeaders(context); Assert.assertEquals(requestHeaders.size(), 4L); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_METHOD), HttpMethod.POST.name()); - Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/pet"); - Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/pet"); + Assert.assertEquals(requestHeaders.get(EndpointUriResolver.REQUEST_PATH_HEADER_NAME), "/petstore/v3/pet"); + Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_REQUEST_URI), "/petstore/v3/pet"); Assert.assertEquals(requestHeaders.get(HttpMessageHeaders.HTTP_CONTENT_TYPE), APPLICATION_JSON_VALUE); Assert.assertNull(sendMessageAction.getEndpoint()); Assert.assertEquals(sendMessageAction.getEndpointUri(), "httpClient"); diff --git a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java index 604d67aac0..c3f0d1f383 100644 --- a/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java +++ b/core/citrus-base/src/main/java/org/citrusframework/util/StringUtils.java @@ -38,8 +38,6 @@ public static boolean hasText(String str) { /** * Helper method checks for null or blank String. - * @param str - * @return */ public static boolean hasNoText(String str) { return !hasText(str); @@ -54,8 +52,6 @@ public static boolean isEmpty(String str) { /** * String helper checking for isEmpty String and adds null check on given parameter. - * @param str - * @return */ public static boolean isNotEmpty(String str) { return !isEmpty(str); @@ -78,7 +74,7 @@ public static String appendSegmentToUrlPath(String path, String segment) { return segment; } - if (segment == null) { + if (isEmpty(segment)) { return path; } diff --git a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java index a1cf7a9dda..8f067a0bc3 100644 --- a/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java +++ b/core/citrus-base/src/test/java/org/citrusframework/util/StringUtilsTest.java @@ -62,7 +62,9 @@ public void isEmpty_returnsFalse_forBlankText(String str) { @Test public void appendSegmentToPath() { assertEquals(StringUtils.appendSegmentToUrlPath("s1", "s2"), "s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("s1", ""), "s1"); assertEquals(StringUtils.appendSegmentToUrlPath("s1/", "s2"), "s1/s2"); + assertEquals(StringUtils.appendSegmentToUrlPath("s1/", ""), "s1/"); assertEquals(StringUtils.appendSegmentToUrlPath("s1/", "/s2"), "s1/s2"); assertEquals(StringUtils.appendSegmentToUrlPath("/s1", "/s2"), "/s1/s2"); assertEquals(StringUtils.appendSegmentToUrlPath("/s1/", "/s2"), "/s1/s2"); diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc index b2b1dded6a..a70bdba30e 100644 --- a/src/manual/connector-openapi.adoc +++ b/src/manual/connector-openapi.adoc @@ -4,10 +4,17 @@ https://www.openapis.org/[OpenAPI] is a popular specification language to describe HTTP APIs and its exposure to clients. Citrus is able to leverage the specification to auto generate client and server request/response message data. The generated message data follows the rules of a given operation in the specification. -In particular, the message body is generated from the given Json schema rules in that specification. +In particular, the message body is generated according to the given Json schema rules in that specification. This way users may do contract-driven testing where the client and the server ensure the conformity with the contract to obey to the same specification rules. -NOTE: The OpenAPI support in Citrus get enabled by adding a separate Maven module as dependency to your project +Taking it a step further, Citrus OpenAPI offers a TestAPI generator powered by OpenApiGenerator. This +generator produces the necessary Builders, which define explicit actions for each operation in a given +OpenAPI. These actions enable access to any operation within the OpenAPI, making it ideal for testing +the API itself or interacting with other supporting services. The current implementation of Citrus +TestAPI uses Maven for generation and Spring for integration. For more details, please refer to +<> . + +NOTE: The OpenAPI support in Citrus gets enabled by adding a separate Maven module as dependency to your project [source,xml] ---- @@ -29,6 +36,90 @@ Or you may just point the OpenAPI components to a local specification file. Citrus supports OpenAPI on both client and server components so the next sections will describe the usage for each of those. +[[openapi-repository]] +== OpenAPI specification repositories + +An OpenApiRepository can be used to manage OpenAPI specifications. + +.Java +[source,java,indent=0,role="primary"] +---- +@Bean +public OpenApiRepository petstoreOpenApiRepository() { + return new OpenApiRepository() + .locations(singletonList( + "classpath:org/citrusframework/openapi/petstore/petstore-v3.json")) + .neglectBasePath(true) + .validationPolicy(OpenApiValidationPolicy.REPORT) + .rootContextPath("/petstore/v3/api") + .requestValidationEnabled(false) + .responseValidationEnabled(false) + ; +} +---- + +.XML +[source,xml,indent=0,role="secondary"] +---- + + + + + + + + +---- + +|=== +|Property | Description | Default + +| locations | Defines the location(s) of the OpenAPI specification files. May be one file or a directory. E.g. `classpath:org/citrusframework/openapi/petstore/*.json` | +| rootContextPath | Sets the root context path for the API, which overrides any context path defined within the specification itself. | Use the context path specified in the first server element of the OpenApi. +| validationPolicy | Controls the handling of validation errors. The available options are: + +- `FAIL`: Causes the test to fail when validation errors occur. + +- `REPORT`: Reports validation errors without failing the test. + +- `IGNORE`: Ignores any validation errors during test execution. | REPORT (from OpenApiSettings) +| requestValidationEnabled | Enables or disables validation of requests. | true (from OpenApiSettings) +| responseValidationEnabled | Enables or disables validation of responses. | true (from OpenApiSettings) + +|=== + +=== Hooking the Operation Path + +The final path used for an operation during testing is built based on the OpenAPI specification's `basePath`, +the `rootContextPath` configuration, and the `neglectBasePath` setting. The path construction follows these rules: + +1. **Default Path Construction**: +- By default, the path is constructed using the `basePath` from the OpenAPI specification (if defined) combined with the `operationPath`. +- For example, if the `basePath` is `/v1/petstore` and the operation path is `/pet`, the final path will be: +``` +/v1/petstore/pet +``` + +2. **When `rootContextPath` is Set**: +- If a `rootContextPath` is provided, it will be prepended to the `basePath` (if present) and the `operationPath`. +- If the `basePath` is `/v1/petstore`, the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, the resulting path will be: +``` +/api/v1/petstore/pet +``` + +3. **When `neglectBasePath` is Set**: +- If `neglectBasePath` is set to `true`, the `basePath` is ignored, and only the `operationPath` and `rootContextPath` is used. +- For example, if the `basePath` is `/v1/petstore` and the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, setting `neglectBasePath=true` will result in the path: +``` +/api/pet +``` + +Likewise, if the `rootContextPath` is not set, the resulting path will be the `operationPath` only: +``` +/pet +``` + + +These properties allow for flexible configuration of the OpenAPI repository, enabling you to customize how API validation is handled and how the OpenAPI specifications are loaded into the system. + + [[openapi-client]] == OpenAPI client diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java index f8d2d86963..6aa56a26c4 100644 --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/RestApiSendMessageActionBuilder.java @@ -17,6 +17,7 @@ package org.citrusframework.openapi.testapi; import static java.lang.String.format; +import static java.net.URLEncoder.encode; import static org.citrusframework.openapi.testapi.OpenApiParameterFormatter.formatArray; import static org.citrusframework.openapi.util.OpenApiUtils.createFullPathOperationIdentifier; import static org.citrusframework.util.FileUtils.getDefaultCharset; @@ -24,7 +25,6 @@ import jakarta.servlet.http.Cookie; import java.lang.reflect.Array; -import java.net.URLEncoder; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -131,7 +131,9 @@ protected void queryParameter(final String name, Object value) { return; } - setParameter((paramName, paramValue) -> super.queryParam(paramName, paramValue != null ? paramValue.toString() : null), name, value); + setParameter((paramName, paramValue) -> super.queryParam( + paramName.replace(" ", "%20"), + paramValue != null ? paramValue.toString() : null), name, value); } protected void queryParameter(final String name, Object value, ParameterStyle parameterStyle, boolean explode, boolean isObject) { @@ -209,6 +211,9 @@ public SendMessageAction doBuild() { // If no endpoint was set explicitly, use the default endpoint given by api if (getEndpoint() == null && getEndpointUri() == null) { + if (generatedApi.getEndpoint() == null) { + throw new CitrusRuntimeException("No endpoint specified for action!"); + } endpoint(generatedApi.getEndpoint()); } @@ -269,7 +274,7 @@ private static void encodeArrayStyleCookies(HttpMessage message) { if (message.getCookies() != null && !message.getCookies().isEmpty()) { for (Cookie cookie : message.getCookies()) { if (cookie.getValue().contains(",")) { - cookie.setValue(URLEncoder.encode(cookie.getValue(), getDefaultCharset())); + cookie.setValue(encode(cookie.getValue(), getDefaultCharset())); } } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache index 34b5319aec..9500cacff1 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache @@ -25,6 +25,7 @@ import static org.citrusframework.util.StringUtils.isNotEmpty; import static {{invokerPackage}}.{{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}OpenApi.{{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Specification; +import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.net.URL; @@ -84,19 +85,22 @@ public class {{classname}} implements GeneratedApi private final List customizers; - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; - public {{classname}}(Endpoint endpoint) { - this(endpoint, emptyList()); + public {{classname}}(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public {{classname}}(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public {{classname}}(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint endpoint) { - return new {{classname}}(endpoint); + public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint defaultEndpoint) { + return new {{classname}}(defaultEndpoint); } @Override @@ -129,8 +133,9 @@ public class {{classname}} implements GeneratedApi } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache index c0b7fb0ca7..d0a65618da 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api_soap.mustache @@ -20,6 +20,7 @@ package {{package}}; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import jakarta.annotation.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -37,21 +38,24 @@ import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; public class {{classname}} implements GeneratedApi { - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; private final List customizers; - public {{classname}}(Endpoint endpoint) { - this(endpoint, emptyList()); + public {{classname}}(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public {{classname}}(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public {{classname}}(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint endpoint) { - return new {{classname}}(endpoint); + public static {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(Endpoint defaultEndpoint) { + return new {{classname}}(defaultEndpoint); } @Override @@ -84,8 +88,9 @@ public class {{classname}} implements GeneratedApi } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache index 7f247f107b..47798c712d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/bean_configuration.mustache @@ -49,8 +49,8 @@ public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}BeanConfigurati {{#apiInfo}} {{#apis}} @Bean(name="{{classname}}") - public {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(@Qualifier("{{apiEndpoint}}") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new {{classname}}(endpoint, customizers); + public {{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}(@Autowired(required = false) @Qualifier("{{apiEndpoint}}") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new {{classname}}(defaultEndpoint, customizers); } {{/apis}} diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java index 7dc844405e..d51316443a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java @@ -1954,6 +1954,32 @@ void java(@CitrusResource TestCaseRunner runner) { } } + @Nested + class ParameterThatNeedUrlEncoding { + + @Test + void java_parameter_with_url_encoding(@CitrusResource TestCaseRunner runner) { + + runner.when(extPetApi.sendGetPetWithParametersRequiringEncoding(1) + .queryID(4) + .fork(true)); + + runner.then(http().server(httpServer) + .receive() + .get("/api/v3/ext/pet/parameter-with-url-encoding-required/1") + .message()); + + runner.then(http().server(httpServer) + .send() + .response(OK) + .message() + .contentType(APPLICATION_JSON_VALUE) + .body("[]")); + + runner.when(extPetApi.receiveGetPetWithSimpleStyleArray("200")); + } + } + /** * Demonstrates the usage of form data. */ diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml index 4aa50c03f2..da8ceca2fe 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml @@ -399,6 +399,38 @@ paths: description: Invalid ID supplied '404': description: Pet not found + /pet/parameter-with-url-encoding-required/{Pet ID}: + get: + tags: + - extPet + summary: Get a pet by id with parameters that potentially require encoding + operationId: getPetWithParametersRequiringEncoding + description: "Returns multiple pets by ID using multiple ids in path parameter." + parameters: + - name: Pet ID + in: path + description: IDs of pet to return + required: true + schema: + type: integer + - name: Query ID + in: query + description: A query parameter containing a space + schema: + type: integer + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: array + items: + $ref: './petstore-v3.yaml#/components/schemas/Pet' + '400': + description: Invalid ID supplied + '404': + description: Pet not found /pet/header/simple: get: tags: diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java index 11a1afb9f8..f87ae2279b 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java index fde96ad0ae..e4d8b586d7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java @@ -25,7 +25,7 @@ /** * Additional historical data for a vaccination report, not contained in internal storage. */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class HistoricalData { private LocalDate lastVaccinationDate; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java index c81d0e3837..c124787b5a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java index 79db62bb29..e214406d81 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java @@ -24,7 +24,7 @@ /** * PetIdentifier */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetIdentifier { private String _name; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java index c10c692c20..f133cd3e31 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java index 2ee2b3ca1f..4955814194 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java @@ -24,7 +24,7 @@ /** * VaccinationDocumentResult */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class VaccinationDocumentResult { private String documentId; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java index 969d47fd03..b85817a1ff 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java @@ -8,6 +8,7 @@ import static org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi.extPetStoreSpecification; +import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.net.URL; @@ -42,7 +43,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.model.VaccinationDocumentResult; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetApi implements GeneratedApi { @@ -69,19 +70,22 @@ public class ExtPetApi implements GeneratedApi private final List customizers; - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; - public ExtPetApi(Endpoint endpoint) { - this(endpoint, emptyList()); + public ExtPetApi(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public ExtPetApi(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public ExtPetApi(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static ExtPetApi extPetApi(Endpoint endpoint) { - return new ExtPetApi(endpoint); + public static ExtPetApi extPetApi(Endpoint defaultEndpoint) { + return new ExtPetApi(defaultEndpoint); } @Override @@ -105,8 +109,9 @@ public Map getApiInfoExtensions() { } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override @@ -612,6 +617,28 @@ public GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder receiveGetPetWith return new GetPetWithMatrixStyleObjectExplodedReceiveActionBuilder(this, statusCode); } + /** + * Builder with type safe required parameters. + */ + public GetPetWithParametersRequiringEncodingSendActionBuilder sendGetPetWithParametersRequiringEncoding(Integer petID) { + return new GetPetWithParametersRequiringEncodingSendActionBuilder(this, petID); + } + + /** + * Builder with required parameters as string, allowing dynamic content using citrus expressions. + */ + public GetPetWithParametersRequiringEncodingSendActionBuilder sendGetPetWithParametersRequiringEncoding$(String petIDExpression ) { + return new GetPetWithParametersRequiringEncodingSendActionBuilder(petIDExpression, this); + } + + public GetPetWithParametersRequiringEncodingReceiveActionBuilder receiveGetPetWithParametersRequiringEncoding(@NotNull HttpStatus statusCode) { + return new GetPetWithParametersRequiringEncodingReceiveActionBuilder(this, Integer.toString(statusCode.value())); + } + + public GetPetWithParametersRequiringEncodingReceiveActionBuilder receiveGetPetWithParametersRequiringEncoding(@NotNull String statusCode) { + return new GetPetWithParametersRequiringEncodingReceiveActionBuilder(this, statusCode); + } + /** * Builder with type safe required parameters. */ @@ -3689,6 +3716,137 @@ public ReceiveMessageAction doBuild() { } + public static class GetPetWithParametersRequiringEncodingSendActionBuilder extends + RestApiSendMessageActionBuilder implements GeneratedApiOperationInfo { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/parameter-with-url-encoding-required/{Pet ID}"; + + private static final String OPERATION_NAME = "getPetWithParametersRequiringEncoding"; + + /** + * Constructor with type safe required parameters. + */ + public GetPetWithParametersRequiringEncodingSendActionBuilder(ExtPetApi extPetApi, Integer petID) { + super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("Pet ID", petID, ParameterStyle.SIMPLE, false, false); + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithParametersRequiringEncodingSendActionBuilder(String petIDExpression, ExtPetApi extPetApi) { + super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("Pet ID", petIDExpression, ParameterStyle.SIMPLE, false, false); + } + + @Override + public String getOperationName() { + return OPERATION_NAME; + } + + @Override + public String getMethod() { + return METHOD; + } + + @Override + public String getPath() { + return ENDPOINT; + } + + /** + * Constructor with required parameters as string to allow for dynamic content. + */ + public GetPetWithParametersRequiringEncodingSendActionBuilder(ExtPetApi extPetApi, TestApiClientRequestMessageBuilder messageBuilder, String petIDExpression) { + super(extPetApi, extPetStoreSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + pathParameter("Pet ID", petIDExpression, ParameterStyle.SIMPLE, false, false); + } + + public GetPetWithParametersRequiringEncodingSendActionBuilder petID(Integer petID) { + pathParameter("Pet ID", petID, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithParametersRequiringEncodingSendActionBuilder petID(String petIDExpression) { + pathParameter("Pet ID", petIDExpression, ParameterStyle.SIMPLE, false, false); + return this; + } + + public GetPetWithParametersRequiringEncodingSendActionBuilder queryID(Integer queryID) { + queryParameter("Query ID", queryID, ParameterStyle.FORM, true, false); + return this; + } + + public void setQueryID(Integer queryID) { + queryParameter("Query ID", queryID, ParameterStyle.FORM, true, false); + } + + public GetPetWithParametersRequiringEncodingSendActionBuilder queryID(String queryIDExpression) { + queryParameter("Query ID", queryIDExpression, ParameterStyle.FORM, true, false); + return this; + } + + public void setQueryID(String queryIDExpression) { + queryParameter("Query ID", queryIDExpression, ParameterStyle.FORM, true, false); + } + + @Override + public SendMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this)); + } + + return super.doBuild(); + } + } + + public static class GetPetWithParametersRequiringEncodingReceiveActionBuilder extends + RestApiReceiveMessageActionBuilder implements GeneratedApiOperationInfo { + + private static final String METHOD = "GET"; + + private static final String ENDPOINT = "/api/v3/ext/pet/parameter-with-url-encoding-required/{Pet ID}"; + + private static final String OPERATION_NAME = "getPetWithParametersRequiringEncoding"; + + public GetPetWithParametersRequiringEncodingReceiveActionBuilder(ExtPetApi extPetApi, String statusCode) { + super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode); + } + + public GetPetWithParametersRequiringEncodingReceiveActionBuilder(ExtPetApi extPetApi, OpenApiClientResponseMessageBuilder messageBuilder) { + super(extPetApi, extPetStoreSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME); + } + + @Override + public String getOperationName() { + return OPERATION_NAME; + } + + @Override + public String getMethod() { + return METHOD; + } + + @Override + public String getPath() { + return ENDPOINT; + } + + @Override + public ReceiveMessageAction doBuild() { + + if (getCustomizers() != null) { + getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this)); + } + + return super.doBuild(); + } + + } + public static class GetPetWithSimpleStyleArraySendActionBuilder extends RestApiSendMessageActionBuilder implements GeneratedApiOperationInfo { diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java index fcd1063f29..793bb8fc8e 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreBeanConfiguration { @Bean @@ -26,8 +26,8 @@ public OpenApiRepository extPetStoreOpenApiRepository() { } @Bean(name="ExtPetApi") - public ExtPetApi extPetApi(@Qualifier("extpetstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new ExtPetApi(endpoint, customizers); + public ExtPetApi extPetApi(@Autowired(required = false) @Qualifier("extpetstore.endpoint") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new ExtPetApi(defaultEndpoint, customizers); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java index d90e9f9897..6c56c475d2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java @@ -12,7 +12,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.306037900+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override @@ -150,6 +150,12 @@ public void init() { new String[]{ "petId" }, new String[]{ }); + registerOperationParsers(ExtPetApi.class,"get-pet-with-parameters-requiring-encoding", "getPetWithParametersRequiringEncoding", "/pet/parameter-with-url-encoding-required/{Pet ID}", + ExtPetApi.GetPetWithParametersRequiringEncodingSendActionBuilder.class, + ExtPetApi.GetPetWithParametersRequiringEncodingReceiveActionBuilder.class, + new String[]{ "petID" }, + new String[]{ "queryID" }); + registerOperationParsers(ExtPetApi.class,"get-pet-with-simple-style-array", "getPetWithSimpleStyleArray", "/pet/simple/{petId}", ExtPetApi.GetPetWithSimpleStyleArraySendActionBuilder.class, ExtPetApi.GetPetWithSimpleStyleArrayReceiveActionBuilder.class, diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java index 1e0b69afc3..79cbc4a5b9 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java @@ -24,7 +24,7 @@ /** * Address */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Address { private String street; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java index b65788bb74..adb7ab5b4a 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java @@ -24,7 +24,7 @@ /** * Category */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Category { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java index 93d3776f57..304150abb7 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java @@ -28,7 +28,7 @@ /** * Customer */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Customer { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java index 27a740b992..178c3a56fa 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java @@ -24,7 +24,7 @@ /** * ModelApiResponse */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class ModelApiResponse { private Integer code; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java index 9dbd21669d..4d2916f2ff 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java @@ -25,7 +25,7 @@ /** * Order */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Order { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java index 96cc08f4f1..3863a75cb4 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java @@ -29,7 +29,7 @@ /** * Pet */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Pet { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java index 319de5c72f..d0779114f5 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java @@ -24,7 +24,7 @@ /** * Tag */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class Tag { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java index 63c474fdc8..fb5338f6b8 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java @@ -24,7 +24,7 @@ /** * User */ -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class User { private Long id; diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java index d26ecd2a76..dd944f0e25 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java @@ -8,6 +8,7 @@ import static org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi.petStoreSpecification; +import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.net.URL; @@ -37,7 +38,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Pet; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetApi implements GeneratedApi { @@ -49,19 +50,22 @@ public class PetApi implements GeneratedApi private final List customizers; - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; - public PetApi(Endpoint endpoint) { - this(endpoint, emptyList()); + public PetApi(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public PetApi(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public PetApi(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static PetApi petApi(Endpoint endpoint) { - return new PetApi(endpoint); + public static PetApi petApi(Endpoint defaultEndpoint) { + return new PetApi(defaultEndpoint); } @Override @@ -85,8 +89,9 @@ public Map getApiInfoExtensions() { } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java index 346e4740d7..e3997dbece 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java @@ -8,6 +8,7 @@ import static org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi.petStoreSpecification; +import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.net.URL; @@ -36,7 +37,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.Order; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class StoreApi implements GeneratedApi { @@ -48,19 +49,22 @@ public class StoreApi implements GeneratedApi private final List customizers; - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; - public StoreApi(Endpoint endpoint) { - this(endpoint, emptyList()); + public StoreApi(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public StoreApi(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public StoreApi(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static StoreApi storeApi(Endpoint endpoint) { - return new StoreApi(endpoint); + public static StoreApi storeApi(Endpoint defaultEndpoint) { + return new StoreApi(defaultEndpoint); } @Override @@ -84,8 +88,9 @@ public Map getApiInfoExtensions() { } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java index 22c95378ef..0a36c15896 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java @@ -8,6 +8,7 @@ import static org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi.petStoreSpecification; +import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; import java.math.BigDecimal; import java.net.URL; @@ -37,7 +38,7 @@ import org.citrusframework.openapi.generator.rest.petstore.model.User; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class UserApi implements GeneratedApi { @@ -49,19 +50,22 @@ public class UserApi implements GeneratedApi private final List customizers; - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; - public UserApi(Endpoint endpoint) { - this(endpoint, emptyList()); + public UserApi(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public UserApi(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public UserApi(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static UserApi userApi(Endpoint endpoint) { - return new UserApi(endpoint); + public static UserApi userApi(Endpoint defaultEndpoint) { + return new UserApi(defaultEndpoint); } @Override @@ -85,8 +89,9 @@ public Map getApiInfoExtensions() { } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java index 7a2334129c..96e9fae6cf 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java @@ -17,7 +17,7 @@ import org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreBeanConfiguration { @Bean @@ -28,18 +28,18 @@ public OpenApiRepository petStoreOpenApiRepository() { } @Bean(name="PetApi") - public PetApi petApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new PetApi(endpoint, customizers); + public PetApi petApi(@Autowired(required = false) @Qualifier("petstore.endpoint") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new PetApi(defaultEndpoint, customizers); } @Bean(name="StoreApi") - public StoreApi storeApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new StoreApi(endpoint, customizers); + public StoreApi storeApi(@Autowired(required = false) @Qualifier("petstore.endpoint") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new StoreApi(defaultEndpoint, customizers); } @Bean(name="UserApi") - public UserApi userApi(@Qualifier("petstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new UserApi(endpoint, customizers); + public UserApi userApi(@Autowired(required = false) @Qualifier("petstore.endpoint") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new UserApi(defaultEndpoint, customizers); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java index 222daac623..4155d1ad5d 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java @@ -14,7 +14,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:06.562367500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class PetStoreNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java index ccdf22a2ea..4e76813642 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java @@ -3,6 +3,7 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import jakarta.annotation.Nullable; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -16,25 +17,28 @@ import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder; @SuppressWarnings("unused") -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceSoapApi implements GeneratedApi { - private final Endpoint endpoint; + /** + * An optional default endpoint which will be passed into the requests. + */ + private final Endpoint defaultEndpoint; private final List customizers; - public BookServiceSoapApi(Endpoint endpoint) { - this(endpoint, emptyList()); + public BookServiceSoapApi(@Nullable Endpoint defaultEndpoint) { + this(defaultEndpoint, emptyList()); } - public BookServiceSoapApi(Endpoint endpoint, List customizers) { - this.endpoint = endpoint; + public BookServiceSoapApi(@Nullable Endpoint defaultEndpoint, @Nullable List customizers) { + this.defaultEndpoint = defaultEndpoint; this.customizers = customizers; } - public static BookServiceSoapApi bookServiceSoapApi(Endpoint endpoint) { - return new BookServiceSoapApi(endpoint); + public static BookServiceSoapApi bookServiceSoapApi(Endpoint defaultEndpoint) { + return new BookServiceSoapApi(defaultEndpoint); } @Override @@ -58,8 +62,9 @@ public Map getApiInfoExtensions() { } @Override + @Nullable public Endpoint getEndpoint() { - return endpoint; + return defaultEndpoint; } @Override diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java index 643177200f..96e2616ee2 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java @@ -15,7 +15,7 @@ import org.citrusframework.openapi.generator.soap.bookservice.BookServiceOpenApi; @Configuration -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceBeanConfiguration { @Bean @@ -26,8 +26,8 @@ public OpenApiRepository bookServiceOpenApiRepository() { } @Bean(name="BookServiceSoapApi") - public BookServiceSoapApi bookServiceSoapApi(@Qualifier("bookstore.endpoint") Endpoint endpoint, @Autowired(required = false) List customizers) { - return new BookServiceSoapApi(endpoint, customizers); + public BookServiceSoapApi bookServiceSoapApi(@Autowired(required = false) @Qualifier("bookstore.endpoint") Endpoint defaultEndpoint, @Autowired(required = false) List customizers) { + return new BookServiceSoapApi(defaultEndpoint, customizers); } } diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java index e561cfd699..610ef9a276 100644 --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java @@ -10,7 +10,7 @@ import org.citrusframework.openapi.testapi.GeneratedApi; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-09T10:28:07.680135700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0") public class BookServiceNamespaceHandler extends NamespaceHandlerSupport { @Override diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java index 9d313cc84d..e864da5b46 100644 --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java @@ -55,7 +55,8 @@ class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase { @Mock private MojoExecution mojoExecutionMock; - +// TODO: test real world scenario with prefix=manageBooking and prefix=ManageBooking (should result in ManageBookingNamespaceHandler instead of manageBookingNamespaceHandler. Also check namespace name it contains managebooking - is that reasonable, also the api yaml cannot be loaded because of capital letters )? + // TODO: Account Number as OpenAPI Parameter Name is allowed but leads to error as the space needs to be url encoded. static Stream replaceDynamicVarsInPattern() { return Stream.of( arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", "1", false, "MyPrefix-aa-1"), diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/util/XMLUtils.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/util/XMLUtils.java index ee01180dbd..0c2d9857ea 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/util/XMLUtils.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/util/XMLUtils.java @@ -16,6 +16,8 @@ package org.citrusframework.util; +import static org.citrusframework.util.StringUtils.isEmpty; + import java.io.ByteArrayInputStream; import java.io.StringWriter; import java.io.UnsupportedEncodingException; @@ -63,7 +65,6 @@ private XMLUtils() { /** * Initializes XML utilities with custom configurer. - * @param xmlConfigurer */ public static void initialize(XmlConfigurer xmlConfigurer) { configurer = xmlConfigurer; @@ -71,7 +72,6 @@ public static void initialize(XmlConfigurer xmlConfigurer) { /** * Creates basic parser instance. - * @return */ public static LSParser createLSParser() { return configurer.createLSParser(); @@ -79,7 +79,6 @@ public static LSParser createLSParser() { /** * Creates basic serializer instance. - * @return */ public static LSSerializer createLSSerializer() { return configurer.createLSSerializer(); @@ -87,7 +86,6 @@ public static LSSerializer createLSSerializer() { /** * Creates LSInput from dom implementation. - * @return */ public static LSInput createLSInput() { return configurer.createLSInput(); @@ -95,7 +93,6 @@ public static LSInput createLSInput() { /** * Creates LSOutput from dom implementation. - * @return */ public static LSOutput createLSOutput() { return configurer.createLSOutput(); @@ -165,13 +162,14 @@ public static Node findNodeByName(Document doc, String pathExpression) { * @param element the root node to normalize. */ public static void stripWhitespaceNodes(Node element) { - Node node, child; + Node node; + Node child; for (child = element.getFirstChild(); child != null; child = node) { node = child.getNextSibling(); stripWhitespaceNodes(child); } - if (element.getNodeType() == Node.TEXT_NODE && element.getNodeValue().trim().length()==0) { + if (element.getNodeType() == Node.TEXT_NODE && element.getNodeValue().trim().isEmpty()) { element.getParentNode().removeChild(element); } } @@ -185,43 +183,42 @@ public static void stripWhitespaceNodes(Node element) { * @return the path expression representing the node in DOM tree. */ public static String getNodesPathName(Node node) { - final StringBuffer buffer = new StringBuffer(); + final StringBuilder builder = new StringBuilder(); if (node.getNodeType() == Node.ATTRIBUTE_NODE) { - buildNodeName(((Attr) node).getOwnerElement(), buffer); - buffer.append("."); - buffer.append(node.getLocalName()); + buildNodeName(((Attr) node).getOwnerElement(), builder); + builder.append("."); + builder.append(node.getLocalName()); } else { - buildNodeName(node, buffer); + buildNodeName(node, builder); } - return buffer.toString(); + return builder.toString(); } /** * Builds the node path expression for a node in the DOM tree. * @param node in a DOM tree. - * @param buffer string buffer. + * @param builder string builder. */ - private static void buildNodeName(Node node, StringBuffer buffer) { + private static void buildNodeName(Node node, StringBuilder builder) { if (node.getParentNode() == null) { return; } - buildNodeName(node.getParentNode(), buffer); + buildNodeName(node.getParentNode(), builder); if (node.getParentNode() != null && node.getParentNode().getParentNode() != null) { - buffer.append("."); + builder.append("."); } - buffer.append(node.getLocalName()); + builder.append(node.getLocalName()); } /** * Serializes a DOM document - * @param doc - * @throws CitrusRuntimeException + * * @return serialized XML string */ public static String serialize(Document doc) { @@ -240,12 +237,15 @@ public static String serialize(Document doc) { } /** - * Pretty prints a XML string. - * @param xml - * @throws CitrusRuntimeException + * Pretty prints an XML string. * @return pretty printed XML string */ public static String prettyPrint(String xml) { + + if (isEmpty(xml)) { + return xml; + } + LSParser parser = configurer.createLSParser(); configurer.setParserConfigParameter(parser, XmlConfigurer.VALIDATE_IF_SCHEMA, false); @@ -306,8 +306,6 @@ public static Map lookupNamespaces(Node referenceNode) { /** * Parse message payload with DOM implementation. - * @param messagePayload - * @throws CitrusRuntimeException * @return DOM document. */ public static Document parseMessagePayload(String messagePayload) { @@ -327,8 +325,6 @@ public static Document parseMessagePayload(String messagePayload) { /** * Try to find encoding for document node. Also supports Citrus default encoding set * as System property. - * @param doc - * @return */ public static Charset getTargetCharset(Document doc) { String defaultEncoding = System.getProperty(CitrusSettings.CITRUS_FILE_ENCODING_PROPERTY, @@ -397,8 +393,6 @@ private static Charset getTargetCharset(String messagePayload) throws Unsupporte /** * Removes leading XML declaration from xml if present. - * @param xml - * @return */ public static String omitXmlDeclaration(String xml) { if (xml.startsWith("")) { diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/DomXmlMessageValidator.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/DomXmlMessageValidator.java index 8609a53463..2ff3c013eb 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/DomXmlMessageValidator.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/DomXmlMessageValidator.java @@ -78,7 +78,12 @@ public DomXmlMessageValidator(XmlSchemaValidation schemaValidator) { @Override public void validateMessage(Message receivedMessage, Message controlMessage, TestContext context, XmlMessageValidationContext validationContext) throws ValidationException { - logger.debug("Start XML message validation: {}", prettyPrint(receivedMessage.getPayload(String.class))); + + if (logger.isDebugEnabled()) { + logger.debug("Start XML message validation: {}", + prettyPrint(receivedMessage.getPayload(String.class))); + } + try { if (validationContext.isSchemaValidationEnabled()) { schemaValidator.validate(receivedMessage, context, validationContext); @@ -110,9 +115,6 @@ public void validateMessage(Message receivedMessage, Message controlMessage, * Validate namespaces in message. The method compares namespace declarations in the root * element of the received message to expected namespaces. Prefixes are important too, so * differing namespace prefixes will fail the validation. - * - * @param expectedNamespaces - * @param receivedMessage */ protected void validateNamespaces(Map expectedNamespaces, Message receivedMessage) { if (expectedNamespaces == null || expectedNamespaces.isEmpty()) { @@ -188,10 +190,6 @@ private void doElementNamespaceValidation(Node received, Node source) { /** * Validate message payloads by comparing to a control message. - * - * @param receivedMessage - * @param validationContext - * @param context */ protected void validateMessageContent(Message receivedMessage, Message controlMessage, XmlMessageValidationContext validationContext, TestContext context) { @@ -232,10 +230,6 @@ protected void validateMessageContent(Message receivedMessage, Message controlMe /** * Validates XML header fragment data. - * @param receivedHeaderData - * @param controlHeaderData - * @param validationContext - * @param context */ private void validateXmlHeaderFragment(String receivedHeaderData, String controlHeaderData, XmlMessageValidationContext validationContext, TestContext context) { @@ -257,10 +251,6 @@ private void validateXmlHeaderFragment(String receivedHeaderData, String control /** * Walk the XML tree and validate all nodes. - * - * @param received - * @param source - * @param validationContext */ private void validateXmlTree(Node received, Node source, XmlMessageValidationContext validationContext, NamespaceContext namespaceContext, TestContext context) { @@ -289,10 +279,6 @@ private void validateXmlTree(Node received, Node source, /** * Handle document type definition with validation of publicId and systemId. - * @param received - * @param source - * @param validationContext - * @param namespaceContext */ private void doDocumentTypeDefinition(Node received, Node source, XmlMessageValidationContext validationContext, @@ -336,10 +322,6 @@ private void doDocumentTypeDefinition(Node received, Node source, /** * Handle element node. - * - * @param received - * @param source - * @param validationContext */ private void doElement(Node received, Node source, XmlMessageValidationContext validationContext, NamespaceContext namespaceContext, TestContext context) { @@ -397,9 +379,6 @@ private void doElement(Node received, Node source, /** * Handle text node during validation. - * - * @param received - * @param source */ private void doText(Element received, Element source) { logger.debug("Validating node value for element: {}", received.getLocalName()); @@ -412,16 +391,13 @@ private void doText(Element received, Element source) { + received.getLocalName() + "'", sourceText.trim(), receivedText.trim())); } - logger.debug("Node value '{}': OK", receivedText.trim()); + if (logger.isDebugEnabled()) { + logger.debug("Node value '{}': OK", receivedText.trim()); + } } /** * Handle attribute node during validation. - * - * @param receivedElement - * @param receivedAttribute - * @param sourceElement - * @param validationContext */ private void doAttribute(Node receivedElement, Node receivedAttribute, Node sourceElement, XmlMessageValidationContext validationContext, NamespaceContext namespaceContext, TestContext context) { @@ -466,10 +442,6 @@ private void doAttribute(Node receivedElement, Node receivedAttribute, Node sour /** * Perform validation on namespace qualified attribute values if present. This includes the validation of namespace presence * and equality. - * @param receivedElement - * @param receivedAttribute - * @param sourceElement - * @param sourceAttribute */ private void doNamespaceQualifiedAttributeValidation(Node receivedElement, Node receivedAttribute, Node sourceElement, Node sourceAttribute) { String receivedValue = receivedAttribute.getNodeValue(); @@ -511,8 +483,6 @@ private void doNamespaceQualifiedAttributeValidation(Node receivedElement, Node /** * Handle processing instruction during validation. - * - * @param received */ private void doPI(Node received) { logger.debug("Ignored processing instruction ({}={})", received.getLocalName(), received.getNodeValue()); @@ -537,7 +507,6 @@ private int countAttributes(NamedNodeMap attributesR) { /** * Checks whether the given node contains a validation matcher - * @param node * @return true if node value contains validation matcher, false if not */ private boolean isValidationMatcherExpression(Node node) { @@ -565,8 +534,6 @@ public boolean supportsMessageType(String messageType, Message message) { /** * Get explicit namespace context builder set on this class or obtain instance from reference resolver. - * @param context - * @return */ private NamespaceContextBuilder getNamespaceContextBuilder(TestContext context) { if (namespaceContextBuilder != null) { @@ -578,7 +545,6 @@ private NamespaceContextBuilder getNamespaceContextBuilder(TestContext context) /** * Sets the namespace context builder. - * @param namespaceContextBuilder */ public void setNamespaceContextBuilder(NamespaceContextBuilder namespaceContextBuilder) { this.namespaceContextBuilder = namespaceContextBuilder; diff --git a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java index 26074b3308..d0182d4de2 100644 --- a/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java +++ b/validation/citrus-validation-xml/src/main/java/org/citrusframework/validation/xml/schema/XmlSchemaValidation.java @@ -55,6 +55,7 @@ import static java.lang.String.format; import static org.citrusframework.validation.xml.schema.ValidationStrategy.FAIL; +import static org.citrusframework.xml.schema.AbstractSchemaCollection.W3C_XML_SCHEMA_NS_URI; public class XmlSchemaValidation implements SchemaValidator { @@ -87,10 +88,6 @@ public XmlSchemaValidation(ValidationStrategy noSchemaFoundStrategy) { /** * Validate message with an XML schema. - * - * @param message - * @param context - * @param validationContext */ @Override public void validate(Message message, TestContext context, XmlMessageValidationContext validationContext) { @@ -162,14 +159,18 @@ private void validateSchema(Message message, TestContext context, XmlMessageVali .stream() .map(AbstractSchemaCollection::toSpringResource) .toList() - .toArray(new org.springframework.core.io.Resource[]{}), WsdlXsdSchema.W3C_XML_SCHEMA_NS_URI); + .toArray(new org.springframework.core.io.Resource[]{}), W3C_XML_SCHEMA_NS_URI); } SAXParseException[] results = validator.validate(new DOMSource(doc)); if (results.length == 0) { logger.debug("XML schema validation successful: All values OK"); } else { - logger.error("XML schema validation failed for message:\n{}", XMLUtils.prettyPrint(message.getPayload(String.class))); + + if (logger.isErrorEnabled()) { + logger.error("XML schema validation failed for message:\n{}", + XMLUtils.prettyPrint(message.getPayload(String.class))); + } // Report all parsing errors logger.debug("Found {} schema validation errors", results.length); @@ -178,7 +179,10 @@ private void validateSchema(Message message, TestContext context, XmlMessageVali errors.append(e.toString()); errors.append("\n"); } - logger.debug(errors.toString()); + + if (logger.isDebugEnabled()) { + logger.debug(errors.toString()); + } throw new ValidationException("XML schema validation failed:", results[0]); } @@ -188,9 +192,6 @@ private void validateSchema(Message message, TestContext context, XmlMessageVali } /** - * - * @param messageType - * @param message * @return true if the message or message type is supported by this validator */ @Override @@ -233,7 +234,6 @@ public boolean canValidate(Message message, boolean schemaValidationEnabled) { /** * Get setting to determine if xml schema validation is enabled by default. - * @return */ private static boolean isXmlSchemaValidationEnabled() { return Boolean.getBoolean(CitrusSettings.OUTBOUND_SCHEMA_VALIDATION_ENABLED_PROPERTY) From 5a036af9c8264e48f37a8472bf43e0467aab7490 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Wed, 29 Jan 2025 23:47:39 +0100 Subject: [PATCH 47/47] fix: finalize documentation of open api --- connectors/citrus-openapi/README.md | 6 - .../openapi/OpenApiRepository.java | 50 - .../openapi/OpenApiSpecification.java | 146 ++- .../OpenApiClientRequestActionBuilder.java | 9 +- .../OpenApiClientResponseActionBuilder.java | 5 - .../OpenApiServerResponseActionBuilder.java | 22 +- .../actions/OpenApiSpecificationSource.java | 28 +- .../openapi/random/RandomConfiguration.java | 16 +- .../citrusframework/openapi/xml/OpenApi.java | 116 +- .../openapi/OpenApiRepositoryTest.java | 33 - .../openapi/OpenApiSpecificationTest.java | 51 +- .../openapi/OpenApiTestDataGeneratorTest.java | 11 +- .../openapi/integration/OpenApiClientIT.java | 1 - .../openapi/xml/OpenApiClientTest.java | 2 +- .../openapi/xml/openapi-client-test.xml | 12 + .../schema/xml/testcase/citrus-testcase.xsd | 14 + src/manual/connector-openapi.adoc | 1027 +++++++++++++---- .../RestApiSendMessageActionParser.java | 7 + .../citrus-test-api-generator-core/README.md | 108 -- .../openapi/generator/CitrusJavaCodegen.java | 8 +- .../main/resources/java-citrus/api.mustache | 4 +- .../java-citrus/namespace_handler.mustache | 2 +- .../resources/java-citrus/schema.mustache | 9 + .../generator/CitrusJavaCodegenTest.java | 6 +- .../openapi/generator/GeneratedRestApiIT.java | 35 +- .../resources/apis/petstore-extended-v3.yaml | 29 +- .../rest/extpetstore/model/Category.java | 2 +- .../extpetstore/model/HistoricalData.java | 2 +- .../rest/extpetstore/model/Pet.java | 2 +- .../rest/extpetstore/model/PetIdentifier.java | 2 +- .../rest/extpetstore/model/Tag.java | 2 +- .../model/VaccinationDocumentResult.java | 2 +- .../rest/extpetstore/request/ExtPetApi.java | 137 ++- .../spring/ExtPetStoreBeanConfiguration.java | 2 +- .../spring/ExtPetStoreNamespaceHandler.java | 8 +- .../rest/petstore/model/Address.java | 2 +- .../rest/petstore/model/Category.java | 2 +- .../rest/petstore/model/Customer.java | 2 +- .../rest/petstore/model/ModelApiResponse.java | 2 +- .../rest/petstore/model/Order.java | 2 +- .../expectedgen/rest/petstore/model/Pet.java | 2 +- .../expectedgen/rest/petstore/model/Tag.java | 2 +- .../expectedgen/rest/petstore/model/User.java | 2 +- .../rest/petstore/request/PetApi.java | 2 +- .../rest/petstore/request/StoreApi.java | 2 +- .../rest/petstore/request/UserApi.java | 2 +- .../spring/PetStoreBeanConfiguration.java | 2 +- .../spring/PetStoreNamespaceHandler.java | 2 +- .../request/BookServiceSoapApi.java | 2 +- .../spring/BookServiceBeanConfiguration.java | 2 +- .../spring/BookServiceNamespaceHandler.java | 2 +- .../withoutOperationIdTest.xml | 43 + .../maven/plugin/TestApiGeneratorMojo.java | 2 - .../plugin/TestApiGeneratorMojoUnitTest.java | 3 +- .../pom-full-config.xml | 2 - .../pom-with-overriding-config.xml | 1 - tools/jbang/dist/CitrusJBang.java | 4 +- 57 files changed, 1466 insertions(+), 537 deletions(-) delete mode 100644 connectors/citrus-openapi/README.md delete mode 100644 test-api-generator/citrus-test-api-generator-core/README.md create mode 100644 test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withoutOperationIdTest.xml diff --git a/connectors/citrus-openapi/README.md b/connectors/citrus-openapi/README.md deleted file mode 100644 index 7669d15a9e..0000000000 --- a/connectors/citrus-openapi/README.md +++ /dev/null @@ -1,6 +0,0 @@ -// TODO -OpenApiServerRequest -- SchemaValidation is active by default (also in other scenarios) - -Oas Validation now by ValidationFramework -- no control response message is created any more \ No newline at end of file diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java index 788635ebeb..c346c479c5 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiRepository.java @@ -17,7 +17,6 @@ package org.citrusframework.openapi; import static java.lang.String.format; -import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.synchronizedList; import static org.citrusframework.openapi.OpenApiSettings.isNeglectBasePathGlobally; import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; @@ -25,13 +24,8 @@ import jakarta.annotation.Nullable; import jakarta.validation.constraints.NotNull; -import java.io.File; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.openapi.validation.OpenApiValidationPolicy; import org.citrusframework.repository.BaseRepository; @@ -83,50 +77,7 @@ public OpenApiRepository() { super(DEFAULT_NAME); } - /** - * @param openApiResource the OpenAPI resource from which to determine the alias - * @return an {@code Optional} containing the resource alias if it can be resolved, otherwise an - * empty {@code Optional} - */ - // Package protection for testing - static Optional determineResourceAlias(Resource openApiResource) { - String resourceAlias = null; - - try { - File file = openApiResource.getFile(); - if (file != null) { - resourceAlias = file.getName(); - int index = resourceAlias.lastIndexOf("."); - if (index != -1 && index != resourceAlias.length() - 1) { - resourceAlias = resourceAlias.substring(0, index); - } - return Optional.of(resourceAlias); - } - } catch (Exception e) { - // Ignore and try with url - } - try { - URL url = openApiResource.getURL(); - if (url != null) { - String urlString = URLDecoder.decode(url.getPath(), UTF_8).replace("\\", "/"); - int index = urlString.lastIndexOf("/"); - resourceAlias = urlString; - if (index != -1 && index != urlString.length() - 1) { - resourceAlias = resourceAlias.substring(index + 1); - } - index = resourceAlias.lastIndexOf("."); - if (index != -1 && index != resourceAlias.length() - 1) { - resourceAlias = resourceAlias.substring(0, index); - } - - } - } catch (MalformedURLException e) { - logger.error("Unable to determine resource alias from resource!", e); - } - - return Optional.ofNullable(resourceAlias); - } public List getOpenApiSpecifications() { return openApiSpecifications; @@ -210,7 +161,6 @@ public void addRepository(Resource openApiResource) { try { OpenApiSpecification openApiSpecification = OpenApiSpecification.from(openApiResource, validationPolicy); - determineResourceAlias(openApiResource).ifPresent(openApiSpecification::addAlias); openApiSpecification.setApiRequestValidationEnabled(requestValidationEnabled); openApiSpecification.setApiResponseValidationEnabled(responseValidationEnabled); openApiSpecification.setRootContextPath(rootContextPath); diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java index b3e4585fe4..03a7b04880 100644 --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/OpenApiSpecification.java @@ -17,9 +17,12 @@ package org.citrusframework.openapi; import static java.lang.String.format; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static java.util.Collections.synchronizedSet; +import static org.citrusframework.openapi.OpenApiSettings.getRequestAutoFillRandomValues; +import static org.citrusframework.openapi.OpenApiSettings.getResponseAutoFillRandomValues; import static org.citrusframework.openapi.OpenApiSettings.isGenerateOptionalFieldsGlobally; import static org.citrusframework.openapi.OpenApiSettings.isNeglectBasePathGlobally; import static org.citrusframework.openapi.OpenApiSettings.isRequestValidationEnabledGlobally; @@ -29,13 +32,16 @@ import static org.citrusframework.util.StringUtils.hasText; import static org.citrusframework.util.StringUtils.isEmpty; +import io.apicurio.datamodels.core.models.Extension; import io.apicurio.datamodels.core.models.common.Info; import io.apicurio.datamodels.openapi.models.OasDocument; import io.apicurio.datamodels.openapi.models.OasOperation; import io.apicurio.datamodels.openapi.models.OasPathItem; +import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.net.URLDecoder; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -86,8 +92,9 @@ public class OpenApiSpecification { private static final String HTTP = "http"; /** - * A unique identifier (UID) for this specification at runtime. The UID is generated based on the SHA - * of the OpenAPI document combined with the full context path to which the API is attached. + * A unique identifier (UID) for this specification at runtime. The UID is generated based on + * the SHA of the OpenAPI document combined with the full context path to which the API is + * attached. * * @see OpenApiSpecification#determineUid for detailed information on how the UID is generated. */ @@ -145,8 +152,22 @@ public class OpenApiSpecification { private OasDocument openApiDoc; private OpenApiValidationContext openApiValidationContext; + + /** + * Generate optional attributes when generating random schema objects. + */ private boolean generateOptionalFields = isGenerateOptionalFieldsGlobally(); + /** + * Autofill parameters and body of request with random data. + */ + private AutoFillType requestAutoFill = getRequestAutoFillRandomValues(); + + /** + * Autofill parameters and body of response with random data. + */ + private AutoFillType responseAutoFill = getResponseAutoFillRandomValues(); + /** * Flag to indicate, whether request validation is enabled on api level. Api level overrules * global level and may be overruled by request level. @@ -174,7 +195,8 @@ public OpenApiSpecification(OpenApiValidationPolicy openApiValidationPolicy) { } /** - * Creates an OpenAPI specification instance from the given URL applying the default validation policy. + * Creates an OpenAPI specification instance from the given URL applying the default validation + * policy. * * @param specUrl the URL pointing to the OpenAPI specification to load * @return an OpenApiSpecification instance populated with the document and validation context @@ -196,13 +218,20 @@ public static OpenApiSpecification from(String specUrl, OpenApiSpecification specification = new OpenApiSpecification(openApiValidationPolicy); specification.setSpecUrl(specUrl); + try { + determineUrlAlias(new URL(specUrl)).ifPresent(specification::addAlias); + } catch (MalformedURLException e) { + // Ignore; + } + return specification; } /** - * Creates an OpenAPI specification instance from the given URL applying the default validation policy. + * Creates an OpenAPI specification instance from the given URL applying the default validation + * policy. * - * @param specUrl the URL pointing to the OpenAPI specification to load + * @param specUrl the URL pointing to the OpenAPI specification to load * @return an OpenApiSpecification instance populated with the document and validation context */ public static OpenApiSpecification from(URL specUrl) { @@ -227,9 +256,12 @@ public static OpenApiSpecification from(URL specUrl, openApiDoc = OpenApiResourceLoader.fromWebResource(specUrl); } - openApiValidationContext = OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), openApiValidationPolicy); + openApiValidationContext = OpenApiValidationContextLoader.fromSpec( + OasModelHelper.toJson(openApiDoc), openApiValidationPolicy); specification.setOpenApiValidationContext(openApiValidationContext); + determineUrlAlias(specUrl).ifPresent(specification::addAlias); + specification.setSpecUrl(specUrl.toString()); specification.initPathLookups(); specification.setOpenApiDoc(openApiDoc); @@ -267,9 +299,12 @@ public static OpenApiSpecification from(Resource resource, OasDocument openApiDoc = OpenApiResourceLoader.fromFile(resource); specification.setOpenApiValidationContext( - OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), openApiValidationPolicy)); + OpenApiValidationContextLoader.fromSpec(OasModelHelper.toJson(openApiDoc), + openApiValidationPolicy)); specification.setOpenApiDoc(openApiDoc); + determineResourceAlias(resource).ifPresent(specification::addAlias); + String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) .orElse(singletonList(HTTP)) .stream() @@ -377,7 +412,6 @@ public synchronized OasDocument getOpenApiDoc(TestContext context) { Resource resource = Resources.create(resolvedSpecUrl); initApiDoc(() -> OpenApiResourceLoader.fromFile(resource)); - if (requestUrl == null) { String schemeToUse = Optional.ofNullable(OasModelHelper.getSchemes(openApiDoc)) .orElse(singletonList(HTTP)) @@ -550,6 +584,32 @@ public void setGenerateOptionalFields(boolean generateOptionalFields) { this.generateOptionalFields = generateOptionalFields; } + public AutoFillType getRequestAutoFill() { + return requestAutoFill; + } + + public void setRequestAutoFill(AutoFillType requestAutoFill) { + this.requestAutoFill = requestAutoFill; + } + + public OpenApiSpecification requestAutoFill(AutoFillType requestAutoFill) { + setRequestAutoFill(requestAutoFill); + return this; + } + + public AutoFillType getResponseAutoFill() { + return responseAutoFill; + } + + public void setResponseAutoFill(AutoFillType responseAutoFill) { + this.responseAutoFill = responseAutoFill; + } + + public OpenApiSpecification responseAutoFill(AutoFillType responseAutoFill) { + setResponseAutoFill(responseAutoFill); + return this; + } + public String getRootContextPath() { return rootContextPath; } @@ -605,6 +665,11 @@ private Collection collectAliases(OasDocument document) { } } + Extension xAlias = info.getExtension("x-citrus-alias"); + if (xAlias != null && xAlias.value != null) { + set.add(xAlias.value.toString()); + } + return set; } @@ -643,14 +708,14 @@ public void initOpenApiDoc(TestContext context) { */ public String getFullPath(OasPathItem oasPathItem) { return appendSegmentToUrlPath(rootContextPath, - getFullBasePath(oasPathItem)); + getFullBasePath(oasPathItem)); } /** * Get the full base-path for the given {@link OasPathItem}. *

        - * The full base-path is constructed by concatenating the base path (if - * applicable), and the path of the given {@code oasPathItem}. The resulting format is: + * The full base-path is constructed by concatenating the base path (if applicable), and the + * path of the given {@code oasPathItem}. The resulting format is: *

        *
              * /basePath/pathItemPath
        @@ -658,12 +723,11 @@ public String getFullPath(OasPathItem oasPathItem) {
              * If the base path is to be neglected, it is excluded from the final constructed path.
              *
              * @param oasPathItem the OpenAPI path item whose full base-path is to be constructed
        -     * @return the full base URL path, consisting of the base path, and the given path
        -     * item
        +     * @return the full base URL path, consisting of the base path, and the given path item
              */
             public String getFullBasePath(OasPathItem oasPathItem) {
                 return appendSegmentToUrlPath(
        -                getApplicableBasePath(), oasPathItem.getPath());
        +            getApplicableBasePath(), oasPathItem.getPath());
             }
         
         
        @@ -721,4 +785,58 @@ public OpenApiSpecification alias(String alias) {
                 addAlias(alias);
                 return this;
             }
        +
        +    /**
        +     * @param openApiResource the OpenAPI resource from which to determine the alias
        +     * @return an {@code Optional} containing the resource alias if it can be resolved, otherwise an
        +     * empty {@code Optional}
        +     */
        +    // Package protection for testing
        +    static Optional determineResourceAlias(Resource openApiResource) {
        +        String resourceAlias = null;
        +
        +        try {
        +            File file = openApiResource.getFile();
        +            if (file != null) {
        +                resourceAlias = file.getName();
        +                int index = resourceAlias.lastIndexOf(".");
        +                if (index != -1 && index != resourceAlias.length() - 1) {
        +                    resourceAlias = resourceAlias.substring(0, index);
        +                }
        +                return Optional.of(resourceAlias);
        +            }
        +        } catch (Exception e) {
        +            // Ignore and try with url
        +        }
        +
        +        try {
        +            URL url = openApiResource.getURL();
        +            return determineUrlAlias(url);
        +        } catch (MalformedURLException e) {
        +            logger.error("Unable to determine resource alias from resource!", e);
        +        }
        +
        +        return Optional.ofNullable(resourceAlias);
        +    }
        +
        +    static Optional determineUrlAlias(URL url) {
        +        String resourceAlias = null;
        +
        +        if (url != null) {
        +            String urlString = URLDecoder.decode(url.getPath(), UTF_8).replace("\\", "/");
        +            int index = urlString.lastIndexOf("/");
        +            resourceAlias = urlString;
        +            if (index != -1 && index != urlString.length() - 1) {
        +                resourceAlias = resourceAlias.substring(index + 1);
        +            }
        +            index = resourceAlias.lastIndexOf(".");
        +            if (index != -1 && index != resourceAlias.length() - 1) {
        +                resourceAlias = resourceAlias.substring(0, index);
        +            }
        +
        +        }
        +
        +        return Optional.ofNullable(resourceAlias);
        +    }
        +
         }
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java
        index 84f5305214..d9f2994b29 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientRequestActionBuilder.java
        @@ -36,7 +36,6 @@
         import org.citrusframework.http.message.HttpMessageBuilder;
         import org.citrusframework.message.Message;
         import org.citrusframework.openapi.AutoFillType;
        -import org.citrusframework.openapi.OpenApiSettings;
         import org.citrusframework.openapi.OpenApiSpecification;
         import org.citrusframework.openapi.model.OasModelHelper;
         import org.citrusframework.openapi.model.OperationPathAdapter;
        @@ -129,8 +128,7 @@ public static class OpenApiClientRequestMessageBuilder extends HttpMessageBuilde
         
                 private final String operationId;
         
        -        // TODO: document me
        -        private AutoFillType autoFill = OpenApiSettings.getRequestAutoFillRandomValues();
        +        private AutoFillType autoFill ;
         
                 public OpenApiClientRequestMessageBuilder(HttpMessage httpMessage,
                     OpenApiSpecificationSource openApiSpec,
        @@ -149,6 +147,11 @@ public OpenApiClientRequestMessageBuilder autoFill(AutoFillType autoFill) {
                 public Message build(TestContext context, String messageType) {
                     OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(
                         context.getReferenceResolver());
        +
        +            if (autoFill == null) {
        +                autoFill = openApiSpecification.getRequestAutoFill();
        +            }
        +
                     openApiSpecification.initOpenApiDoc(context);
                     openApiSpecification.getOperation(operationId, context)
                         .ifPresentOrElse(operationPathAdapter ->
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java
        index 1fcf16e964..b57061a912 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiClientResponseActionBuilder.java
        @@ -80,11 +80,6 @@ public OpenApiClientResponseActionBuilder(OpenApiSpecificationSource openApiSpec
                 this.operationId = operationId;
         
                 // Set json as default instead of xml. This is most common for rest.
        -        // TODO: we need to specify the type on message builder support level. So actually we need to
        -        // 1. determine the response from operationId and statusCode
        -        // 2. If status code is missing, take the most probable as response as determined by OasModelHelper.getResponseForRandomGeneration
        -        // 3. Determine message type from response and set it on builder support
        -        // If we do not set a proper type here, validations may not even be executed. E.g. simple json message validation.
                 this.getMessageBuilderSupport().type(JSON);
             }
         
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java
        index 99a304a62a..d7e509a254 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiServerResponseActionBuilder.java
        @@ -18,6 +18,8 @@
         
         import static java.lang.Integer.parseInt;
         import static java.util.Collections.singletonMap;
        +import static org.citrusframework.openapi.AutoFillType.NONE;
        +import static org.citrusframework.openapi.AutoFillType.REQUIRED;
         import static org.citrusframework.openapi.OpenApiMessageType.RESPONSE;
         import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload;
         import static org.citrusframework.openapi.OpenApiTestDataGenerator.createRandomValueExpression;
        @@ -145,7 +147,7 @@ private static class OpenApiServerResponseMessageBuilder extends HttpMessageBuil
                 private final String statusCode;
                 private final String accept;
         
        -        private AutoFillType autoFillType = OpenApiSettings.getResponseAutoFillRandomValues();
        +        private AutoFillType autoFill;
         
                 public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage,
                     OpenApiSpecificationSource openApiSpecificationSource,
        @@ -159,9 +161,8 @@ public OpenApiServerResponseMessageBuilder(HttpMessage httpMessage,
                     this.accept = accept;
                 }
         
        -        // TODO: properly document autofill feature
                 public OpenApiServerResponseMessageBuilder autoFill(AutoFillType autoFillType) {
        -            this.autoFillType = autoFillType;
        +            this.autoFill = autoFillType;
                     return this;
                 }
         
        @@ -169,6 +170,11 @@ public OpenApiServerResponseMessageBuilder autoFill(AutoFillType autoFillType) {
                 public Message build(TestContext context, String messageType) {
                     OpenApiSpecification openApiSpecification = openApiSpecificationSource.resolve(
                         context.getReferenceResolver());
        +
        +            if (autoFill == null) {
        +                 autoFill = OpenApiSettings.getResponseAutoFillRandomValues();
        +            }
        +
                     if (STATUS_CODE_PATTERN.matcher(statusCode).matches()) {
                         getMessage().status(HttpStatus.valueOf(parseInt(statusCode)));
                     } else {
        @@ -208,7 +214,7 @@ private void buildResponse(TestContext context, OpenApiSpecification openApiSpec
                     if (responseForRandomGeneration.isPresent()) {
                         OasResponse oasResponse = responseForRandomGeneration.get();
         
        -                if (autoFillType != AutoFillType.NONE) {
        +                if (autoFill != NONE) {
                             buildRandomHeaders(context, openApiSpecification, oasResponse);
                             buildRandomPayload(openApiSpecification, operation, oasResponse);
                         }
        @@ -227,7 +233,7 @@ private void buildResponse(TestContext context, OpenApiSpecification openApiSpec
         
                 private void buildRandomHeaders(TestContext context,
                     OpenApiSpecification openApiSpecification, OasResponse response) {
        -            if (autoFillType == AutoFillType.NONE) {
        +            if (autoFill == NONE) {
                         return;
                     }
         
        @@ -236,10 +242,10 @@ private void buildRandomHeaders(TestContext context,
                         entry.getKey());
         
                     Map headersToFill;
        -            if (openApiSpecification.isGenerateOptionalFields()) {
        -                headersToFill = OasModelHelper.getHeaders(response);
        -            } else {
        +            if (autoFill == REQUIRED) {
                         headersToFill = OasModelHelper.getRequiredHeaders(response);
        +            } else {
        +                headersToFill = OasModelHelper.getHeaders(response);
                     }
         
                     headersToFill.entrySet().stream()
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java
        index 931e142156..bf86e0ce54 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/actions/OpenApiSpecificationSource.java
        @@ -1,15 +1,14 @@
         package org.citrusframework.openapi.actions;
         
        +import static org.citrusframework.util.StringUtils.isEmpty;
        +
        +import java.util.Objects;
         import org.citrusframework.exceptions.CitrusRuntimeException;
         import org.citrusframework.openapi.OpenApiRepository;
         import org.citrusframework.openapi.OpenApiSpecification;
         import org.citrusframework.openapi.util.OpenApiUtils;
         import org.citrusframework.spi.ReferenceResolver;
         
        -import java.util.Objects;
        -
        -import static org.citrusframework.util.StringUtils.isEmpty;
        -
         /**
          * The {@code OpenApiSpecificationSource} class is responsible for managing and resolving an
          * {@link OpenApiSpecification} instance. It can either directly contain an
        @@ -36,18 +35,21 @@ public OpenApiSpecification resolve(ReferenceResolver resolver) {
         
                     if (!isEmpty(openApiAlias)) {
                         openApiSpecification = resolver.resolveAll(OpenApiRepository.class).values()
        -                        .stream()
        -                        .map(openApiRepository -> openApiRepository.openApi(openApiAlias)).
        -                        filter(Objects::nonNull).
        -                        findFirst()
        +                    .stream()
        +                    .map(openApiRepository -> openApiRepository.openApi(openApiAlias)).
        +                    filter(Objects::nonNull).
        +                    findFirst()
        +                    .orElseGet(() -> resolver.resolveAll(OpenApiSpecification.class).values().stream()
        +                        .filter(specification -> specification.getAliases().contains(openApiAlias))
        +                        .findFirst()
                                 .orElseThrow(() ->
        -                                new CitrusRuntimeException(
        -                                        "Unable to resolve OpenApiSpecification from alias '%s'. Known aliases for open api specs are '%s'".formatted(
        -                                                openApiAlias, OpenApiUtils.getKnownOpenApiAliases(resolver)))
        -                        );
        +                            new CitrusRuntimeException(
        +                                "Unable to resolve OpenApiSpecification from alias '%s'. Known aliases for open api specs are '%s'".formatted(
        +                                    openApiAlias, OpenApiUtils.getKnownOpenApiAliases(resolver)))
        +                        ));
                     } else {
                         throw new CitrusRuntimeException(
        -                        "Unable to resolve OpenApiSpecification. Neither OpenAPI spec, nor OpenAPI  alias are specified.");
        +                    "Unable to resolve OpenApiSpecification. Neither OpenAPI spec, nor OpenAPI  alias are specified.");
                     }
                 }
         
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java
        index 80adcb690a..c7d1a64346 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/random/RandomConfiguration.java
        @@ -37,14 +37,14 @@ private RandomConfiguration() {
         
                 // Note that the order of generators in the list is relevant, as the list is traversed from start to end, to find the first matching generator for a schema, and some generators match for less significant schemas.
                 generators.add(new RandomEnumGenerator());
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE_TIME).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, FORMAT_UUID).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomUUID()")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "email").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + EMAIL_PATTERN + "')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "uri").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + URI_PATTERN + "')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "hostname").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + HOSTNAME_PATTERN + "')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "ipv4").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV4_PATTERN + "')")));
        -        generators.add(RandomGeneratorBuilder.randomGeneratorBuilder(TYPE_STRING, "ipv6").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV6_PATTERN + "')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, FORMAT_DATE_TIME).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:currentDate('yyyy-MM-dd'T'hh:mm:ssZ')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, FORMAT_UUID).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomUUID()")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, "email").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + EMAIL_PATTERN + "')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, "uri").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + URI_PATTERN + "')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, "hostname").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + HOSTNAME_PATTERN + "')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, "ipv4").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV4_PATTERN + "')")));
        +        generators.add(randomGeneratorBuilder(TYPE_STRING, "ipv6").build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + IPV6_PATTERN + "')")));
                 generators.add(randomGeneratorBuilder().withType(TYPE_STRING).withPattern(ANY).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimpleQuoted("citrus:randomPattern('" + schema.pattern + "')")));
                 generators.add(randomGeneratorBuilder().withType(TYPE_BOOLEAN).build((randomContext, schema) -> randomContext.getRandomModelBuilder().appendSimple("citrus:randomEnumValue('true', 'false')")));
                 generators.add(new RandomStringGenerator());
        diff --git a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java
        index 01615e438b..f7060d44b4 100644
        --- a/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java
        +++ b/connectors/citrus-openapi/src/main/java/org/citrusframework/openapi/xml/OpenApi.java
        @@ -22,30 +22,30 @@
         import jakarta.xml.bind.annotation.XmlElement;
         import jakarta.xml.bind.annotation.XmlRootElement;
         import jakarta.xml.bind.annotation.XmlType;
        +import java.util.ArrayList;
        +import java.util.List;
        +import java.util.Optional;
         import org.citrusframework.TestAction;
         import org.citrusframework.TestActionBuilder;
         import org.citrusframework.actions.ReceiveMessageAction;
         import org.citrusframework.actions.SendMessageAction;
         import org.citrusframework.endpoint.resolver.EndpointUriResolver;
         import org.citrusframework.exceptions.CitrusRuntimeException;
        -import org.citrusframework.http.actions.HttpServerResponseActionBuilder;
         import org.citrusframework.http.message.HttpMessageHeaders;
        +import org.citrusframework.openapi.AutoFillType;
         import org.citrusframework.openapi.actions.OpenApiActionBuilder;
         import org.citrusframework.openapi.actions.OpenApiClientActionBuilder;
         import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder;
         import org.citrusframework.openapi.actions.OpenApiClientResponseActionBuilder;
         import org.citrusframework.openapi.actions.OpenApiServerActionBuilder;
         import org.citrusframework.openapi.actions.OpenApiServerRequestActionBuilder;
        +import org.citrusframework.openapi.actions.OpenApiServerResponseActionBuilder;
         import org.citrusframework.spi.ReferenceResolver;
         import org.citrusframework.spi.ReferenceResolverAware;
         import org.citrusframework.xml.actions.Message;
         import org.citrusframework.xml.actions.Receive;
         import org.citrusframework.xml.actions.Send;
         
        -import java.util.ArrayList;
        -import java.util.List;
        -import java.util.Optional;
        -
         @XmlRootElement(name = "openapi")
         public class OpenApi implements TestActionBuilder, ReferenceResolverAware {
         
        @@ -92,11 +92,19 @@ public OpenApi setHttpServer(String httpServer) {
             @XmlElement(name = "send-request")
             public OpenApi setSendRequest(ClientRequest request) {
                 OpenApiClientRequestActionBuilder requestBuilder =
        -                asClientBuilder().send(request.getOperation());
        +            asClientBuilder().send(request.getOperation());
         
                 requestBuilder.name("openapi:send-request");
                 requestBuilder.description(description);
         
        +        if (request.getSchemaValidation() != null) {
        +            requestBuilder.schemaValidation(request.getSchemaValidation());
        +        }
        +
        +        if (request.getAutoFill() != null) {
        +            requestBuilder.autoFill(request.getAutoFill());
        +        }
        +
                 send = new Send(requestBuilder) {
                     @Override
                     protected SendMessageAction doBuild() {
        @@ -124,11 +132,15 @@ protected SendMessageAction doBuild() {
             @XmlElement(name = "receive-response")
             public OpenApi setReceiveResponse(ClientResponse response) {
                 OpenApiClientResponseActionBuilder responseBuilder =
        -                asClientBuilder().receive(response.getOperation(), response.getStatus());
        +            asClientBuilder().receive(response.getOperation(), response.getStatus());
         
                 responseBuilder.name("openapi:receive-response");
                 responseBuilder.description(description);
         
        +        if (response.getSchemaValidation() != null) {
        +            responseBuilder.schemaValidation(response.getSchemaValidation());
        +        }
        +
                 receive = new Receive(responseBuilder) {
                     @Override
                     protected ReceiveMessageAction doBuild() {
        @@ -166,11 +178,15 @@ protected ReceiveMessageAction doBuild() {
             @XmlElement(name = "receive-request")
             public OpenApi setReceiveRequest(ServerRequest request) {
                 OpenApiServerRequestActionBuilder requestBuilder =
        -                asServerBuilder().receive(request.getOperation());
        +            asServerBuilder().receive(request.getOperation());
         
                 requestBuilder.name("openapi:receive-request");
                 requestBuilder.description(description);
         
        +        if (request.getSchemaValidation() != null) {
        +            requestBuilder.schemaValidation(request.getSchemaValidation());
        +        }
        +
                 receive = new Receive(requestBuilder) {
                     @Override
                     protected ReceiveMessageAction doBuild() {
        @@ -205,12 +221,20 @@ protected ReceiveMessageAction doBuild() {
         
             @XmlElement(name = "send-response")
             public OpenApi setSendResponse(ServerResponse response) {
        -        HttpServerResponseActionBuilder responseBuilder =
        -                asServerBuilder().send(response.getOperation(), response.getStatus());
        +        OpenApiServerResponseActionBuilder  responseBuilder =
        +            asServerBuilder().send(response.getOperation(), response.getStatus());
         
                 responseBuilder.name("openapi:send-response");
                 responseBuilder.description(description);
         
        +        if (response.getSchemaValidation() != null) {
        +            responseBuilder.schemaValidation(response.getSchemaValidation());
        +        }
        +
        +        if (response.getAutoFill() != null) {
        +            responseBuilder.autoFill(response.getAutoFill());
        +        }
        +
                 send = new Send(responseBuilder) {
                     @Override
                     protected SendMessageAction doBuild() {
        @@ -266,7 +290,7 @@ private OpenApiClientActionBuilder asClientBuilder() {
                 }
         
                 throw new CitrusRuntimeException(String.format("Failed to convert '%s' to openapi client action builder",
        -                Optional.ofNullable(builder).map(Object::getClass).map(Class::getName).orElse("null")));
        +            Optional.ofNullable(builder).map(Object::getClass).map(Class::getName).orElse("null")));
             }
         
             /**
        @@ -280,7 +304,7 @@ private OpenApiServerActionBuilder asServerBuilder() {
                 }
         
                 throw new CitrusRuntimeException(String.format("Failed to convert '%s' to openapi server action builder",
        -                Optional.ofNullable(builder).map(Object::getClass).map(Class::getName).orElse("null")));
        +            Optional.ofNullable(builder).map(Object::getClass).map(Class::getName).orElse("null")));
             }
         
             @XmlAccessorType(XmlAccessType.FIELD)
        @@ -292,6 +316,10 @@ public static class ClientRequest {
                 protected String uri;
                 @XmlAttribute(name = "fork")
                 protected Boolean fork;
        +        @XmlAttribute(name = "schemaValidation")
        +        protected Boolean schemaValidation;
        +        @XmlAttribute(name = "autofill")
        +        protected AutoFillType autoFill;
         
                 @XmlElement
                 protected Message.Extract extract;
        @@ -320,6 +348,14 @@ public void setFork(Boolean fork) {
                     this.fork = fork;
                 }
         
        +        public Boolean getSchemaValidation() {
        +            return schemaValidation;
        +        }
        +
        +        public void setSchemaValidation(Boolean schemaValidation) {
        +            this.schemaValidation = schemaValidation;
        +        }
        +
                 public Message.Extract getExtract() {
                     return extract;
                 }
        @@ -327,6 +363,15 @@ public Message.Extract getExtract() {
                 public void setExtract(Message.Extract extract) {
                     this.extract = extract;
                 }
        +
        +        public AutoFillType getAutoFill() {
        +            return autoFill;
        +        }
        +
        +        public void setAutoFill(AutoFillType autoFill) {
        +            this.autoFill = autoFill;
        +        }
        +
             }
         
             @XmlAccessorType(XmlAccessType.FIELD)
        @@ -353,6 +398,9 @@ public static class ServerRequest {
                 @XmlAttribute(name = "header-validators")
                 protected String headerValidators;
         
        +        @XmlAttribute(name = "schemaValidation")
        +        protected Boolean schemaValidation;
        +
                 @XmlElement
                 protected Receive.Selector selector;
         
        @@ -437,6 +485,15 @@ public Message.Extract getExtract() {
                 public void setExtract(Message.Extract extract) {
                     this.extract = extract;
                 }
        +
        +        public Boolean getSchemaValidation() {
        +            return schemaValidation;
        +        }
        +
        +        public void setSchemaValidation(Boolean schemaValidation) {
        +            this.schemaValidation = schemaValidation;
        +        }
        +
             }
         
             @XmlAccessorType(XmlAccessType.FIELD)
        @@ -448,6 +505,12 @@ public static class ServerResponse {
                 @XmlAttribute
                 protected String status = "200";
         
        +        @XmlAttribute(name = "schemaValidation")
        +        protected Boolean schemaValidation;
        +
        +        @XmlAttribute(name = "autofill")
        +        protected AutoFillType autoFill;
        +
                 @XmlElement
                 protected Message.Extract extract;
         
        @@ -474,6 +537,23 @@ public Message.Extract getExtract() {
                 public void setExtract(Message.Extract extract) {
                     this.extract = extract;
                 }
        +
        +        public Boolean getSchemaValidation() {
        +            return schemaValidation;
        +        }
        +
        +        public void setSchemaValidation(Boolean schemaValidation) {
        +            this.schemaValidation = schemaValidation;
        +        }
        +
        +        public AutoFillType getAutoFill() {
        +            return autoFill;
        +        }
        +
        +        public void setAutoFill(AutoFillType autoFill) {
        +            this.autoFill = autoFill;
        +        }
        +
             }
         
             @XmlAccessorType(XmlAccessType.FIELD)
        @@ -503,6 +583,9 @@ public static class ClientResponse {
                 @XmlAttribute(name = "header-validators")
                 protected String headerValidators;
         
        +        @XmlAttribute(name = "schemaValidation")
        +        protected Boolean schemaValidation;
        +
                 @XmlElement
                 protected Receive.Selector selector;
         
        @@ -599,5 +682,14 @@ public Message.Extract getExtract() {
                 public void setExtract(Message.Extract extract) {
                     this.extract = extract;
                 }
        +
        +        public Boolean getSchemaValidation() {
        +            return schemaValidation;
        +        }
        +
        +        public void setSchemaValidation(Boolean schemaValidation) {
        +            this.schemaValidation = schemaValidation;
        +        }
        +
             }
         }
        diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java
        index 817b06825d..fe846a6f59 100644
        --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java
        +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiRepositoryTest.java
        @@ -17,22 +17,14 @@
         package org.citrusframework.openapi;
         
         import static java.util.Collections.singletonList;
        -import static org.mockito.Mockito.doReturn;
        -import static org.mockito.Mockito.doThrow;
        -import static org.mockito.Mockito.mock;
         import static org.testng.Assert.assertEquals;
         import static org.testng.Assert.assertFalse;
         import static org.testng.Assert.assertNotNull;
         import static org.testng.Assert.assertThrows;
         import static org.testng.Assert.assertTrue;
         
        -import java.io.File;
        -import java.net.MalformedURLException;
        -import java.net.URL;
         import java.util.List;
        -import java.util.Optional;
         import org.citrusframework.openapi.validation.OpenApiValidationPolicy;
        -import org.citrusframework.spi.Resource;
         import org.testng.annotations.Test;
         
         public class OpenApiRepositoryTest {
        @@ -89,31 +81,6 @@ public void shouldFailOnFaultyOpenApiRepositoryByStrictValidation() {
                 assertThrows(openApiRepository::initialize);
             }
         
        -    @Test
        -    public void shouldResolveResourceAliasFromFile() {
        -        File fileMock = mock();
        -        doReturn("MyApi.json").when(fileMock).getName();
        -        Resource resourceMock = mock();
        -        doReturn(fileMock).when(resourceMock).getFile();
        -
        -        Optional alias = OpenApiRepository.determineResourceAlias(resourceMock);
        -        assertTrue(alias.isPresent());
        -        assertEquals(alias.get(), "MyApi");
        -    }
        -
        -    @Test
        -    public void shouldResolveResourceAliasFromUrl() throws MalformedURLException {
        -        URL urlMock = mock();
        -        doReturn("/C:/segment1/segment2/MyApi.json").when(urlMock).getPath();
        -        Resource resourceMock = mock();
        -        doThrow(new RuntimeException("Forced Exception")).when(resourceMock).getFile();
        -        doReturn(urlMock).when(resourceMock).getURL();
        -
        -        Optional alias = OpenApiRepository.determineResourceAlias(resourceMock);
        -        assertTrue(alias.isPresent());
        -        assertEquals(alias.get(), "MyApi");
        -    }
        -
             @Test
             public void shouldSetAndProvideProperties() {
                 // Given
        diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java
        index 9025e528dd..ae49846a53 100644
        --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java
        +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiSpecificationTest.java
        @@ -16,13 +16,17 @@
         
         package org.citrusframework.openapi;
         
        +import static org.citrusframework.openapi.OpenApiSpecification.determineResourceAlias;
         import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.IGNORE;
         import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.REPORT;
         import static org.citrusframework.openapi.validation.OpenApiValidationPolicy.STRICT;
         import static org.citrusframework.util.FileUtils.readToString;
         import static org.mockito.AdditionalAnswers.returnsFirstArg;
        +import static org.mockito.Mockito.doReturn;
        +import static org.mockito.Mockito.doThrow;
         import static org.mockito.Mockito.isA;
         import static org.mockito.Mockito.mock;
        +import static org.mockito.Mockito.spy;
         import static org.mockito.Mockito.when;
         import static org.testng.Assert.assertEquals;
         import static org.testng.Assert.assertFalse;
        @@ -33,7 +37,9 @@
         
         import io.apicurio.datamodels.openapi.models.OasDocument;
         import java.io.ByteArrayInputStream;
        +import java.io.File;
         import java.io.IOException;
        +import java.net.MalformedURLException;
         import java.net.URL;
         import java.nio.charset.StandardCharsets;
         import java.util.Optional;
        @@ -108,11 +114,9 @@ private static URL mockUrlConnection(String urlString) {
                             invocation -> new ByteArrayInputStream(PING_API_STRING.getBytes(
                                     StandardCharsets.UTF_8)));
         
        -            URL urlMock = mock();
        -            when(urlMock.getProtocol()).thenReturn(urlString.substring(0, urlString.indexOf(":")));
        -            when(urlMock.toString()).thenReturn(urlString);
        -            when(urlMock.openConnection()).thenReturn(httpsURLConnectionMock);
        -            return urlMock;
        +            URL urlSpy = spy(new URL(urlString));
        +            when(urlSpy.openConnection()).thenReturn(httpsURLConnectionMock);
        +            return urlSpy;
                 } catch (Exception e) {
                     throw new CitrusRuntimeException("Unable to mock spec url!", e);
                 }
        @@ -429,18 +433,6 @@ public void shouldSetRootContextPathNeglectingBasePathAndReinitialize() {
                 assertEquals(pongOperationPathAdapter.get().fullPath(), "/root/pong/{id}");
             }
         
        -    @Test
        -    public void shouldSeAndProvideProperties() {
        -
        -        openApiSpecification.setGenerateOptionalFields(true);
        -
        -        assertTrue(openApiSpecification.isGenerateOptionalFields());
        -
        -        openApiSpecification.setGenerateOptionalFields(false);
        -
        -        assertFalse(openApiSpecification.isGenerateOptionalFields());
        -    }
        -
             @Test
             public void shouldReturnSpecUrlInAbsenceOfRequestUrl() {
         
        @@ -455,4 +447,29 @@ public void shouldReturnSpecUrlInAbsenceOfRequestUrl() {
                 assertEquals(openApiSpecification.getSpecUrl(), "/ping-api.yaml");
                 assertEquals(openApiSpecification.getRequestUrl(), "http://or.citrus.sample");
             }
        +
        +    @Test
        +    public void testResolveResourceAliasFromFile() {
        +        File fileMock = mock();
        +        doReturn("MyApi.json").when(fileMock).getName();
        +        Resource resourceMock = mock();
        +        doReturn(fileMock).when(resourceMock).getFile();
        +
        +        Optional alias = determineResourceAlias(resourceMock);
        +        assertTrue(alias.isPresent());
        +        assertEquals(alias.get(), "MyApi");
        +    }
        +
        +    @Test
        +    public void testResolveResourceAliasFromUrl() throws MalformedURLException {
        +        URL urlMock = mock();
        +        doReturn("/C:/segment1/segment2/MyApi.json").when(urlMock).getPath();
        +        Resource resourceMock = mock();
        +        doThrow(new RuntimeException("Forced Exception")).when(resourceMock).getFile();
        +        doReturn(urlMock).when(resourceMock).getURL();
        +
        +        Optional alias = determineResourceAlias(resourceMock);
        +        assertTrue(alias.isPresent());
        +        assertEquals(alias.get(), "MyApi");
        +    }
         }
        diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java
        index 3f8ff4f9d8..23d180eddb 100644
        --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java
        +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/OpenApiTestDataGeneratorTest.java
        @@ -48,6 +48,7 @@
         import static org.citrusframework.openapi.OpenApiConstants.TYPE_INTEGER;
         import static org.citrusframework.openapi.OpenApiConstants.TYPE_NUMBER;
         import static org.citrusframework.openapi.OpenApiConstants.TYPE_STRING;
        +import static org.citrusframework.openapi.OpenApiTestDataGenerator.createOutboundPayload;
         import static org.testng.Assert.assertEquals;
         import static org.testng.Assert.assertFalse;
         import static org.testng.Assert.assertNotNull;
        @@ -226,7 +227,7 @@ public void testRandomNumber(String type,
                 testSchema.exclusiveMaximum = exclusiveMaximum;
         
                 for (int i = 0; i < 1000; i++) {
        -            String randomValue = OpenApiTestDataGenerator.createOutboundPayload(
        +            String randomValue = createOutboundPayload(
                             testSchema, openApiSpecification);
                     String finalRandomValue = testContext.resolveDynamicValue(randomValue);
                     BigDecimal value = new BigDecimal(finalRandomValue);
        @@ -291,7 +292,7 @@ public void testPingApiSchemas(String schemaType) throws IOException {
                 assertNotNull(schema);
         
                 for (int i = 0; i < 100; i++) {
        -            String randomValue = OpenApiTestDataGenerator.createOutboundPayload(schema, openApiSpecification);
        +            String randomValue = createOutboundPayload(schema, openApiSpecification);
                     assertNotNull(randomValue);
         
                     String finalJsonAsText = testContext.replaceDynamicContentInString(randomValue);
        @@ -324,7 +325,7 @@ public void testArray() {
                 arraySchema.items = stringSchema;
         
                 for (int i = 0; i < 10; i++) {
        -            String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification);
        +            String randomValue = createOutboundPayload(arraySchema, openApiSpecification);
                     int nElements = StringUtils.countMatches(randomValue, "citrus:randomString");
                     assertTrue(nElements > 0);
                 }
        @@ -344,7 +345,7 @@ public void testArrayMinItems() {
                 arraySchema.items = stringSchema;
         
                 for (int i = 0; i < 10; i++) {
        -            String randomValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification);
        +            String randomValue = createOutboundPayload(arraySchema, openApiSpecification);
                     int nElements = StringUtils.countMatches(randomValue, "citrus:randomString(15)");
                     assertTrue(nElements <= 5);
                 }
        @@ -366,7 +367,7 @@ public void testArrayMaxItems() {
         
                 Pattern pattern = Pattern.compile("citrus:randomString\\(1[0-5],MIXED,true,10\\)");
                 for (int i = 0; i < 100; i++) {
        -            String randomArrayValue = OpenApiTestDataGenerator.createOutboundPayload(arraySchema, openApiSpecification);
        +            String randomArrayValue = createOutboundPayload(arraySchema, openApiSpecification);
         
                     Matcher matcher = pattern.matcher(randomArrayValue);
                     int matches = 0;
        diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java
        index 6b563cf507..1b49c3c1bf 100644
        --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java
        +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/integration/OpenApiClientIT.java
        @@ -72,7 +72,6 @@ public void shouldExecuteGetPetById() {
                 when(openapi("petstore-v3")
                     .client(httpClient)
                     .send("getPetById")
        -            .autoFill(AutoFillType.ALL)
                     .message()
                     .fork(true));
         
        diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java
        index 598590e947..768c957d4b 100644
        --- a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java
        +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/xml/OpenApiClientTest.java
        @@ -151,7 +151,7 @@ public void shouldLoadOpenApiClientActions() throws IOException {
                 Assert.assertEquals(result.getName(), "OpenApiClientTest");
                 Assert.assertEquals(result.getMetaInfo().getAuthor(), "Christoph");
                 Assert.assertEquals(result.getMetaInfo().getStatus(), TestCaseMetaInfo.Status.FINAL);
        -        Assert.assertEquals(result.getActionCount(), 4L);
        +        Assert.assertEquals(result.getActionCount(), 6L);
                 Assert.assertEquals(result.getTestAction(0).getClass(), SendMessageAction.class);
                 Assert.assertEquals(result.getTestAction(0).getName(), "openapi:send-request");
         
        diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/xml/openapi-client-test.xml b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/xml/openapi-client-test.xml
        index 019c1a9e07..48837d6301 100644
        --- a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/xml/openapi-client-test.xml
        +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/xml/openapi-client-test.xml
        @@ -37,5 +37,17 @@
             
               
             
        +
        +    
        +      
        +        
        +          
        +        
        +      
        +    
        +
        +    
        +      
        +    
           
         
        diff --git a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd
        index 74eb05ebfc..f3d92d87a5 100644
        --- a/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd
        +++ b/runtime/citrus-xml/src/main/resources/org/citrusframework/schema/xml/testcase/citrus-testcase.xsd
        @@ -1412,6 +1412,14 @@
             
           
         
        +  
        +    
        +      
        +      
        +      
        +    
        +  
        +
           
             
               
        @@ -1430,6 +1438,7 @@
                     
                     
                     
        +            
                   
                 
                 
        @@ -1447,6 +1456,7 @@
                     
                     
                     
        +            
                   
                 
                 
        @@ -1457,6 +1467,8 @@
                     
                     
                     
        +            
        +            
                   
                 
                 
        @@ -1466,6 +1478,8 @@
                     
                     
                     
        +            
        +            
                   
                 
               
        diff --git a/src/manual/connector-openapi.adoc b/src/manual/connector-openapi.adoc
        index a70bdba30e..f79c43f801 100644
        --- a/src/manual/connector-openapi.adoc
        +++ b/src/manual/connector-openapi.adoc
        @@ -7,11 +7,11 @@ The generated message data follows the rules of a given operation in the specifi
         In particular, the message body is generated according to the given Json schema rules in that specification.
         This way users may do contract-driven testing where the client and the server ensure the conformity with the contract to obey to the same specification rules.
         
        -Taking it a step further, Citrus OpenAPI offers a TestAPI generator powered by OpenApiGenerator. This
        -generator produces the necessary Builders, which define explicit actions for each operation in a given
        -OpenAPI. These actions enable access to any operation within the OpenAPI, making it ideal for testing
        -the API itself or interacting with other supporting services. The current implementation of Citrus
        -TestAPI uses Maven for generation and Spring for integration. For more details, please refer to
        +Taking it a step further, Citrus OpenAPI offers a TestAPI generator powered by OpenApiGenerator.
        +This generator produces the necessary Builders, which define explicit actions for each operation in a given OpenAPI.
        +These actions enable access to any operation within the OpenAPI, making it ideal for testing the API itself or interacting with other supporting services.
        +The current implementation of Citrus TestAPI uses Maven for generation and Spring for integration.
        +For more details, please refer to
         <> .
         
         NOTE: The OpenAPI support in Citrus gets enabled by adding a separate Maven module as dependency to your project
        @@ -36,10 +36,40 @@ Or you may just point the OpenAPI components to a local specification file.
         
         Citrus supports OpenAPI on both client and server components so the next sections will describe the usage for each of those.
         
        +[[openapi-specification-settings]]
        +== OpenAPI specification settings
        +
        +The `OpenApiSettings` class provides configuration settings for controlling various aspects of OpenAPI request and response validation and random data generation.
        +These settings can be controlled globally through system properties or environment variables.
        +The following table outlines the available configuration options:
        +
        +|===
        +| Parameter Name                                | Environment Variable Name                      | Description
        +
        +| `citrus.openapi.validation.enabled.request`    | `CITRUS_OPENAPI_VALIDATION_DISABLE_REQUEST`     | Controls whether request validation is enabled for OpenAPI operations.
        +| `citrus.openapi.validation.enabled.response`   | `CITRUS_OPENAPI_VALIDATION_DISABLE_RESPONSE`    | Controls whether response validation is enabled for OpenAPI operations.
        +| `citrus.openapi.neglect.base.path`             | `CITRUS_OPENAPI_NEGLECT_BASE_PATH`              | Determines whether to neglect the base path when building openration paths.
        +| `citrus.openapi.request.fill.random.values`    | `CITRUS_OPENAPI_REQUEST_FILL_RANDOM_VALUES`     | Specifies whether to automatically fill missing values in request bodies with random data. One of `REQUIRED` (default) `ALL` or `NONE`)
        +| `citrus.openapi.response.fill.random.values`   | `CITRUS_OPENAPI_RESPONSE_FILL_RANDOM_VALUES`    | Specifies whether to automatically fill missing values in response bodies with random data. One of `REQUIRED` (default) `ALL` or `NONE`)
        +| `citrus.openapi.generate.optional.fields`      | `CITRUS_OPENAPI_GENERATE_OPTIONAL_FIELDS`        | Enables or disables the generation of optional fields in the OpenAPI Json requests and responses.
        +| `citrus.openapi.validation.policy`             | `CITRUS_OPENAPI_VALIDATION_POLICY`              | Defines the validation policy for OpenAPI operations (e.g., `FAIL`, `REPORT`, `IGNORE`).
        +|===
        +
        +
         [[openapi-repository]]
         == OpenAPI specification repositories
         
        -An OpenApiRepository can be used to manage OpenAPI specifications.
        +An OpenApiRepository provides a centralized way to manage OpenAPI specifications within a test environment.
        +When bound to a bean container, it automatically makes registered specifications available for message
        +validation in conjunction with messages send by actions created by OpenApiActionBuilders. These built actions
        +ensure that all necessary validation information is present, enabling seamless verification without additional user input.
        +
        +While an OpenApiRepository is particularly useful for loading multiple OpenAPI definitions from a specified
        +location, in many cases, directly registering an individual OpenApiSpecification within the bean container
        +is sufficient.
        +Any registered specification—whether added individually or via a repository—will be considered during message validation.
        +
        +This approach simplifies OpenAPI-based validation in Citrus, ensuring that test messages conform to their expected structure without requiring manual intervention.
         
         .Java
         [source,java,indent=0,role="primary"]
        @@ -74,7 +104,7 @@ public OpenApiRepository petstoreOpenApiRepository() {
         |===
         |Property | Description | Default
         
        -| locations | Defines the location(s) of the OpenAPI specification files. May be one file or a directory. E.g. `classpath:org/citrusframework/openapi/petstore/*.json` |
        +| locations | Defines the location(s) of the OpenAPI specification files. May be one file or a directory. E.g. `classpath:org/citrusframework/openapi/petstore/*.json`. Note that when loading more than one OpenAPI via a repository, care must be taken with respect to the context paths of the OpenAPIs. See the context path configuration properties of the repository and the following <<_hooking_the_operation_path>> chapter.  |
         | rootContextPath | Sets the root context path for the API, which overrides any context path defined within the specification itself. | Use the context path specified in the first server element of the OpenApi.
         | validationPolicy | Controls the handling of validation errors. The available options are: +
         - `FAIL`: Causes the test to fail when validation errors occur. +
        @@ -87,49 +117,72 @@ public OpenApiRepository petstoreOpenApiRepository() {
         
         === Hooking the Operation Path
         
        -The final path used for an operation during testing is built based on the OpenAPI specification's `basePath`,
        -the `rootContextPath` configuration, and the `neglectBasePath` setting. The path construction follows these rules:
        +In OpenAPI, an operation represents a single API endpoint, typically corresponding to an HTTP method (e.g., GET, POST) and a specific path.
        +The path defines how the client interacts with the API and often includes dynamic parameters.
        +These paths are defined relative to the API's base URL and are an essential part of structuring API interactions.
        +
        +The OpenAPI specification allows defining a server URL, which acts as the root of the API. This URL
        +may include a basePath, which serves as a prefix for all operation paths.
        +If more than one server is specified, the first one will be used.
        +Additionally, applications may define a context path, which can be used to namespace APIs when deployed in different environments.
        +In the following, this context path is denoted rootContextPath.
        +It is a user-specified value that can be assigned to an OpenApiRepository or to an OpenApiSpecification itself.
        +
        +The final path used for an operation during testing is built based on the OpenAPI specification's `basePath`, the `rootContextPath`.
        +For most flexibility, Citrus provides several options to configure the final operation path:
         
         1. **Default Path Construction**:
         - By default, the path is constructed using the `basePath` from the OpenAPI specification (if defined) combined with the `operationPath`.
        -- For example, if the `basePath` is `/v1/petstore` and the operation path is `/pet`, the final path will be:
        -```
        -/v1/petstore/pet
        -```
        +- For example, if the `basePath` is `/v1/petstore` and the operation path is `/pet`, the final path will be: `*/v1/petstore/pet*`
         
         2. **When `rootContextPath` is Set**:
         - If a `rootContextPath` is provided, it will be prepended to the `basePath` (if present) and the `operationPath`.
        -- If the `basePath` is `/v1/petstore`, the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, the resulting path will be:
        -```
        -/api/v1/petstore/pet
        -```
        +- or example, if the `basePath` is `/v1/petstore`, the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, the resulting path will be: `*/api/v1/petstore/pet*`
         
         3. **When `neglectBasePath` is Set**:
         - If `neglectBasePath` is set to `true`, the `basePath` is ignored, and only the `operationPath` and `rootContextPath` is used.
        -- For example, if the `basePath` is `/v1/petstore` and the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, setting `neglectBasePath=true` will result in the path:
        -```
        -/api/pet
        -```
        +- For example, if the `basePath` is `/v1/petstore` and the `operationPath` is `/pet`, and the `rootContextPath` is `/api`, setting `neglectBasePath=true` will result in the path: `*/api/pet*` +
        +Likewise, if the `rootContextPath` is not set, the resulting path will be the `operationPath` only: `*/pet*`
        +
        +These properties allow for flexible configuration of the OpenAPI repository, enabling you to customize how API validation is handled and how the OpenAPI specifications are loaded into the system.
         
        -Likewise, if the `rootContextPath` is not set, the resulting path will be the `operationPath` only:
        -```
        -/pet
        -```
        +[[openapi-specification]]
        +== OpenAPI aliases
         
        +You can refer to registered OpenAPI specification by an alias.
        +That way, you can register a specification in your preferred bean container and refer to it, rather than instantiating a specification over and over in all your tests.
        +The specification can then be resolved at runtime when needed.
         
        -These properties allow for flexible configuration of the OpenAPI repository, enabling you to customize how API validation is handled and how the OpenAPI specifications are loaded into the system.
        +The following aliases are derived from the specification.
        +
        +1. If the specification has an info element with a title, the title will be assigned as alias: `Swagger Petstore`
        +2. If the specification has an info element with a version and a title, the title plus version will be assigned as alias: `Swagger Petstore/1.0.1`
        +3. If the specification is loaded from a `Resource` via an OpenAPIRepository, the resource name without file extension will be added as alias: `petstore-v3`
        +4. If the specification has an extension named `x-citrus-alias`, the value of this extension will be assigned as alias.
        +5. For technical reasons, a unique-id will also be added as alias.
        +This unique-id alias is determined from the document SHA value and the full context path, to which the specification is mounted, making it unique, even if the same API is used at different mount-points.
        +Note that this unique-id alias is used internally during validation, to identify the OpenAPI specification that relates to a specific message.
        +
        +Citrus will try to resolve the specification from a given alias by querying all registered OpenApiRepositories as well as all registered OpenApiSpecifications.
         
        +[[openapi-specification]]
        +== XML Support
        +
        +This is a brief note on the XML support of OpenAPI. Due to the comprehensive <>  approach
        +with Spring support, which covers all aspects of OpenAPI, the plain XML support has not yet been fully
        +implemented. We recommend using the generated TestAPI with Spring, instead of plain XML for better functionality and coverage.
         
         [[openapi-client]]
         == OpenAPI client
         
        -On the client side Citrus uses the OpenAPI specification to generate a proper HTTP request that is sent to the server.
        -The user just gives a valid operationId from the specification every thing else is automatically generated.
        -The Citrus client message will use the proper request path (e.g. `/petstore/v3/pet`) and Content-Type (e.g. `applicaiton/json`) according to the specification rules.
        +On the client side, Citrus uses the OpenAPI specification to generate the appropriate HTTP request sent to the server.
        +While you can manually configure every aspect of the message sent by the client, it’s also possible to auto-generate the message from the specification.
        +In either case, the client will automatically use the correct request path (e.g., `/petstore/v3/pet`) and Content-Type (e.g., `application/json`) based on the specification.
         
        -Of course, you can also validate the HTTP response message with auto generated validation.
        -The user just gives the expected HTTP status code that is also described in the specification (e.g. 200 OK).
        -The response data used as expected message content is then also generated from the specification.
        +A response is automatically validated against the corresponding response defined in the OpenAPI specification
        +for the given status code.
        +You just specify the expected HTTP status code, which must match one defined in the specification (e.g., 200 OK), and validation will be performed automatically.
        +For more details see <>.
         
         As an example the following OpenAPI specification defines the operation `getPetById`.
         
        @@ -207,10 +260,12 @@ Pet:
         # ...
         ----
         
        -In a testcase Citrus is able to leverage this information in order to send a proper request and validate the response based on the OpenAPI specification.
        +In a testcase Citrus is able to leverage this information in order to send a proper request and validate
        +the response based on the OpenAPI specification.
         
         .Java
         [source,java,indent=0,role="primary"]
        +
         ----
         private final HttpClient httpClient = new HttpClientBuilder()
                     .requestUrl("http://localhost:%d".formatted(port))
        @@ -282,37 +337,202 @@ actions:
         ----
         
        -    
        +    
         
         ----
         
        -In this very first example The client uses the OpenAPI specification to generate a proper GET HTTP request for the `getPetById` operation.
        -The request is sent to the server using the request URL path `/petstore/v3/pet/${petId}` as declared in the OpenAPI specification.
        +In this very first example The client uses the OpenAPI specification to generate a proper GET HTTP request
        +for the `getPetById` operation. The request is sent to the server using the request URL path `/petstore/v3/pet/${petId}`
        +as declared in the OpenAPI specification.
         
        -The resulting HTTP response from the server is verified on the client by giving the operationId and the expected status `200`.
        -The OpenAPI client generates the expected control message from the given Json schema in the OpenAPI specification.
        +It is also possible to reference a given specification by one of its aliases. In the following example,
        +this is demonstrated through the usage of either an OpenApiRepository or an OpenApiSpecification. Note
        +that it is sufficient to register the specification using either method. The `openapi` call then accepts
        +a string argument representing one of the specification's aliases..
         
        -The generated control message contains validation matchers and expressions as follows.
        +.Java
        +[source,java,indent=0,role="primary"]
         
        -.Generated control message body
        -[source,json]
         ----
        -{
        -  "id": "@isNumber()@",
        -  "name": "@notEmpty()@",
        -  "category": {
        -    "id": "@isNumber()@",
        -    "name": "@notEmpty()@"
        -  },
        -  "photoUrls": "@notEmpty()@",
        -  "tags":  "@ignore@",
        -  "status": "@matches(sold|pending|available)@"
        +private final HttpClient httpClient = new HttpClientBuilder()
        +            .requestUrl("http://localhost:%d".formatted(port))
        +            .build();
        +
        +@BindToRegistry
        +private OpenApiRepository openApiRepository = new OpenApiRepository()
        +            .locations(singletonList(
        +                "classpath:org/citrusframework/openapi/petstore/petstore-v3.json"))
        +            .neglectBasePath(true)
        +            .validationPolicy(OpenApiValidationPolicy.REPORT);
        +
        +@BindToRegistry
        +private OpenApiSpecification openApiSpecification = OpenApiSpecification
        +            .from(Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-v3.json"), OpenApiValidationPolicy.REPORT)
        +            .neglectBasePath(true);
        +
        +@CitrusTest
        +public void openApiClientTest() {
        +    variable("petId", "1001");
        +    when(openapi("petstore-v3")
        +        .client(httpClient)
        +        .send("getPetById"));
        +
        +    then(openapi("petstore-v3")
        +        .client(httpClient)
        +        .receive("getPetById", HttpStatus.OK));
         }
         ----
         
        -This control message meets the rules defined by the OpenAPI Json schema specification for the pet object.
        -For instance the enum field `status` is validated with a matching expression.
        -In case the OpenAPI specification changes the generated control message will change accordingly.
        +[[openapi-client]]
        +=== Message Content
        +
        +All variables that match the parameters of the operation will be automatically assigned to the constructed method.
        +For example, in the samples above, the `petId` will be assigned to the corresponding path parameter.
        +The same applies to `header`, `query`, and `cookie` parameters. Additionally, it is also possible to
        +specify parameters and body at the message level.
        +
        +For example, setting the `verbose` query parameter at the message level in the sample below has the
        +same effect as specifying a `verbose` variable.
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +@CitrusTest
        +public void openApiClientTest() {
        +    variable("petId", "1001");
        +    when(openapi("petstore-v3")
        +        .client(httpClient)
        +        .send("getPetById")
        +        .message()
        +        .header("verbose", "true"));
        +
        +    then(openapi("petstore-v3")
        +        .client(httpClient)
        +        .receive("getPetById", HttpStatus.OK));
        +}
        +----
        +
        +[[openapi-autofill]]
        +=== Autofill
        +
        +As all parameters and the body are defined in the OpenAPI specification, it is possible to autofill
        +missing values. Autofill works by generating random, schema-conforming values for parameters and the body.
        +The ability to create random values based on OpenAPI schema definitions has been significantly enhanced
        +compared to the previous implementations. It now respects constraints such as `min/max` definitions for
        +numbers, composite patterns like `oneOf`, `anyOf`, and `allOf`, `arrays`, and specific patterns like
        +`email`, `URI`, `hostname`, `IPv4`, and `IPv6`. Regular expression patterns for strings are properly
        +generated using the `com.github.mifmif:generex` library.
        +
        +Note that random message generation has limitations. For example, in the case of complex schemas containing
        +nested objects, the random generator currently stops if it encounters the same object type during generation,
        +in order to avoid infinite recursion.
        +
        +There are three autofill modes:
        +
        +|===
        +|Mode | Description
        +|  `REQUIRED` | Autofills only the required parts of the message, such as required body attributes, and required header, query, cookie, and path parameters. This is the default mode.
        +|  `ALL` | Autofills all parts of the message, including both required and optional parameters and body attributes.
        +|  `NONE` | No autofill is applied. All missing parameters and body must be explicitly provided.
        +|===
        +
        +The autofill mode is supported at client and server and can be specified at send the send message:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +@CitrusTest
        +public void openApiClientTest() {
        +    // This request is invalid because no body will be generated
        +    when(openapi("petstore-v3")
        +        .client(httpClient)
        +        .send("addPet")
        +        .autoFill(AutoFillType.NONE));
        +}
        +----
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +    
        +        
        +    
        +    
        +        
        +          
        +          
        +        
        +    
        +
        +----
        +
        +[[openapi-validation]]
        +=== Validation
        +
        +The foundation of the OpenAPI validation concept is the OpenAPI validator provided by `com.atlassian.oai:swagger-request-validator-core`.
        +This concept applies to both client-side and server-side implementations, covering both requests and responses.
        +It includes parameter validation as well as message validation, with the latter being limited to messages
        +based on schema definitions in the OpenAPI specification
        +
        +Since most use cases require sent and received messages to conform to the specification, schema validation
        +is `enabled by default`. This ensures that parameter values and the body are valid not only in terms
        +of type but also with respect to other constraints, such as minimum and maximum values, patterns,
        +composites (`oneOf`, `anyOf`, `allOf`), and other restrictions.
        +
        +Unlike the previous validation implementation in Citrus, no explicit control message is involved in the validation.
        +Technically, the OpenAPI validation is implemented as a Citrus SchemaValidation, similar to JSON and XML
        +validation. However, you can still use the standard message validation features of Citrus to
        +validate the explicit content of the body or header parameters.
        +
        +If you intentionally want to send or receive invalid data to test the response behavior or error handling
        +of your service, you can disable the validation as follows:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +@CitrusTest
        +public void openApiClientTest() {
        +    variable("petId", "invalid-string-as-pet-id");
        +
        +    // Although the petId is not an integer, this call will not fail due to disabled schema validation
        +    when(openapi("petstore-v3")
        +        .client(httpClient)
        +        .send("getPetById")
        +        .schemaValidation(false));
        +
        +    then(openapi("petstore-v3")
        +        .client(httpClient)
        +        .receive("getPetById", HttpStatus.OK))
        +        .schemaValidation(false);
        +}
        +----
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +    
        +        
        +        
        +        
        +    
        +    
        +        
        +          
        +          
        +        
        +    
        +
        +----
        +
        +Of course, the resulting HTTP response from the server is also verified against the OpenAPI specification.
        +Programmatically, verification is configured by providing the `operationId` and the expected `status`.
        +From this, the expected response is determined and validated against the actual response.
        +
        +Response schema validation can also be disabled, as shown in the previous example.
         
         This completes the client side OpenAPI support.
         Now let's have a closer look at the server side OpenAPI support in the next section.
        @@ -320,8 +540,10 @@ Now let's have a closer look at the server side OpenAPI support in the next sect
         [[openapi-server]]
         == OpenAPI server
         
        -On the server side Citrus is able to verify incoming requests based on the OpenAPI specification.
        -The expected request message content as well as the expected resource URL path and the Content-Type are automatically validated.
        +As already mentioned in chapter <>, Citrus is able to verify incoming requests and
        +outgoing responses, based on the OpenAPI specification. The expected request message content as well
        +as the expected resource URL path, query, header, cookie parameters and the Content-Type are automatically
        +validated.
         
         .Java
         [source,java,indent=0,role="primary"]
        @@ -405,91 +627,185 @@ actions:
         
         The example above uses the `addPet` operation defined in the OpenAPI specification.
         The operation expects a HTTP POST request with a pet object as message payload.
        -The OpenAPI server generates an expected Json message body according to the specification.
        +The OpenAPI server validates the incoming message using `com.atlassian.oai:swagger-request-validator-core`.
         This ensures that the incoming client request meets the Json schema rules for the pet object.
        -Also, the server will verify the HTTP request method, the Content-Type header as well as the used resource path `/petstore/v3/pet`.
        +Also, the server will verify the HTTP request method, the Content-Type header as well as the used
        +resource path `/petstore/v3/pet`. For more information check chapter <>.
         
         The given HTTP status code defines the response that should be sent by the server.
        -The server will generate a proper response according to the OpenAPI specification.
        -This also includes a potential response message body (e.g. pet object).
        +The server will generate a proper response according to the OpenAPI specification and the autofill mode
        +described in chapter <>. This also includes a potential response message body (e.g. pet object).
        +
        +Note that the OpenAPI specification does not require all possible responses to be defined. Therefore,
        +a response for a given operation and status code may not always be specified by the OpenAPI specification.
        +In such cases, Citrus will fail to generate a valid random response, and you will need to specify the response manually.
        +
        +In case validation is unwanted, it can always be turned off for server side send and receive. Again, see
        +<> for details.
         
         [[openapi-test-api-generator]]
        -=== OpenAPI Test API Generator
        +== OpenAPI Test API Generator
        +
        +For a deeper integration with a given OpenAPI, Citrus offers the ability to generate a dedicated
        +TestAPI, providing test actions tailored to the specific operations of the OpenAPI under evaluation.
        +These actions can be used with both XML and Java DSL.
         
        -For an even deeper integration with a given OpenAPI, Citrus offers the possibility to generate a dedicated Test API which provides test actions tailored to the specific operations of the OpenAPI under evaluation.
        -These actions can be used in XML or Java DSL.
        -The functionality is provided by the `Citrus OpenAPI Test API Generator` which  leverages the link:https://github.com/swagger-api/swagger-codegen/tree/master[OpenAPI Code Generator] to generate code, but provides custom templates tailored for seamless integration within the Citrus framework.
        +Please note the following restrictions:
        +- Only OpenApiClient send/receive is implemented
        +- XML integration is only available for Spring Framework
         
        -The generator provides the following features:
        +The TestAPI functionality is provided by the https://github.com/citrusframework/citrus/tree/main/test-api-generator[Citrus OpenAPI TestAPI Generator]
        +module, which utilizes the link:https://github.com/swagger-api/swagger-codegen/tree/master[OpenAPI Code Generator]
        +to generate the necessary code. Citrus provides the following modules to build and run the TestAPI code:
         
        -* generation of a Test API
        -** from OpenAPI Specification
        -** [TODO #1163] from WSDL via an intermediate step that generates a "light" OpenApi specification from a WSDL
        -* integration into <>
        -** integration into XML editors via generated XSD
        -*** schema validation
        -*** auto completion
        -* integration into <> via Java DSL [TODO #1161]
        +|===
        +| Artifact            | Purpose
         
        -The following directory structure/table specifies the files, which are generated by the generator.
        -Note that the `Prefix` is a configuration parameter which should uniquely identify a generated API.
        -It is specified in the build configuration for the Test API.
        +| `citrus-test-api-core`  | Runtime dependencies of Citrus TestAPI feature.
        +| `citrus-test-api-generator-core`  | Citrus specific generator `org.citrusframework.openapi.generator.CitrusJavaCodegen` and required
        +https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus[mustache templates].
        +| `citrus-test-api-generator-maven-plugin`  | The maven plugin used to build the TestAPI.
         
        -.Generated Folder Structure
        +|===
        +
        +
        +The generator offers the following features:
        +
        +* Generation of a TestAPI
        +** From OpenAPI Specification
        +** From WSDL
        +* Integration into Citrus XML test cases:
        +** Integration into XML editors via dedicated generated XSD for:
        +*** Schema validation
        +*** Auto-completion
        +* Integration into Citrus Java test cases via Java DSL
        +
        +Keep in mind that a generated TestAPI not only serves as a powerful tool for calling and validating
        +the operations of your system under test, but also streamlines access to other supporting libraries
        +that offer an OpenAPI specification, enhancing the overall integration and testing experience.
        +
        +[[openapi-test-api-when-to-use]]
        +=== When to use a TestAPI
        +
        +Using a TestAPI simplifies testing OpenAPI-based services but introduces additional configuration overhead.
        +It is essential to have a solid understanding of Maven and managing generated code.
        +
        +If you're writing multiple tests for a service, investing time in the following chapters will be worthwhile.
        +However, if you only need a basic smoke test, using plain Citrus features may be the better choice.
        +
        +[[openapi-test-api-wsdl]]
        +=== TestAPI from WSDL
        +
        +Citrus also supports the generation of a TestAPI from a WSDL. The WSDL is parsed, and a simple OpenAPI
        +specification is generated, which includes an OpenAPI operation for each WSDL binding. Using specific
        +code generation templates, the generator provides WS-specific action builders that can be used in both
        +Java DSL and XML. All this happens behind the scenes, if you specifiy a WSDL as source and use the
        +`citrus-test-api-generator-maven-plugin` for code generation.
        +
        +Note that there is currently no support for generating random messages. Also, the WSDL is not yet
        +properly registered with an `XsdSchemaRepository`, nor are the actions configured for schema validation.
        +Therefore, out of the box validation is currently not supported.
        +
        +[[openapi-test-api-files]]
        +=== Generated Files
        +
        +The following directory structure depicts the files that are produced during code generation. Note
        +that the `Prefix` in folder and file-names is a placeholder for a specific value configured by a
        +parameter in the build configuration. This value should uniquely identify an API to avoid name clashes.
        +
        +.Generated Folder Structure and Files
         [source]
         ----
         target/
        -├───generated-test-resources/
        -│   ├───META-INF/
        -│   │   ├───spring.handlers
        -│   │   └───spring.schemas
        -│   └───schema/
        -│       └───xsd/
        -│           └───prefix-api.xsd
        -└───generated-test-sources/
        -    └───org/
        -        └───citrusframework/
        -            └───automation/
        -                └───prefix/
        -                    ├───api/
        -                    │   └───MyApi.java
        -                    ├───citrus/
        -                    │   ├───extension/
        -                    │   │   └───PrefixNamespaceHandler.java
        -                    │   ├───PrefixAbstractTestRequest.java
        -                    │   └───PrefixBeanDefinitionParser.java
        -                    ├───model/
        -                    │   ├───MyReqTypeA.java
        -                    │   └───MyReqTypeB.java
        -                    └───spring/
        -                        └───PrefixBeanConfiguration.java
        +â””generated-test-sources/
        + â”” openapi/
        +    ├ .openapi-generator/                             // OpenApiGenerator Metafiles
        +    ├ docs/                                           // Standard OpenApiGenerator
        +    │                                                 // documentation
        +    â”” src/
        +       ├ main/
        +       │   ├ java/
        +       │   │   └ org/                                 // default
        +       │   │      └ citrusframework/                  //   TestAPI
        +       │   │         └ automation/                    //     package structure
        +       │   │            │
        +       │   │            └ prefix/                     // Api prefix as specified in Maven
        +       │   │               │                          // build
        +       │   │               │
        +       │   │               └ version/                 // Optional version as specified in
        +       │   │                  │                       // Maven build
        +       │   │                  ├ api/
        +       │   │                  │  └ PrefixApi.java     // The dedicated api action builder
        +       │   │                  │
        +       │   │                  ├ model/                // Model classes generated for
        +       │   │                  │  ├ TypeA.java         // schema components
        +       │   │                  │  └ TypeB.java
        +       │   │                  ├ spring/
        +       │   │                  │  ├ PrefixBeanConfiguration.java  // Spring BeanConfiguration
        +       │   │                  │  │                            // providing OpenApiSpecification
        +       │   │                  │  │                            // and PrefixApi bean
        +       │   │                  │  │
        +       │   │                  │  └ PrefixNamespaceHandler.java   // Spring NamespaceHandler for
        +       │   │                  │                                  // XML integration
        +       │   │                  │
        +       │   │                  └ PrefixApi.java        // OpenApiSpecification provider
        +       │   └ resources/
        +       │       ├ META-INF/                            // Spring Integration files
        +       │       │  ├ spring.handlers
        +       │       │  └ spring.schemas
        +       │       ├ org/
        +       │       │  └ citrusframework/
        +       │       │     └ automation/
        +       │       │        ├ apiprefix/
        +       │       │           └ version/
        +       │       │              └ prefix_openApi.yml    // Copy of the OpenAPI specification
        +       │       │                                      // for validation purposes
        +       │       └ schema/
        +       │          └ xsd
        +       │             └ prefix-api.xsd                 // Generated XSD schema for XML
        +       │                                              // integration
        +       │
        +       â”” test                                         // Unused
         ----
         
         |===
         | File                                | Content
         
        +| `PrefixApi.java`                    | The class containing the dedicated TestAPI action builder and actions.
        +| `TypeA.java, TypeB.java`            | Model files generated with respect to the schema components of the OpenAPI.
        +| `PrefixBeanConfiguration.java`      | A Spring @Configuration class, that provides an OpenApiRepository with the Specification and an instance of PrefixApi.
        +| `PrefixNamespaceHandler.java`       | A Spring class, that registers bean definition parsers for TestAPI XML elements.
        +| `PrefixApi.java`                    | Provides static access to an instance of the TestAPI OpenAPI specification.
         | `spring.handlers`                   | Spring namespace handler configuration, that contains all NamespaceHandlers for all generated APIs.
         | `spring.schemas`                    | Spring schema definitions, with mappings of namespaces to schemas for all generated APIs.
        -| `prefix-api.xsd`                    | XSD schema for the integration of the Test API into XML.
        -| `PrefixNamespaceHandler.java`       | A Spring class, that registers bean definition parsers for Test API XML elements.
        -| `PrefixAbstractTestRequest.java`    | Abstract superclass of all Test API actions.
        -| `PrefixBeanDefinitionParser.java`   | Spring bean definition parser, responsible for parsing Test API XML elements into test actions.
        -| `MyReqTypeA.java, MyReqTypeB.java`  | Model files generated with respect to the schema definition of the OpenAPI.
        -| `PrefixBeanConfiguration.java`      | A Spring @Configuration class, that registers all Test API actions as Spring beans.
        +| `prefix-openApi.yml`                | The OpenAPI source that was used to build the TestAPI.
        +| `prefix-api.xsd`                    | XSD schema for the integration of the TestAPI into XML.
         |===
         
        -==== Configuration of Test API Generation
        +[[openapi-test-api-generator]]
        +=== Configuration of TestAPI Generation
        +
        +Code generation is typically integrated into the build process, and for the `Citrus TestAPI Generator`,
        +this is accomplished using a Maven or Gradle plugin. While the standard `org.openapitools:openapi-generator-maven-plugin`
        +can be used for this purpose, configuring it, especially for multiple APIs, can be cumbersome and complex.
        +However, it is certainly possible, and a sample configuration is available in the
        +https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-core/pom.xml/[module descriptor].
         
        -Code generation is typically performed during the build process.
        -For the Citrus Test API Generator, it is carried out by a Maven or Gradle plugin.
        -While the standard generator plugin, `org.openapitools:openapi-generator-maven-plugin`, can be employed for this purpose, configuring it can be cumbersome, especially when dealing with multiple APIs.
        -To address this challenge, Citrus offers its own adaptation of this standard generator plugin.
        -This `Citrus OpenAPI Generator Plugin` simplifies the configuration of test API generation by providing predefined defaults and supporting the generation of multiple APIs.
        -Additionally, it enhances support for generating Spring integration files (`spring.handlers` and `spring.schemas`), as described above.
        -It is thereby facilitating the integration of generated APIs into Spring-based applications.
        -Consequently, utilizing the Citrus Generator Plugin is recommended in most scenarios.
        +To streamline this process, Citrus provides its own adaptation of the standard generator plugin: the
        +`Citrus OpenAPI Generator Plugin`. This plugin simplifies TestAPI generation by offering sensible
        +default configurations and better support for generating multiple APIs. It also enhances integration
        +with Spring by automatically generating Spring-specific files (`spring.handlers` and `spring.schemas`),
        +making it easier to integrate the generated APIs into Spring-based applications.
         
        -The following shows the configuration of test api generation for different scenarios:
        +Given these advantages, the Citrus OpenAPI Generator Plugin is recommended in most scenarios as it
        +greatly simplifies the configuration process and improves overall flexibility.
        +
        +The plugin is thoroughly tested across a wide variety of configurations. For additional details, you
        +can refer to
        +https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest[these]
        +sample project build descriptors used for testing.
        +
        +The following section provides a configuration example for basic TestAPI generation scenarios:
         
         .Citrus OpenAPI Generator Plugin - multiple APIs, minimal configuration
         [source,xml,indent=0,role="primary"]
        @@ -531,23 +847,41 @@ The following shows the configuration of test api generation for different scena
         
             citrus-test-api-generator-maven-plugin
             
        -        
        +        
        +        
        +            b
        +            otherOption
        +        
        +        
                 
        -            my-generated-sources
        -            my-generated-resources
                     myschema/xsd
                     src/main/resources/META-INF
                     
                         Full
                         api/test-api.yml
                         org.mypackage.%PREFIX%.api
        -                myEndpoint
                         org.mypackage.%PREFIX%.invoker
                         org.mypackage.%PREFIX%.model
        -                "http://company/citrus-test-api/myNamespace"
        +                myEndpoint
        +                
        +                    "http://company/citrus-test-api/myNamespace"
                         
        +                v1
        +                
        +                a=b,c=d
        +                
        +                    
        +                    generated-sources
        +                    generated-resources
        +                
                     
                 
        +        
        +        myschema/xsd
        +        
        +        src/main/resource-mod/META-INF-MOD
             
             
                 
        @@ -596,9 +930,15 @@ The following shows the configuration of test api generation for different scena
                     
                         ${project.basedir}/src/test/resources/apis/petstore.yaml
                         
        -                    org.citrusframework.openapi.generator.rest.petstore
        -                    org.citrusframework.openapi.generator.rest.petstore.request
        -                    org.citrusframework.openapi.generator.rest.petstore.model
        +                    
        +                        org.citrusframework.openapi.generator.rest.petstore
        +                    
        +                    
        +                        org.citrusframework.openapi.generator.rest.petstore.request
        +                    
        +                    
        +                        org.citrusframework.openapi.generator.rest.petstore.model
        +                    
                             PetStore
                             petStoreEndpoint
                         
        @@ -611,13 +951,20 @@ The following shows the configuration of test api generation for different scena
                         generate
                     
                     
        -                ${project.basedir}/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml
        +                
        +                    ${project.basedir}/src/test/resources/org/citrusframework/openapi/generator/SimpleWsdlToOpenApiTransformerTest/BookService-generated.yaml
        +                
                         
                             SOAP
        -                    org.citrusframework.openapi.generator.soap.bookservice
        -                    org.citrusframework.openapi.generator.soap.bookservice.request
        -                    org.citrusframework.openapi.generator.soap.bookservice.model
        -                    SoapSample
        +                    
        +                        org.citrusframework.openapi.generator.soap.bookservice
        +                    
        +                    
        +                        org.citrusframework.openapi.generator.soap.bookservice.request
        +                    
        +                    
        +                        org.citrusframework.openapi.generator.soap.bookservice.model
        +                    
                             OpenApiFromWsdl
                             soapSampleEndpoint
                         
        @@ -630,74 +977,106 @@ The following shows the configuration of test api generation for different scena
         These are the primary elements you can configure in the `` section:
         
         |===
        -| Configuration element            | Maven Property                                                | Description                                                      | Default Value
        -
        -| `schemaFolder`                   | `citrus.test.api.generator.schema.folder`                     | Location of the generated XSD schemas                            | `schema/xsd/%VERSION%`
        -| `resourceFolder`                 | `citrus.test.api.generator.resource.folder`                   | Location into which the resources are generated                  | `generated-resources`
        -| `sourceFolder`                   | `citrus.test.api.generator.source.folder`                     | Location into which the sources are generated                    | `generated-sources`
        -| `metaInfFolder`                  | `citrus.test.api.generator.meta.inf.folder`                   | Location into which spring meta files are generated/updated      | `target/generated-test-resources/META-INF`
        -| `generateSpringIntegrationFiles` | `citrus.test.api.generator.generate.spring.integration.files` | Specifies whether spring integration files should be generated   | `true`
        -| Nested `` element         |                                                               |                                                                  |
        -| `prefix`                         | `citrus.test.api.generator.prefix`                            | Specifies the prefix used for the test API, typically an acronym | (no default, **required**)
        -| `source`                         | `citrus.test.api.generator.source`                            | Specifies the source of the test API                             | (no default, **required**)
        -| `version`                        | `citrus.test.api.generator.version`                           | Specifies the version of the API, may be `null`                  | (none)
        -| `endpoint`                       | `citrus.test.api.generator.endpoint`                          | Specifies the endpoint of the test API                           | `applicationServiceClient`
        -| `type`                           | `citrus.test.api.generator.type`                              | Specifies the type of the test API                               | `REST`, other option is `SOAP`
        -| `useTags`                        | `citrus.test.api.generator.use.tags`                          | Specifies whether tags should be used by the generator           | `true`
        -| `invokerPackage`                 | `citrus.test.api.generator.invoker.package`                   | Package for the test API classes                                 | `org.citrusframework.automation.%PREFIX%.%VERSION%`
        -| `apiPackage`                     | `citrus.test.api.generator.api.package`                       | Package for the test API interface classes                       | `org.citrusframework.automation.%PREFIX%.%VERSION%.api`
        -| `modelPackage`                   | `citrus.test.api.generator.model.package`                     | Package for the test API model classes                           | `org.citrusframework.automation.%PREFIX%.%VERSION%.model`
        -| `targetXmlnsNamespace`           | `citrus.test.api.generator.namespace`                         | XML namespace used by the API                                    | `http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api`
        +| Configuration element            | Maven Property   (ns = citrus.test.api.generator)                                             | Description                                                      | Default Value
        +
        +| `schemaFolder`                   | `ns.schema.folder`                     | Location of the generated XSD schemas                            | `schema/xsd/%VERSION%`
        +| `metaInfFolder`                  | `ns.meta.inf.folder`                   | Location into which spring meta files are generated/updated      | `target/generated-test-resources/META-INF`
        +| `generateSpringIntegrationFiles` | `ns.generate.spring.integration.files` | Specifies whether spring integration files should be generated   | `true`
        +
        +4+| Nested `` element
        +| `prefix`                         | `ns.prefix`                            | Specifies the prefix used for the TestAPI, typically an acronym. | (no default, **required**)
        +| `source`                         | `ns.source`                            | Specifies the source of the TestAPI.                             | (no default, **required**)
        +| `version`                        | `ns.version`                           | Specifies the version of the API, may be `null`.                  | (none)
        +| `endpoint`                       | `ns.endpoint`                          | Specifies the default endpoint name of the TestAPI.                           | `%PREFIX%Endpoint`
        +| `type`                           | `ns.type`                              | Specifies the type of the TestAPI.                               | `REST`, other option is `SOAP`
        +| `useTags`                        | `ns.use.tags`                          | Specifies whether the generator should generate an API class per tag name. | `true`
        +| `invokerPackage`                 | `ns.invoker.package`                   | Package for the TestAPI classes.                                 | `org.citrusframework.automation.%PREFIX%.%VERSION%`
        +| `apiPackage`                     | `ns.api.package`                       | Package for the TestAPI interface classes.                       | `org.citrusframework.automation.%PREFIX%.%VERSION%.api`
        +| `modelPackage`                   | `ns.model.package`                     | Package for the TestAPI model classes.                           | `org.citrusframework.automation.%PREFIX%.%VERSION%.model`
        +| `targetXmlnsNamespace`           | `ns.namespace`                         | XML namespace used by the API.                                    | `http://www.citrusframework.org/schema/%VERSION%/%PREFIX%-api`
        +| Nested `` element 3+|  https://openapi-generator.tech/docs/generators/java[OpenAPI Generator Options]
        +| `resourceFolder`                 |                    | Location into which the resources are generated                  | Dependend on the phase in which the source is generated:
        +-`target/generated-sources/openapi/src/main/java`
        +-`target/generated-test-sources/openapi/src/main/java`
        +| `sourceFolder`                   |                      | Location into which the sources are generated                    | Dependend on the phase in which the source is generated:
        +-`target/generated-sources/openapi/src/main/resources`
        +-`target/generated-test-sources/openapi/src/main/resources`
        +|  `` 3+|  https://openapi-generator.tech/docs/globals[OpenAPI Generator global Config Options]
         |===
         
         Note: `%PREFIX%` and `%VERSION%` are placeholders that will be replaced by their specific values as configured.
         The plugin performs a conversion to lowercase for `PREFIX` used in package names and in `targetXmlnsNamespace`.
         
        +[[openapi-test-api-generator-run]]
         ==== Running the generator
         
         To run the generator, execute the following command in your project directory:
         
         [source,bash]
         ----
        -mvn citrus-test-api-generator-maven-plugin:create-test-api
        +mvn citrus-test-api-generator:create-test-api
         ----
         
         This command will generate the classes and XSD files as configured for your APIs in the specified locations.
         
        +[[openapi-test-api-generator-spring-meta]]
         ==== Spring meta file generation
         
        -The `citrus-test-api-generator-maven-plugin` supports the generation of Spring integration files, specifically `spring.handlers` and `spring.schemas`.
        -These files are essential for Spring applications utilizing XML configuration.
        -The generated Spring integration files serve the purpose of mapping custom XML namespaces to their corresponding namespace handler and schema locations.
        -This mapping allows Spring to properly parse and validate XML configuration files containing custom elements and attributes.
        +The `citrus-test-api-generator-maven-plugin` supports the generation of essential Spring integration
        +files, namely `spring.handlers` and `spring.schemas`. These files play a crucial role for Spring applications
        +that use XML configuration.
         
        +The generated Spring integration files provide mappings between custom XML namespaces and their
        +corresponding namespace handlers and schema locations. This mapping enables Spring to correctly parse
        +and validate XML configuration files that contain custom elements and attributes, ensuring seamless
        +integration with your Spring-based application.
        +
        +[[openapi-test-api-generator-spring-meta-config]]
         ===== Configuration
         
        -The maven plugin generates these Spring integration files based on the provided configuration in the `citrus-test-api-generator-maven-plugin` section of the `pom.xml` file.
        -For each API specified, the plugin writes entries into the `spring.handlers` and `spring.schemas` files according to the configured XML namespaces and their corresponding handlers and schemas.
        +The `citrus-test-api-generator-maven-plugin` generates the Spring integration files based on the
        +configuration provided in the `citrus-test-api-generator-maven-plugin` section of the pom.xml file.
        +For each API defined, the plugin generates entries in the `spring.handlers` and `spring.schemas` files,
        +mapping XML namespaces to their respective handlers and schema locations.
        +
        +===== Meta File Update Process
         
        -===== Important Consideration
        +If you are running your TestAPI alongside a non-generated API and need to modify the existing
        +`spring.handlers` and `spring.schemas` files from your non-generated source code, you should point
        +the metaInfoFolder to the location of your existing META-INF folder (e.g., src/test/resources/META-INF).
        +This ensures that the plugin updates the existing files without overwriting any content.
         
        -When there are other non-generated Spring schemas or handlers present in the `META-INF` folder, it's crucial to ensure that the `metaInfFolder` configuration points to the existing `META-INF` directory in the main resources, which is usually `src/main/resources/META-INF`.
        -This ensures that the plugin correctly updates the existing files without overwriting them.
        +To distinguish the generated schemas from the non-generated ones during the metafile update process,
        +the plugin checks for namespace URLs containing the segment `citrus-test-schemas`. When updating the
        +files, all schemas that match this segment will be removed, while the other schemas will be preserved.
        +After that, the plugin will add the namespaces for the generated TestAPI according to the configuration.
         
        -To identify generated schemas, their namespace should include the following segment `citrus-test-schema`.
        -During updates of the meta files, the generator filters out lines containing this segment from existing files and then re-adds them, preserving any non-generated content.
        +===== Usage
         
        -==== Usage
        +Once generated, the `spring.handlers` and `spring.schemas` files, along with any existing
        +non-generated content, should be included in the classpath of your Spring application.
        +During runtime, Spring will pick up and use these files to resolve custom XML namespaces and handle elements
        +accordingly. This automatically happens if one of the following folders is chosen:
         
        -Once generated, the `spring.handlers` and `spring.schemas` files, along with any existing non-generated content, should be included in the resources of your Spring application.
        -During runtime, Spring will use these files to resolve custom XML namespaces and handle elements accordingly.
        -This automatically happens if one of the following folders is chosen:
        +- target/generated-sources/openapi/src/main/resources/META-INF
        +- target/generated-test-sources/openapi/src/main/resources/META-INF (`default`)
        +- src/main/resources/META-INF - for mixing existing meta files with generated
        +- src/test/resources/META-INF - for mixing existing meta files with generated
         
        --   `target/generated-test-resources/META-INF` (default)
        --   `target/generated-resources/META-INF` for pure testing projects that provide their code on main rather than test
        --   `src/main/resources/META-INF` - for mixing existing meta files with generated
        +For the directories listed above, the resources folder is included in the classpath by default, depending
        +on whether tests are executed. For other directories, the Citrus TestAPI generator plugin automatically
        +adds them to the classpath.
         
        -==== Configuration of the Test Classpath
        +If your IDE fails to resolve the files, you may need to manually configure the directories as source
        +or resource folders. Additionally, consider adding a Maven build step to ensure these folders are handled
        +correctly during the build process.
         
        -In case you choose to generate the API into `generated-test` folders, the maven build requires further configuration to add the `generated-test` folders to the classpath.
        -The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-helper-maven-plugin] is used to accomplish this configuration step.
        +==== Configuration of the Classpath for using TestAPI
        +
        +In case you encounter issues with the classpath when running your TestAPI, you may want to manually
        +configure the classpath to contain the generated sources/resources. You can use the
        +link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-helper-maven-plugin] plugin to do so.
        +Explicit definition of these classpath entries should solve all related issues.
         
         .Configuration of `build-helper-maven-plugin`
         [source,xml]
        @@ -716,7 +1095,7 @@ The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-hel
                        
                        
                           
        -                     ${project.build.directory}/generated-test-sources
        +                     ${project.build.directory}/generated-test-sources/openapi/src/main/java
                           
                        
                     
        @@ -729,7 +1108,7 @@ The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-hel
                        
                           
                              
        -                        ${project.build.directory}/generated-test-resources
        +                        ${project.build.directory}/generated-test-sources/openapi/src/main/resources
                              
                           
                        
        @@ -742,11 +1121,33 @@ The link:https://www.mojohaus.org/build-helper-maven-plugin/usage.html[build-hel
         
         ==== Sample usage
         
        -To utilize the test API in XML, it's necessary to import the respective namespace.
        +To utilize the TestAPI in XML, it's necessary to import the respective namespace.
         Once imported, requests can be directly employed as actions, as illustrated in the sample below.
         Further examples can be found here `org.citrusframework.openapi.generator.GeneratedApiIT`.
         
        -.XML DSL
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +@ExtendWith(CitrusSpringExtension.class)
        +@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class})
        +class GetPetByIdTest {
        +
        +    @Autowired
        +    private ApplicationContext applicationContext;
        +
        +    @Autowired
        +    private PetApi petApi;
        +
        +    @Test
        +    @CitrusTest
        +    void testByJsonPath(@CitrusResource TestCaseRunner runner) {
        +        runner.when(petApi.sendGetPetById(1234L));
        +        runner.then(petApi.receiveGetPetById(OK));
        +    }
        +}
        +----
        +
        +.XML
         [source,xml,indent=0,role="secondary"]
         ----
         
             
                 
        -            
        -                
        -                    
        -                    
        -                
        -            
        +            
        +            
                 
             
         
         ----
         
        -To utilize the test API in Java, it's necessary to import the API configuration, that provides the respective request actions.
        -The request to test can then be configured and autowired, as illustrated in the sample below.
        -Further examples can be found here: `org.citrusframework.openapi.generator.GetPetByIdIT`.
        +To use the TestAPI in Java, you need to import the relevant API configuration, which provides the necessary request actions.
        +In the example above, this configuration is named PetStoreBeanConfiguration.
        +Once imported, you can autowire the API and use its builder methods to create dedicated actions for your operations.
         
        -.Java DSL
        -[source,java,indent=0,role="secondary"]
        -----
        -@ExtendWith(CitrusSpringExtension.class)
        -@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class})
        -class GetPetByIdTest {
        +*Type-Safe Action Builders*
         
        -    @Autowired
        -    private ApplicationContext applicationContext;
        +The Java DSL offers type-safe methods for all required parameters.
        +For example, the `getPetById` operation requires a valid petId of type long, as shown in the sample.
        +This ensures that all parameters are correctly typed, providing compile-time validation and reducing the risk of errors.
         
        -    @Autowired
        -    private GetPetByIdRequest getPetByIdRequest;
        +*Dynamic Content with String Expressions*
         
        -    @Test
        -    @CitrusTest
        -    void testByJsonPath(@CitrusResource TestCaseRunner runner) {
        +In addition to type-safe builder methods, there is another version of each action that allows you to
        +pass string expressions, which are dynamically resolved by Citrus at runtime.
        +These methods have the same name as their type-safe counterparts, but they end with a `$`.
        +For instance, if the type-safe method is getPetById(long petId), the dynamic method would be getPetById$(String petId).
         
        -        // Given
        -        getPetByIdRequest.setPetId("1234");
        +The reason for the $ in the method name is related to the underlying code generation mechanism, which facilitates dynamic content substitution during runtime.
         
        -        // Then
        -        getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
        -        getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());
        +*Example: Type-Safe vs Dynamic Method*
        +Both method calls achieve the same outcome, but one provides type safety at compile-time, while the other allows for dynamic content resolution at runtime:
         
        -        // Assert body by json path
        -        getPetByIdRequest.setResponseValue(Map.of("$.name", "Snoopy"));
        +- *Type-Safe:* getPetById(123L);
        +- *Dynamic:* getPetById$("123");
         
        -        // When
        -        runner.$(getPetByIdRequest);
        -    }
        +In both cases, the correct action is created, but the former ensures type correctness at compile time, while the latter allows flexibility with dynamic values.
        +
        +
        +==== OpenAPI Default Endpoint
        +
        +It is possible to specify a default endpoint for a generated TestAPI.
        +The endpoint needs to be registered as bean and will be resolved when needed.
        +The name of the endpoint can be specified as configuration parameter in the <> config options.
        +If not specified a default name is derived from the TestAPI prefix as follows:
        +
        +Endpointname: `prefixEndpoint`
        +
        +Because of the default endpoint option, it is not required to specify the endpoint in the action builder.
        +If omitted, the endpoint will be resolved at runtime.
        +Failure in specification of a default endpoint will result in an exception at runtime.
        +
        +The following shows an example of how to specify two endpoints for the same server:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +@Bean(name = {"petstoreEndpoint", "extpetstoreEndpoint"})
        +public HttpClient applicationServiceClient() {
        +    return new HttpClientBuilder()
        +        .requestUrl("http://localhost:8080")
        +        .handleCookies(true)
        +        .build();
         }
         ----
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +
        +----
        +
        +==== OpenAPI Security
        +
        +An OpenAPI may contain security specifications which can be referenced by operations.
        +Several schemes exist, of which Citrus currently supports:
        +
        +- Basic Authentication
        +- Bearer Authentication
        +- Api Key Authentication
        +
        +The following snippet shows the definition of these security schemes in an OpenAPI.
        +
        +.Yaml
        +[source,yaml,indent=0,role="primary"]
        +----
        +openapi: 3.0.2
        +info:
        +title: Extended Petstore API
        +description: "This API extends the standard Petstore API. Although the operations\
        +\ may not be meaningful in\na real-world context, they are designed to showcase\
        +\ various advanced OpenAPI features that \nare not present in the standard Petstore\
        +\ API.\n"
        +version: 1.0.0
        +servers:
        +- url: http://localhost:9000/api/v3/ext
        +....
        +components:
        +  securitySchemes:
        +    basicAuth:
        +      type: http
        +      scheme: basic
        +    bearerAuth:
        +      type: http
        +      scheme: bearer
        +      bearerFormat: JWT
        +    api_key_header:
        +      type: apiKey
        +      description: Header api key description
        +      name: api_key_header
        +      in: header
        +    api_key_cookie:
        +      type: apiKey
        +      description: Cookie api key description
        +      name: api_key_cookie
        +      in: cookie
        +    api_key_query:
        +      type: apiKey
        +      description: Query api key description
        +      name: api_key_query
        +      in: query
        +----
        +
        +===== Basic Authentication
        +
        +Citrus supports Basic Authentication by specifying the following properties per authenticated TestAPI:
        +
        +.Properties
        +[source,properties,indent=0,role="primary"]
        +----
        +extpetstore.basic.username=extUser
        +extpetstore.basic.password=extPassword
        +----
        +
        +The properties must be prefixed with the API prefix in lower case.
        +
        +If present, these values will automatically be added as authorization headers to each call of relevant operations.
        +
        +In addition, it is possible to set the values on the operation action builder, possibly overwriting the above defaults:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        + runner.when(extPetApi
        +  .sendGetPetByIdWithBasicAuthentication$("${petId}", "true")
        +  .basicAuthUsername("admin")
        +  .basicAuthPassword("topSecret")
        +  .fork(true));
        +----
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +----
        +
        +===== Bearer Authentication
        +
        +For bearer authentication, a bearer token may be specified using the following property:
        +
        +.Properties
        +[source,properties,indent=0,role="primary"]
        +----
        +extpetstore.bearer.token=defaultBearerToken
        +----
        +
        +The property must be prefixed with the API prefix in lower case.
        +
        +If present, this value will automatically be added as `Authorization Bearer Header`  to each call of relevant operations.
        +
        +In addition, it is possible to set this value on the operation action builder, possibly overwriting the above default:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        + runner.when(extPetApi
        +  .sendGetPetByIdWithBasicAuthentication$("${petId}", "true")
        +  .basicAuthBearer("bearerToken")
        +  .fork(true));
        +----
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +----
        +
        +==== API Key Authentication
        +
        +Citrus supports API Key Authentication by specifying the following properties per authenticated TestAPI:
        +
        +.Properties
        +[source,properties,indent=0,role="primary"]
        +----
        +# Whether the api key should be Base64 encoded or not
        +extpetstore.base64-encode-api-key=true
        +extpetstore.api-key-query=defaultTopSecretQueryApiKey
        +extpetstore.api-key-header=defaultTopSecretHeaderApiKey
        +extpetstore.api-key-cookie=defaultTopSecretCookieApiKey
        +----
        +
        +The properties must be prefixed with the API prefix in lower case.
        +
        +If present, these values will automatically be added as a query, header or cookie to each call of relevant operations.
        +
        +In addition, it is possible to set the values on the operation action builder, possibly overwriting the above defaults:
        +
        +.Java
        +[source,java,indent=0,role="primary"]
        +----
        +runner.when(extPetApi
        +    .sendGetPetByIdWithApiKeyAuthentication$("${petId}", "false")
        +    .apiKeyHeader("TopSecretHeader")
        +    .apiKeyCookie("TopSecretCookie")
        +    .apiKeyQuery("TopSecretQuery")
        +    .fork(true));
        +----
        +
        +Note that only one type of parameter (query, header or cookie) should be specified in a real world scenario.
        +
        +.XML
        +[source,xml,indent=0,role="secondary"]
        +----
        +
        +----
        +
        +
        +=== TestAPI  Configuration and Usage Samples
        +
        +The Citrus TestAPI module includes numerous tests that serve as excellent starting points.
        +
        +- The https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest[TestApiGeneratorMojoIntegrationTest]
        +folder contains various Maven configurations for specifcation of TestAPI generation.
        +
        +- The https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java[GeneratedRestApiIT]
        +is the primary integration test for the Citrus TestAPI in a REST environment. +
        +It includes over 100 tests written in both `Java DSL` and `XML`, covering all aspects of the generated TestAPI. +
        +The https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml[ExtendedPetAPI]
        +provides a range of specific operations for testing, all of which are thoroughly covered in this test.
        +
        +- For SOAP integration, the https://github.com/citrusframework/citrus/tree/main/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedSoapApiIT.java[GeneratedSoapApiIT]
        +serves as the main integration test for Citrus TestAPI in a SOAP environment.
        diff --git a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java
        index 9353672ca9..82f8d1f1c2 100644
        --- a/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java
        +++ b/test-api-generator/citrus-test-api-core/src/main/java/org/citrusframework/openapi/testapi/spring/RestApiSendMessageActionParser.java
        @@ -35,6 +35,7 @@
         import org.citrusframework.http.config.xml.HttpSendRequestActionParser;
         import org.citrusframework.http.message.HttpMessage;
         import org.citrusframework.http.message.HttpMessageBuilder;
        +import org.citrusframework.openapi.AutoFillType;
         import org.citrusframework.openapi.OpenApiSpecification;
         import org.citrusframework.openapi.actions.OpenApiClientRequestActionBuilder.OpenApiClientRequestMessageBuilder;
         import org.citrusframework.openapi.actions.OpenApiSpecificationSource;
        @@ -138,6 +139,8 @@ protected BeanDefinitionBuilder createBeanDefinitionBuilder(final Element elemen
                     beanDefinitionBuilder);
                 beanDefinitionBuilder.addConstructorArgValue(actionBuilder.getBeanDefinition());
         
        +        beanDefinitionBuilder.addPropertyValue("autoFill", element.getAttribute("autofill"));
        +
                 setDefaultEndpoint(beanDefinitionBuilder);
         
                 Element receive = getChildElementByTagName(element, "receive");
        @@ -399,5 +402,9 @@ public HttpClientRequestActionBuilder getBuilder() {
                 public void setBuilder(RestApiSendMessageActionBuilder builder) {
                     this.builder = builder;
                 }
        +
        +        public void setAutoFill(AutoFillType autoFill) {
        +            this.builder.autoFill(autoFill);
        +        }
             }
         }
        diff --git a/test-api-generator/citrus-test-api-generator-core/README.md b/test-api-generator/citrus-test-api-generator-core/README.md
        deleted file mode 100644
        index 72f5c7a381..0000000000
        --- a/test-api-generator/citrus-test-api-generator-core/README.md
        +++ /dev/null
        @@ -1,108 +0,0 @@
        -TODO document the OpenApiSpecification retrieval strategy
        -    - An OpenApiRepository does not have a unique name (and can exist in several versions). Therefore,
        -      retrieval of a specifc spec from a repository is not trivial. For this, the alias concept has 
        -      been introduced. Aliases are determined from the spec (e.g. the name of the spec, the resource 
        -      name from which the spec was loaded without extension). Also, the name of the repository itself
        -      can be used for retrieval, IF the repository contains only one spec. Otherwise, this would not be
        -      ambiguous.
        -TODO: document properties for security and others
        -TODO: document default properties for the endpoint -> prefix with lowercase 
        -
        -## Generated Java Code for API Testing
        -
        -The code generator creates Java classes from an OpenAPI specification to facilitate API testing using the Citrus framework. 
        -The Java classes represent Citrus Send and Receive ActionBuilders for each operation of the OpenAPI. Each builder provides
        -setter for the actual operation parameters. In general a type-safe method is provided, that reflects the correct operation type.
        -In addition a setter in string representation is provided to allow for citrus dynamic content setting using string expressions.
        -For each builder a specific operation is added to ...
        -A type-safe method providing the correct java type and a non type-safe method using a string type, allowing the usage of citrus expressions for the respective content.
        -
        -1. **Type-Safe Parameter Method**: This method accepts the required parameters directly.
        -2. **String-Based Parameter Method**: This method accepts parameters as strings to allow for dynamic content.
        -
        -Method names of non type-safe methods are prepended with a `$`. This is mainly to avoid conflicts.
        -
        -### Structure of the Generated API Class
        -
        -For each API operation, the generated class includes:
        -
        -1. **Builder with Type-Safe Required Parameters**: A method that takes the required parameters directly and returns a builder configured with these parameters.
        -
        -2. **Builder with Parameters as Strings**: A method that takes parameters as strings, allowing dynamic replacements via the Citrus framework. The method name is suffixed with `$` to distinguish it from the type-safe version.
        -
        -### Example
        -
        -Consider an operation to delete a pet with the following parameter:
        -- `petId` (required, type `Long`)
        -
        -The generated Java API class might look like this:
        -
        -```java
        -public class PetsApi {
        -
        -    /**
        -     * Builder with type safe required parameters.
        -     */
        -    public DeletePetRequestActionBuilder sendDeletePet(Long petId) {
        -        DeletePetRequestActionBuilder builder = new DeletePetRequestActionBuilder(openApiSpecification, petId);
        -        builder.endpoint(httpClient);
        -        return builder;
        -    }
        -
        -    /**
        -     * Builder with required parameters as string, allowing dynamic content using citrus expressions.
        -     */
        -    public DeletePetRequestActionBuilder sendDeletePet$(String petIdExpression) {
        -        DeletePetRequestActionBuilder builder = new DeletePetRequestActionBuilder(petIdExpression, openApiSpecification);
        -        builder.endpoint(httpClient);
        -        return builder;
        -    }
        -}
        -```
        -
        -## Known issues
        -
        -## Validation
        -
        -It is known, that the used OpenAPI validator is not able to validate certain situations.
        -E.g. certain array encoding situations related to object encoding 
        -
        -## Variable processing
        -
        -Processing of variables in case of parameter serialization, in some cases causes problems. For example, it  
        -is not possible to assign a json string to a variable and path it into an object into the current 
        -parameter serialization mechanism. This expects a real json, which cannot be resolved. To solve this issue,
        -serialization of arrays must happen as late as possible. Maybe it is feasible to create an OpenApiEndpointConfiguration
        -with a respective message converter.
        -
        -## Handling of Array Parameters
        -
        -Currently, all array parameters are handled in explode mode, regardless of the `explode` setting specified
        -in the API definition. This means that each item in an array will be serialized as a separate query 
        -parameter, even if the `explode` setting is set to `false` in the OpenAPI specification.
        -
        -### Example
        -
        -Suppose the OpenAPI specification defines an array parameter named `status` with the following attributes:
        -
        -```yaml
        -parameters:
        -  - name: status
        -    in: query
        -    description: Status values that need to be considered for filter
        -    required: false
        -    explode: false
        -    schema:
        -      type: string
        -      default: available
        -      enum:
        -        - available
        -        - pending
        -        - sold
        -```
        -
        -Despite the explode: false setting, the request will be serialized as follows:
        -
        -```
        -?status=available&status=pending&status=sold
        -```
        \ No newline at end of file
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java
        index 4da01c693e..b060c3e7ba 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/main/java/org/citrusframework/openapi/generator/CitrusJavaCodegen.java
        @@ -272,8 +272,8 @@ public CodegenType getTag() {
             @Override
             public void processOpts() {
                 super.processOpts();
        -        setupEndpoint();
                 setupApiPrefix();
        +        setupEndpoint();
                 setupNamespace();
                 setupFolders();
                 setupApiType();
        @@ -282,10 +282,8 @@ public void processOpts() {
             }
         
             private void setupEndpoint() {
        -        if (additionalProperties.containsKey(API_ENDPOINT)) {
        -            this.setHttpClient(additionalProperties.get(API_ENDPOINT).toString());
        -        }
        -        additionalProperties.put(API_ENDPOINT, httpClient);
        +        additionalProperties.computeIfAbsent(API_ENDPOINT, k->apiPrefix+"Endpoint");
        +        this.setHttpClient(additionalProperties.get(API_ENDPOINT).toString());
             }
         
             private void setupApiPrefix() {
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache
        index 9500cacff1..3c889c78b9 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache
        +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/api.mustache
        @@ -220,7 +220,7 @@ public class {{classname}} implements GeneratedApi
         
                 private static final String ENDPOINT = "{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}";
         
        -        private static final String OPERATION_NAME = "{{operationId}}";
        +        private static final String OPERATION_NAME = "{{#operationIdOriginal}}{{operationId}}{{/operationIdOriginal}}{{^operationIdOriginal}}{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}_{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}{{/operationIdOriginal}}";
                 {{#hasApiKeyAuth}}
         
                 @Value("${" + "{{#lambda.lowercase}}{{prefix}}{{/lambda.lowercase}}.base64-encode-api-key:#{false}}")
        @@ -604,7 +604,7 @@ public class {{classname}} implements GeneratedApi
         
                 private static final String ENDPOINT = "{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}";
         
        -        private static final String OPERATION_NAME = "{{operationId}}";
        +        private static final String OPERATION_NAME = "{{#operationIdOriginal}}{{operationId}}{{/operationIdOriginal}}{{^operationIdOriginal}}{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}_{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}{{/operationIdOriginal}}";
         
                 public {{operationIdCamelCase}}ReceiveActionBuilder({{classname}} {{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}},  String statusCode) {
                     super({{#lambda.camelcase}}{{classname}}{{/lambda.camelcase}}, {{#lambda.camelcase}}{{prefix}}{{/lambda.camelcase}}Specification, METHOD, ENDPOINT, OPERATION_NAME, statusCode);
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache
        index b4576a59d8..40c3e5e3d1 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache
        +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/namespace_handler.mustache
        @@ -43,7 +43,7 @@ public class {{#lambda.titlecase}}{{prefix}}{{/lambda.titlecase}}NamespaceHandle
                 {{#operations}}
                 {{#operation}}
         
        -            registerOperationParsers({{classname}}.class,"{{#lambda.kebabcase}}{{operationId}}{{/lambda.kebabcase}}", "{{operationIdOriginal}}", "{{path}}",
        +            registerOperationParsers({{classname}}.class,"{{#lambda.kebabcase}}{{operationId}}{{/lambda.kebabcase}}", "{{#operationIdOriginal}}{{operationId}}{{/operationIdOriginal}}{{^operationIdOriginal}}{{#lambda.uppercase}}{{httpMethod}}{{/lambda.uppercase}}_{{#rootContextPath}}{{rootContextPath}}{{/rootContextPath}}{{^neglectBasePath}}{{basePathWithoutHost}}{{/neglectBasePath}}{{path}}{{/operationIdOriginal}}", "{{path}}",
                         {{classname}}.{{operationIdCamelCase}}SendActionBuilder.class,
                         {{classname}}.{{operationIdCamelCase}}ReceiveActionBuilder.class,
                         new String[]{ {{#requiredNonBodyParams}}"{{paramName}}{{^isString}}{{/isString}}"{{^-last}}, {{/-last}}{{/requiredNonBodyParams}} },
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache
        index 64e0738760..54ab56c2f7 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache
        +++ b/test-api-generator/citrus-test-api-generator-core/src/main/resources/java-citrus/schema.mustache
        @@ -27,6 +27,14 @@
                 schemaLocation="http://www.citrusframework.org/schema/http/testcase/citrus-http-testcase.xsd"
             />
         
        +    
        +        
        +            
        +            
        +            
        +        
        +    
        +
             
                 
                     
        @@ -48,6 +56,7 @@
                 
                 
                 
        +        
             
         
             
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java
        index f8f23ca1a2..5e12e63c91 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/CitrusJavaCodegenTest.java
        @@ -170,11 +170,13 @@ void testFromOperation() {
                 Operation operation = Mockito.mock(Operation.class);
                 List servers = Collections.emptyList();
         
        -        CodegenOperation codegenOperation = codegen.fromOperation("/path", "GET", operation, servers);
        +        CodegenOperation codegenOperation = codegen.fromOperation("/path/segment1/{param1}/segment3/{param2}", "GET", operation, servers);
                 assertThat(codegenOperation)
                         .isInstanceOf(CustomCodegenOperation.class)
                         .hasFieldOrPropertyWithValue("httpMethod", "GET")
        -                .hasFieldOrPropertyWithValue("path", "/path");
        +                .hasFieldOrPropertyWithValue("path", "/path/segment1/{param1}/segment3/{param2}")
        +                .hasFieldOrPropertyWithValue("operationId", "pathSegment1Param1Segment3Param2GET")
        +                .hasFieldOrPropertyWithValue("operationIdOriginal", null);
             }
         
             @Test
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java
        index d51316443a..00e6a91c93 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/java/org/citrusframework/openapi/generator/GeneratedRestApiIT.java
        @@ -243,6 +243,39 @@ public ApiActionBuilderCustomizer petApiCustomizer() {
                 }
             }
         
        +    @Nested
        +    class OperationWithoutOperationId {
        +
        +        @Test
        +        @CitrusTestSource(type = TestLoader.SPRING, packageName = "org.citrusframework.openapi.generator.GeneratedApiTest", name = "withoutOperationIdTest")
        +        void xml() {
        +        }
        +
        +        @Test
        +        void java_operation_without_operationId(@CitrusResource TestCaseRunner runner) {
        +            runner.variable("petId", "1234");
        +
        +            runner.when(extPetApi.sendPetWithoutOperationIdPetIdGet(1234)
        +                .fork(true));
        +            runner.then(http().server(httpServer)
        +                .receive()
        +                .get("/api/v3/ext/pet/without-operation-id/1234")
        +                .message());
        +
        +            runner.then(http().server(httpServer)
        +                .send()
        +                .response(OK)
        +                .message()
        +                .contentType(APPLICATION_JSON_VALUE)
        +                .body(Resources.create(
        +                    "classpath:org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetById_response.json"))
        +                .contentType(APPLICATION_JSON_VALUE));
        +
        +            runner.when(extPetApi
        +                .receivePetWithoutOperationIdPetIdGet(OK));
        +
        +        }
        +    }
             /**
              * Demonstrates usage of parameter serialization according to
              * ...
        @@ -2501,7 +2534,7 @@ void java(@CitrusResource TestCaseRunner runner) {
         
                     runner.then(http().server(otherHttpServer)
                         .receive()
        -                .get("/api/v3/ext/pet/simple/object/uuid/" + uuid.toString())
        +                .get("/api/v3/ext/pet/simple/object/uuid/" + uuid)
                         .message()
                         .accept("@contains('application/json')@"));
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml
        index da8ceca2fe..255b98d238 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/apis/petstore-extended-v3.yaml
        @@ -2,13 +2,38 @@ openapi: 3.0.2
         info:
             title: Extended Petstore API
             description: |
        -        This is an extended version of the Petstore API which includes additional operations, 
        -        such as updating a pet using form data and managing vaccination records.
        +        This API extends the standard Petstore API. Although the operations may not be meaningful in
        +        a real-world context, they are designed to showcase various advanced OpenAPI features that 
        +        are not present in the standard Petstore API.
             version: 1.0.0
         servers:
             -   url: http://localhost:9000/api/v3/ext
         
         paths:
        +    /pet/without-operation-id/{petId}:
        +        get:
        +            tags:
        +                - extPet
        +            summary: Get a pet by id. This operation has no operationId.
        +            description: "Returns pet by ID using. This operation has no operationId."
        +            parameters:
        +                -   name: petId
        +                    in: path
        +                    description: ID of pet to return
        +                    required: true
        +                    schema:
        +                        type: integer
        +            responses:
        +                '200':
        +                    description: Successful operation
        +                    content:
        +                        application/json:
        +                            schema:
        +                                $ref: './petstore-v3.yaml#/components/schemas/Pet'
        +                '400':
        +                    description: Invalid ID supplied
        +                '404':
        +                    description: Pet not found
             /pet/simple/object/uuid/{petUuid}:
                 get:
                     tags:
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java
        index f87ae2279b..25c79ddbb6 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Category.java
        @@ -24,7 +24,7 @@
         /**
          * Category
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Category {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java
        index e4d8b586d7..a4966efcb1 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/HistoricalData.java
        @@ -25,7 +25,7 @@
         /**
          * Additional historical data for a vaccination report, not contained in internal storage. 
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class HistoricalData {
           private LocalDate lastVaccinationDate;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java
        index c124787b5a..19a5293f83 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Pet.java
        @@ -29,7 +29,7 @@
         /**
          * Pet
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Pet {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java
        index e214406d81..49117bed19 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/PetIdentifier.java
        @@ -24,7 +24,7 @@
         /**
          * PetIdentifier
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class PetIdentifier {
           private String _name;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java
        index f133cd3e31..c95a7058f5 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/Tag.java
        @@ -24,7 +24,7 @@
         /**
          * Tag
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Tag {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java
        index 4955814194..4600b1ece3 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/model/VaccinationDocumentResult.java
        @@ -24,7 +24,7 @@
         /**
          * VaccinationDocumentResult
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class VaccinationDocumentResult {
           private String documentId;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java
        index b85817a1ff..79f431441a 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/request/ExtPetApi.java
        @@ -43,7 +43,7 @@
         import org.citrusframework.openapi.generator.rest.extpetstore.model.VaccinationDocumentResult;
         
         @SuppressWarnings("unused")
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class ExtPetApi implements GeneratedApi
         {
         
        @@ -815,6 +815,28 @@ public GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder receiveGetPetWithSi
                 return new GetPetWithSimpleStyleObjectHeaderReceiveActionBuilder(this,  statusCode);
             }
         
        +    /**
        +     * Builder with type safe required parameters.
        +     */
        +    public PetWithoutOperationIdPetIdGetSendActionBuilder sendPetWithoutOperationIdPetIdGet(Integer petId)   {
        +            return new PetWithoutOperationIdPetIdGetSendActionBuilder(this, petId);
        +    }
        +
        +    /**
        +     * Builder with required parameters as string, allowing dynamic content using citrus expressions.
        +     */
        +    public PetWithoutOperationIdPetIdGetSendActionBuilder sendPetWithoutOperationIdPetIdGet$(String petIdExpression )   {
        +            return new PetWithoutOperationIdPetIdGetSendActionBuilder(petIdExpression, this);
        +    }
        +
        +    public PetWithoutOperationIdPetIdGetReceiveActionBuilder receivePetWithoutOperationIdPetIdGet(@NotNull HttpStatus statusCode)   {
        +        return new PetWithoutOperationIdPetIdGetReceiveActionBuilder(this, Integer.toString(statusCode.value()));
        +    }
        +
        +    public PetWithoutOperationIdPetIdGetReceiveActionBuilder receivePetWithoutOperationIdPetIdGet(@NotNull String statusCode)   {
        +        return new PetWithoutOperationIdPetIdGetReceiveActionBuilder(this,  statusCode);
        +    }
        +
             /**
              * Builder with type safe required parameters.
              */
        @@ -4751,6 +4773,119 @@ public ReceiveMessageAction doBuild() {
         
             }
         
        +    public static class PetWithoutOperationIdPetIdGetSendActionBuilder extends
        +                RestApiSendMessageActionBuilder implements GeneratedApiOperationInfo {
        +
        +        private static final String METHOD = "GET";
        +
        +        private static final String ENDPOINT = "/api/v3/ext/pet/without-operation-id/{petId}";
        +
        +        private static final String OPERATION_NAME = "GET_/api/v3/ext/pet/without-operation-id/{petId}";
        +
        +        /**
        +         * Constructor with type safe required parameters.
        +         */
        +        public PetWithoutOperationIdPetIdGetSendActionBuilder(ExtPetApi extPetApi, Integer petId) {
        +            super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME);
        +            pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false);
        +        }
        +
        +        /**
        +         * Constructor with required parameters as string to allow for dynamic content.
        +         */
        +            public PetWithoutOperationIdPetIdGetSendActionBuilder(String petIdExpression, ExtPetApi extPetApi) {
        +            super(extPetApi, extPetStoreSpecification,  METHOD, ENDPOINT, OPERATION_NAME);
        +            pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false);
        +        }
        +
        +        @Override
        +        public String getOperationName() {
        +            return OPERATION_NAME;
        +        }
        +
        +        @Override
        +        public String getMethod() {
        +            return METHOD;
        +        }
        +
        +        @Override
        +        public String getPath() {
        +            return ENDPOINT;
        +        }
        +
        +        /**
        +         * Constructor with required parameters as string to allow for dynamic content.
        +         */
        +        public PetWithoutOperationIdPetIdGetSendActionBuilder(ExtPetApi extPetApi, TestApiClientRequestMessageBuilder messageBuilder, String petIdExpression) {
        +            super(extPetApi, extPetStoreSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME);
        +            pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false);
        +        }
        +
        +        public PetWithoutOperationIdPetIdGetSendActionBuilder petId(Integer petId) {
        +            pathParameter("petId", petId, ParameterStyle.SIMPLE, false, false);
        +            return this;
        +        }
        +
        +        public PetWithoutOperationIdPetIdGetSendActionBuilder petId(String petIdExpression) {
        +            pathParameter("petId", petIdExpression, ParameterStyle.SIMPLE, false, false);
        +                return this;
        +        }
        +
        +        @Override
        +        public SendMessageAction doBuild() {
        +
        +            if (getCustomizers() != null) {
        +                getCustomizers().forEach(customizer -> customizer.customizeRequestBuilder(this, this));
        +            }
        +
        +            return super.doBuild();
        +        }
        +    }
        +
        +    public static class PetWithoutOperationIdPetIdGetReceiveActionBuilder extends
        +                        RestApiReceiveMessageActionBuilder implements GeneratedApiOperationInfo {
        +
        +        private static final String METHOD = "GET";
        +
        +        private static final String ENDPOINT = "/api/v3/ext/pet/without-operation-id/{petId}";
        +
        +        private static final String OPERATION_NAME = "GET_/api/v3/ext/pet/without-operation-id/{petId}";
        +
        +        public PetWithoutOperationIdPetIdGetReceiveActionBuilder(ExtPetApi extPetApi,  String statusCode) {
        +            super(extPetApi, extPetStoreSpecification, METHOD, ENDPOINT, OPERATION_NAME, statusCode);
        +        }
        +
        +        public PetWithoutOperationIdPetIdGetReceiveActionBuilder(ExtPetApi extPetApi, OpenApiClientResponseMessageBuilder messageBuilder) {
        +            super(extPetApi, extPetStoreSpecification, messageBuilder, messageBuilder.getMessage(), METHOD, ENDPOINT, OPERATION_NAME);
        +        }
        +
        +        @Override
        +        public String getOperationName() {
        +            return OPERATION_NAME;
        +        }
        +
        +        @Override
        +        public String getMethod() {
        +            return METHOD;
        +        }
        +
        +        @Override
        +        public String getPath() {
        +            return ENDPOINT;
        +        }
        +
        +        @Override
        +        public ReceiveMessageAction doBuild() {
        +
        +            if (getCustomizers() != null) {
        +                getCustomizers().forEach(customizer -> customizer.customizeResponseBuilder(this, this));
        +            }
        +
        +            return super.doBuild();
        +        }
        +
        +    }
        +
             public static class PostVaccinationDocumentSendActionBuilder extends
                         RestApiSendMessageActionBuilder implements GeneratedApiOperationInfo {
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java
        index 793bb8fc8e..0ca6dbfd28 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreBeanConfiguration.java
        @@ -15,7 +15,7 @@
         import org.citrusframework.openapi.generator.rest.extpetstore.ExtPetStoreOpenApi;
         
         @Configuration
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class ExtPetStoreBeanConfiguration {
         
             @Bean
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java
        index 6c56c475d2..d1147d9d86 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/extpetstore/spring/ExtPetStoreNamespaceHandler.java
        @@ -12,7 +12,7 @@
         import org.citrusframework.openapi.testapi.GeneratedApi;
         import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
         
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.512935700+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.524898+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class ExtPetStoreNamespaceHandler extends NamespaceHandlerSupport {
         
             @Override
        @@ -204,6 +204,12 @@ public void init() {
                         new String[]{ "petId" },
                     new String[]{  });
         
        +            registerOperationParsers(ExtPetApi.class,"pet-without-operation-id-pet-id-get", "GET_/api/v3/ext/pet/without-operation-id/{petId}", "/pet/without-operation-id/{petId}",
        +                ExtPetApi.PetWithoutOperationIdPetIdGetSendActionBuilder.class,
        +                ExtPetApi.PetWithoutOperationIdPetIdGetReceiveActionBuilder.class,
        +                new String[]{ "petId" },
        +            new String[]{  });
        +
                     registerOperationParsers(ExtPetApi.class,"post-vaccination-document", "postVaccinationDocument", "/pet/vaccination/{bucket}/{filename}",
                         ExtPetApi.PostVaccinationDocumentSendActionBuilder.class,
                         ExtPetApi.PostVaccinationDocumentReceiveActionBuilder.class,
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java
        index 79cbc4a5b9..c3c9eeac45 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Address.java
        @@ -24,7 +24,7 @@
         /**
          * Address
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Address {
           private String street;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java
        index adb7ab5b4a..54bfb4c0ed 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Category.java
        @@ -24,7 +24,7 @@
         /**
          * Category
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Category {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java
        index 304150abb7..aaa350d108 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Customer.java
        @@ -28,7 +28,7 @@
         /**
          * Customer
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Customer {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java
        index 178c3a56fa..829c0d4384 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/ModelApiResponse.java
        @@ -24,7 +24,7 @@
         /**
          * ModelApiResponse
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class ModelApiResponse {
           private Integer code;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java
        index 4d2916f2ff..ca29b9d1ca 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Order.java
        @@ -25,7 +25,7 @@
         /**
          * Order
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Order {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java
        index 3863a75cb4..6241feff86 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Pet.java
        @@ -29,7 +29,7 @@
         /**
          * Pet
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Pet {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java
        index d0779114f5..2139697852 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/Tag.java
        @@ -24,7 +24,7 @@
         /**
          * Tag
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class Tag {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java
        index fb5338f6b8..34509d8ac4 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/model/User.java
        @@ -24,7 +24,7 @@
         /**
          * User
          */
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class User {
           private Long id;
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java
        index dd944f0e25..17f78a1a90 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/PetApi.java
        @@ -38,7 +38,7 @@
         import org.citrusframework.openapi.generator.rest.petstore.model.Pet;
         
         @SuppressWarnings("unused")
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class PetApi implements GeneratedApi
         {
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java
        index e3997dbece..3359f32ed3 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/StoreApi.java
        @@ -37,7 +37,7 @@
         import org.citrusframework.openapi.generator.rest.petstore.model.Order;
         
         @SuppressWarnings("unused")
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class StoreApi implements GeneratedApi
         {
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java
        index 0a36c15896..1d8d085cb5 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/request/UserApi.java
        @@ -38,7 +38,7 @@
         import org.citrusframework.openapi.generator.rest.petstore.model.User;
         
         @SuppressWarnings("unused")
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class UserApi implements GeneratedApi
         {
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java
        index 96e9fae6cf..c37e2a3481 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreBeanConfiguration.java
        @@ -17,7 +17,7 @@
         import org.citrusframework.openapi.generator.rest.petstore.PetStoreOpenApi;
         
         @Configuration
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class PetStoreBeanConfiguration {
         
             @Bean
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java
        index 4155d1ad5d..f441d37cf9 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/rest/petstore/spring/PetStoreNamespaceHandler.java
        @@ -14,7 +14,7 @@
         import org.citrusframework.openapi.testapi.GeneratedApi;
         import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
         
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:06.769523100+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:47.794716200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class PetStoreNamespaceHandler extends NamespaceHandlerSupport {
         
             @Override
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java
        index 4e76813642..505b022375 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/request/BookServiceSoapApi.java
        @@ -17,7 +17,7 @@
         import org.citrusframework.openapi.testapi.SoapApiSendMessageActionBuilder;
         
         @SuppressWarnings("unused")
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.920209500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class BookServiceSoapApi implements GeneratedApi
         {
         
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java
        index 96e2616ee2..f27f214ca1 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceBeanConfiguration.java
        @@ -15,7 +15,7 @@
         import org.citrusframework.openapi.generator.soap.bookservice.BookServiceOpenApi;
         
         @Configuration
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.920209500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class BookServiceBeanConfiguration {
         
             @Bean
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java
        index 610ef9a276..36eac4ee50 100644
        --- a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/ExpectedCodeGenIT/expectedgen/soap/bookservice/spring/BookServiceNamespaceHandler.java
        @@ -10,7 +10,7 @@
         import org.citrusframework.openapi.testapi.GeneratedApi;
         import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
         
        -@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-23T18:00:07.870607200+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
        +@jakarta.annotation.Generated(value = "org.citrusframework.openapi.generator.CitrusJavaCodegen", date = "2025-01-29T23:14:48.920209500+01:00[Europe/Zurich]", comments = "Generator version: 7.9.0")
         public class BookServiceNamespaceHandler extends NamespaceHandlerSupport {
         
             @Override
        diff --git a/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withoutOperationIdTest.xml b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withoutOperationIdTest.xml
        new file mode 100644
        index 0000000000..1a7ce6d1f5
        --- /dev/null
        +++ b/test-api-generator/citrus-test-api-generator-core/src/test/resources/org/citrusframework/openapi/generator/GeneratedApiTest/withoutOperationIdTest.xml
        @@ -0,0 +1,43 @@
        +
        +    
        +        
        +            
        +                
        +            
        +
        +            
        +                
        +                    
        +                
        +            
        +
        +            
        +                
        +            
        +
        +            
        +                
        +                    
        +                
        +                
        +                    
        +                
        +            
        +
        +        
        +    
        +
        diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java
        index 26e3eb508f..dcd546ca06 100644
        --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java
        +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/main/java/org/citrusframework/maven/plugin/TestApiGeneratorMojo.java
        @@ -401,8 +401,6 @@ public enum ApiType {
                 REST, SOAP
             }
         
        -    // TODO: document all configuration properties
        -
             /**
              * Note that the default values are not properly set by maven processor. Therefore, the default
              * values have been assigned additionally on field level.
        diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java
        index e864da5b46..9d313cc84d 100644
        --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java
        +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/java/org/citrusframework/maven/plugin/TestApiGeneratorMojoUnitTest.java
        @@ -55,8 +55,7 @@ class TestApiGeneratorMojoUnitTest extends AbstractMojoTestCase {
         
             @Mock
             private MojoExecution mojoExecutionMock;
        -// TODO: test real world scenario with prefix=manageBooking and prefix=ManageBooking (should result in ManageBookingNamespaceHandler instead of manageBookingNamespaceHandler. Also check namespace name it contains managebooking - is that reasonable, also the api yaml cannot be loaded because of capital letters )?
        -    // TODO: Account Number as OpenAPI Parameter Name is allowed but leads to error as the space needs to be url encoded.
        +
             static Stream replaceDynamicVarsInPattern() {
                 return Stream.of(
                     arguments("%PREFIX%-aa-%VERSION%", "MyPrefix", "1", false, "MyPrefix-aa-1"),
        diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml
        index d030deee4b..4e447e6f8c 100644
        --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml
        +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-full-config.xml
        @@ -32,10 +32,8 @@
                                     a=b,c=d
                                     /a/b/c/d
                                     
        -                                
                                         b
                                         d
        -                                
                                         target/pom-full-config/target/generated-sources-mod/openapi-mod
                                         src/main/java-mod
                                         src/main/resource-mod
        diff --git a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml
        index c3675ca22c..754c2fcffa 100644
        --- a/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml
        +++ b/test-api-generator/citrus-test-api-generator-maven-plugin/src/test/resources/TestApiGeneratorMojoIntegrationTest/pom-with-overriding-config.xml
        @@ -25,7 +25,6 @@
                                     Minimal
                                     api/test-api.yml
                                     
        -                                
                                         b
                                         d
                                     
        diff --git a/tools/jbang/dist/CitrusJBang.java b/tools/jbang/dist/CitrusJBang.java
        index 665c9e924d..c2d5c5a44e 100755
        --- a/tools/jbang/dist/CitrusJBang.java
        +++ b/tools/jbang/dist/CitrusJBang.java
        @@ -18,8 +18,8 @@
         
         //JAVA 17+
         //REPOS mavencentral
        -//DEPS org.citrusframework:citrus-bom:${citrus.jbang.version:4.5.2}@pom
        -//DEPS org.citrusframework:citrus-jbang:${citrus.jbang.version:4.5.2}
        +//DEPS org.citrusframework:citrus-bom:${citrus.jbang.version:4.6.0-SNAPSHOT}@pom
        +//DEPS org.citrusframework:citrus-jbang:${citrus.jbang.version:4.6.0-SNAPSHOT}
         //DEPS org.citrusframework:citrus-jbang-connector
         //DEPS org.citrusframework:citrus-groovy
         //DEPS org.citrusframework:citrus-xml