From 4e2a4bdfa6caa0ba7f16b3bd1601f95f4e19f5b9 Mon Sep 17 00:00:00 2001 From: Thorsten Schlathoelter Date: Sun, 29 Sep 2024 14:54:06 +0200 Subject: [PATCH] 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 | 22 + .../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 | 3 +- .../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, 21708 insertions(+), 13221 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 0e0aa4a2f4..d542f0bbae 100644 --- a/catalog/citrus-bom/pom.xml +++ b/catalog/citrus-bom/pom.xml @@ -238,6 +238,21 @@ citrus-openapi 4.4.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 94445abcf3..8de25f9978 100644 --- a/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java +++ b/core/citrus-api/src/main/java/org/citrusframework/CitrusSettings.java @@ -427,7 +427,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 172acc9d7d..16694e9378 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 @@ -98,6 +98,10 @@ public class HttpEndpointConfiguration extends AbstractPollableEndpointConfigura /** Should handle http cookies */ private boolean handleCookies = 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(); @@ -396,6 +400,24 @@ 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 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 86105f9d87..3f623e52da 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ 3.4.0 3.1.1 3.3.0 - 3.5.0 + 3.10.0 1.6.13 3.9.0 3.13.1 @@ -260,6 +260,7 @@ 1.1.10.7 2.3 6.1.13 + 3.3.1 4.0.11 6.3.4 3.0.1 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 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 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