Skip to content

Commit

Permalink
feat(citrusframework#1156): provide test api generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorsten Schlathoelter authored and Sterchi Daniel committed Jul 17, 2024
1 parent 85dbe5d commit 754115c
Show file tree
Hide file tree
Showing 37 changed files with 5,202 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ public void processOpts() {
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);

Expand Down Expand Up @@ -229,14 +228,11 @@ public void processOpts() {
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";
Expand All @@ -248,7 +244,6 @@ public void processOpts() {
} else if (API_TYPE_SOAP.equals(apiType)) {
addSoapSupportingFiles(citrusFolder, schemaFolder);
} else {
throw new IllegalArgumentException(format("Unknown API_TYPE: '%s'", apiType));
}

addDefaultSupportingFiles(citrusFolder, extensionFolder, springFolder);
Expand All @@ -264,12 +259,67 @@ public void preprocessOpenAPI(OpenAPI openAPI) {
additionalProperties.putAll(extensions);

Map<String, Object> infoExtensions = extensions.entrySet().stream()
.filter(entry -> entry.getKey().toUpperCase().startsWith("X-"))
.collect(toMap(Entry::getKey, Entry::getValue));
additionalProperties.put("infoExtensions", infoExtensions);
}
}

public void setApiPrefix(String apiPrefix) {
this.apiPrefix = apiPrefix;
}

public String getHttpClient() {
return httpClient;
}

public void setHttpClient(String httpClient) {
this.httpClient = httpClient;
}

public String getHttpPathPrefix() {
return httpPathPrefix;
}

public void setHttpPathPrefix(String httpPathPrefix) {
this.httpPathPrefix = httpPathPrefix;
}

public String getOpenapiSchema() {
return openapiSchema;
}

public void setOpenapiSchema(String openapiSchema) {
this.openapiSchema = openapiSchema;
}

public String getResourceFolder() {
return resourceFolder;
}

public void setResourceFolder(String resourceFolder) {
this.resourceFolder = resourceFolder;
}

public String getGeneratedSchemaFolder() {
return generatedSchemaFolder;
}

public void setGeneratedSchemaFolder(String generatedSchemaFolder) {
this.generatedSchemaFolder = generatedSchemaFolder;
}

public String getTargetXmlnsNamespace() {
return targetXmlnsNamespace;
}

public void setTargetXmlnsNamespace(String targetXmlnsNamespace) {
this.targetXmlnsNamespace = targetXmlnsNamespace;
}

public String getApiPrefix() {
return apiPrefix;
}

private void addRestSupportingFiles(final String citrusFolder, String schemaFolder) {
supportingFiles.add(new SupportingFile("schema.mustache", schemaFolder, apiPrefix.toLowerCase() + "-api.xsd"));
supportingFiles.add(new SupportingFile("test_base.mustache", citrusFolder, apiPrefix + ABSTRACT_TEST_REQUEST_JAVA));
Expand All @@ -291,4 +341,5 @@ private void addDefaultSupportingFiles(final String citrusFolder, final String e
supportingFiles.add(new SupportingFile("namespace_handler.mustache", extensionFolder, apiPrefix + "NamespaceHandler.java"));
supportingFiles.add(new SupportingFile("api-model.mustache", resourceFolder, apiPrefix.toLowerCase() + "-api-model.csv"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public String transformToOpenApi() throws WsdlToOpenApiTransformationException {

/**
* Performs the actual transformation from bindings into OpenApi operations.
*
* @param bindings
* @return
*/
private OpenAPI transformToOpenApi(Map<?, ?> bindings) {
OpenAPI openAPI = new OpenAPI();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

package {{package}};

import jakarta.annotation.Generated;
import org.citrusframework.testapi.GeneratedApi;
import org.citrusframework.testapi.GeneratedApiRequest;
import jakarta.servlet.http.Cookie;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// not in use
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# not in use
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package org.citrusframework.openapi.generator;

import static org.assertj.core.api.Assertions.assertThat;
import static org.citrusframework.container.Assert.Builder.assertException;
import static org.citrusframework.util.FileUtils.readToString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.citrusframework.TestCaseRunner;
import org.citrusframework.annotations.CitrusResource;
import org.citrusframework.annotations.CitrusTest;
import org.citrusframework.config.CitrusSpringConfig;
import org.citrusframework.context.TestContext;
import org.citrusframework.endpoint.EndpointConfiguration;
import org.citrusframework.http.client.HttpClient;
import org.citrusframework.http.client.HttpEndpointConfiguration;
import org.citrusframework.junit.jupiter.spring.CitrusSpringExtension;
import org.citrusframework.message.DefaultMessage;
import org.citrusframework.message.Message;
import org.citrusframework.messaging.Producer;
import org.citrusframework.messaging.SelectiveConsumer;
import org.citrusframework.openapi.generator.GetPetByIdTest.Config;
import org.citrusframework.openapi.generator.rest.petstore.request.PetApi.GetPetByIdRequest;
import org.citrusframework.openapi.generator.rest.petstore.spring.PetStoreBeanConfiguration;
import org.citrusframework.spi.Resources;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;

@ExtendWith(CitrusSpringExtension.class)
@SpringBootTest(classes = {PetStoreBeanConfiguration.class, CitrusSpringConfig.class, Config.class})
class GetPetByIdTest {

@Autowired
private GetPetByIdRequest getPetByIdRequest;

@Autowired
@Qualifier("petStoreEndpoint")
private HttpClient httpClient;

private String defaultResponse;

@BeforeEach
public void beforeTest() throws IOException {
defaultResponse = readToString(Resources.create(
"org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json"),
StandardCharsets.UTF_8) ;

mockProducer();
mockConsumer();
}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void testByJsonPath(@CitrusResource TestCaseRunner runner) {

// Given
getPetByIdRequest.setPetId("1234");

// Then
getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());

// Assert body by json path
getPetByIdRequest.setResponseValue(Map.of("$.name", "Snoopy"));

// When
runner.$(getPetByIdRequest);
}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void testValidationFailureByJsonPath(@CitrusResource TestCaseRunner runner) {

// Given
getPetByIdRequest.setPetId("1234");

// Then
getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());

// Assert body by json path
getPetByIdRequest.setResponseValue(Map.of("$.name", "Garfield"));

// When
runner.$(assertException()
.exception(org.citrusframework.exceptions.CitrusRuntimeException.class)
.message("Values not equal for element '$.name', expected 'Garfield' but was 'Snoopy'")
.when(
getPetByIdRequest
)
);
// When

}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void testByResource(@CitrusResource TestCaseRunner runner) {

// Given
getPetByIdRequest.setPetId("1234");

// Then
getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());
// Assert body by resource
getPetByIdRequest.setResource(
"org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage1.json");

// When
runner.$(getPetByIdRequest);
}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void testValidationFailureByResource(@CitrusResource TestCaseRunner runner) {

// Given
getPetByIdRequest.setPetId("1234");

// Then
getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());
// Assert body by resource
getPetByIdRequest.setResource(
"org/citrusframework/openapi/generator/GeneratedApiTest/payloads/getPetByIdControlMessage2.json");

// When
runner.$(assertException()
.exception(org.citrusframework.exceptions.CitrusRuntimeException.class)
.message("Values not equal for entry: '$['name']', expected 'Garfield' but was 'Snoopy'")
.when(
getPetByIdRequest
)
);
}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void validateByVariable(@CitrusResource TestContext testContext,
@CitrusResource TestCaseRunner runner) {

// Given
getPetByIdRequest.setPetId("1234");

// Then
getPetByIdRequest.setResponseStatus(HttpStatus.OK.value());
getPetByIdRequest.setResponseReasonPhrase(HttpStatus.OK.getReasonPhrase());

// Assert load data into variables
getPetByIdRequest.setResponseVariable(Map.of("$", "RESPONSE", "$.id", "ID"));

// When
runner.$(getPetByIdRequest);

// Then
assertThat(testContext)
.satisfies(
c -> assertThat(c.getVariable("RESPONSE"))
.isNotNull(),
c -> assertThat(c.getVariable("ID"))
.isNotNull()
.isEqualTo("12")
);
}

/**
* TODO #1161 - Improve with builder pattern
*/
@Test
@CitrusTest
void validateReceivedResponse(@CitrusResource TestContext testContext) {

// Given
getPetByIdRequest.setPetId("1234");

// When
getPetByIdRequest.sendRequest(testContext);

// Then
Message receiveResponse = getPetByIdRequest.receiveResponse(testContext);
assertThat(receiveResponse)
.isNotNull()
.extracting(Message::getPayload)
.asString()
.isEqualToIgnoringWhitespace(defaultResponse);
assertThat(receiveResponse.getHeaders())
.containsEntry("citrus_http_status_code", 200)
.containsEntry("citrus_http_reason_phrase", "OK");
}

private void mockProducer() {
Producer producerMock = mock();
when(httpClient.createProducer()).thenReturn(producerMock);
}

private void mockConsumer() {
Message receiveMessage = createReceiveMessage();

SelectiveConsumer consumer = mock(SelectiveConsumer.class);
when(httpClient.createConsumer()).thenReturn(consumer);
when(consumer.receive(any(), eq(5000L))).thenReturn(receiveMessage);
}

private Message createReceiveMessage() {
Message receiveMessage = new DefaultMessage();
receiveMessage.setPayload(defaultResponse);
receiveMessage.getHeaders().put("citrus_http_reason_phrase", "OK");
receiveMessage.getHeaders().put("citrus_http_version", "HTTP/1.1");
receiveMessage.getHeaders().put("Content-Type", 200);
receiveMessage.getHeaders().put("citrus_http_status_code", 200);
return receiveMessage;
}

@TestConfiguration
public static class Config {

@Bean(name = {"applicationServiceClient", "petStoreEndpoint"})
public HttpClient applicationServiceClient() {
HttpClient client = mock(HttpClient.class);
EndpointConfiguration endpointConfiguration = mock(EndpointConfiguration.class);
when(client.getEndpointConfiguration()).thenReturn(new HttpEndpointConfiguration());
when(endpointConfiguration.getTimeout()).thenReturn(5000L);
return client;
}
}
}
Loading

0 comments on commit 754115c

Please sign in to comment.