From 40e7de216913cdac1d8109529ea20ecfa4101e85 Mon Sep 17 00:00:00 2001 From: Ralf Ueberfuhr <40685729+ueberfuhr@users.noreply.github.com> Date: Mon, 3 Jun 2024 11:33:23 +0200 Subject: [PATCH] fix(#1169): openapi uses explicitly declared values instead of random values * fix: use explicitly declared values instead of random values * fix: use explicitly declared values instead of random values * fix: payload is by default an empty string * Add test for OpenApiClientRequestMessageBuilder --------- Co-authored-by: Ralf Ueberfuhr --- .../OpenApiClientRequestActionBuilder.java | 30 +++- ...penApiClientRequestMessageBuilderTest.java | 63 +++++++ ...e-derivation-for-message-builder-test.json | 164 ++++++++++++++++++ 3 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java create mode 100644 connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json 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 03f27805df..d646202c4d 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 @@ -98,23 +98,37 @@ public Message build(TestContext context, String messageType) { } if (operation.parameters != null) { + List configuredHeaders = getHeaderBuilders() + .stream() + .flatMap(b -> b.builderHeaders(context).keySet().stream()) + .toList(); operation.parameters.stream() .filter(param -> "header".equals(param.in)) .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> httpMessage.setHeader(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, - OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context))); + .forEach(param -> { + if(httpMessage.getHeader(param.getName()) == null && !configuredHeaders.contains(param.getName())) { + httpMessage.setHeader(param.getName(), + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, + OasModelHelper.getSchemaDefinitions(oasDocument), false, openApiSpec, context)); + } + }); operation.parameters.stream() .filter(param -> "query".equals(param.in)) .filter(param -> (param.required != null && param.required) || context.getVariables().containsKey(param.getName())) - .forEach(param -> httpMessage.queryParam(param.getName(), - OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, context))); + .forEach(param -> { + if(!httpMessage.getQueryParams().containsKey(param.getName())) { + httpMessage.queryParam(param.getName(), + OpenApiTestDataGenerator.createRandomValueExpression(param.getName(), (OasSchema) param.schema, context)); + } + }); } - Optional body = OasModelHelper.getRequestBodySchema(oasDocument, operation); - body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, - OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + if(httpMessage.getPayload() == null || (httpMessage.getPayload() instanceof String p && p.isEmpty())) { + Optional body = OasModelHelper.getRequestBodySchema(oasDocument, operation); + body.ifPresent(oasSchema -> httpMessage.setPayload(OpenApiTestDataGenerator.createOutboundPayload(oasSchema, + OasModelHelper.getSchemaDefinitions(oasDocument), openApiSpec))); + } String randomizedPath = pathItem.getPath(); if (operation.parameters != null) { diff --git a/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java new file mode 100644 index 0000000000..17b2159a60 --- /dev/null +++ b/connectors/citrus-openapi/src/test/java/org/citrusframework/openapi/actions/OpenApiClientRequestMessageBuilderTest.java @@ -0,0 +1,63 @@ +package org.citrusframework.openapi.actions; + +import org.citrusframework.context.TestContext; +import org.citrusframework.http.message.HttpMessage; +import org.citrusframework.message.Message; +import org.citrusframework.openapi.OpenApiSpecification; +import org.citrusframework.spi.Resources; +import org.testng.Assert; +import org.testng.annotations.Test; + +import static org.citrusframework.openapi.actions.OpenApiActionBuilder.openapi; + +public class OpenApiClientRequestMessageBuilderTest { + + private final OpenApiSpecification petstoreSpec = OpenApiSpecification.from( + Resources.create("classpath:org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json")); + + + @Test + public void shouldAddRandomDataForOperation() { + Message message = openapi() + .specification(petstoreSpec) + .client() + .send("addPet") // operationId + .build() + .getMessageBuilder() + .build(new TestContext(), ""); + Assert.assertTrue(message instanceof HttpMessage); + HttpMessage httpMessage = (HttpMessage) message; + // test payload + Object payload = httpMessage.getPayload(); + Assert.assertNotNull(payload); + Assert.assertTrue(payload instanceof String); + // test header + Object header = httpMessage.getHeader("X-SAMPLE-HEADER"); + Assert.assertNotNull(header); + } + + @Test + public void shouldAddCustomDataForOperation() { + String body = "{\"a\":\"b\"}"; + String sampleHeader = "X-SAMPLE-HEADER-VALUE"; + Message message = openapi() + .specification(petstoreSpec) + .client() + .send("addPet") // operationId + .message() + .body(body) + .header("X-SAMPLE-HEADER", sampleHeader) + .build() + .getMessageBuilder() + .build(new TestContext(), ""); + Assert.assertTrue(message instanceof HttpMessage); + HttpMessage httpMessage = (HttpMessage) message; + // test payload + Object payload = httpMessage.getPayload(); + Assert.assertEquals(payload, body); + // test header + Object header = httpMessage.getHeader("X-SAMPLE-HEADER"); + Assert.assertEquals(header, sampleHeader); + } + +} \ No newline at end of file diff --git a/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json new file mode 100644 index 0000000000..a3d3953ce1 --- /dev/null +++ b/connectors/citrus-openapi/src/test/resources/org/citrusframework/openapi/petstore/petstore-derivation-for-message-builder-test.json @@ -0,0 +1,164 @@ +{ + "openapi": "3.0.2", + "info": { + "title": "Swagger Petstore", + "version": "1.0.1", + "description": "This is a sample server Petstore server.", + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "servers": [ + { + "url": "http://localhost/petstore/v3" + } + ], + "paths": { + "/pet": { + "post": { + "requestBody": { + "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" + } + } + }, + "required": true + }, + "parameters": [ + { + "name": "X-SAMPLE-HEADER", + "required": true, + "in": "header", + "schema": { + "type": "string" + } + }, + { + "name": "sample-param", + "required": true, + "in": "query", + "schema": { + "type": "string" + } + } + ], + "tags": [ + "pet" + ], + "responses": { + "201": { + "description": "Created" + }, + "405": { + "description": "Invalid input" + } + }, + "operationId": "addPet", + "summary": "Add a new pet to the store", + "description": "" + } + } + }, + "components": { + "schemas": { + "Category": { + "type": "object", + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Category" + } + }, + "Tag": { + "type": "object", + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "name": { + "type": "string" + } + }, + "xml": { + "name": "Tag" + } + }, + "Pet": { + "required": [ + "category", + "name", + "status" + ], + "type": "object", + "properties": { + "id": { + "format": "int64", + "type": "integer" + }, + "category": { + "$ref": "#/components/schemas/Category" + }, + "name": { + "type": "string", + "example": "doggie" + }, + "photoUrls": { + "type": "array", + "items": { + "type": "string" + }, + "xml": { + "name": "photoUrl", + "wrapped": true + } + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Tag" + }, + "xml": { + "name": "tag", + "wrapped": true + } + }, + "status": { + "description": "pet status in the store", + "enum": [ + "available", + "pending", + "sold" + ], + "type": "string" + } + }, + "xml": { + "name": "Pet" + } + } + } + }, + "tags": [ + { + "name": "pet", + "description": "Everything about your Pets" + } + ] +}