Skip to content

Commit

Permalink
feat(#1156): provide test api generator
Browse files Browse the repository at this point in the history
  • Loading branch information
Thorsten Schlathoelter authored and bbortt committed Dec 9, 2024
1 parent e25f59d commit 0de512a
Show file tree
Hide file tree
Showing 115 changed files with 12,632 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,38 @@ public static String prettyPrintJson(String payload) {
}
return sb.toString();
}

/**
* Normalizes the given text by replacing all whitespace characters (identified by {@link Character#isWhitespace) by a single space
* and replacing windows style line endings with unix style line endings.
*/
public static String normalizeWhitespace(String text, boolean normalizeWhitespace, boolean normalizeLineEndingsToUnix) {
if (text == null || text.isEmpty()) {
return text;
}

if (normalizeWhitespace) {
StringBuilder result = new StringBuilder();
boolean lastWasSpace = true;
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (Character.isWhitespace(c)) {
if (!lastWasSpace) {
result.append(' ');
}
lastWasSpace = true;
} else {
result.append(c);
lastWasSpace = false;
}
}
return result.toString().trim();
}

if (normalizeLineEndingsToUnix) {
return text.replaceAll("\\r(\\n)?", "\n");
}

return text;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.citrusframework.testapi;

import java.util.Map;

/**
* Interface representing a generated API from an OpenAPI specification.
* Provides methods to retrieve metadata about the API such as title, version,
* prefix, and information extensions.
*/
public interface GeneratedApi {

/**
* Retrieves the title of the OpenAPI specification, as specified in the info section of the API.
*
* @return the title of the OpenAPI specification
*/
String getApiTitle();

/**
* Retrieves the version of the OpenAPI specification, as specified in the info section of the API.
*
* @return the version of the OpenAPI specification
*/
String getApiVersion();

/**
* Retrieves the prefix used for the API, as specified in the API generation configuration.
*
* @return the prefix used for the API
*/
String getApiPrefix();

/**
* Retrieves the specification extensions of the OpenAPI defined in the "info" section.
* <p>
* Specification extensions, also known as vendor extensions, are custom key-value pairs used to describe extra
* functionality not covered by the standard OpenAPI Specification. These properties start with "x-".
* This method collects only the extensions defined in the "info" section of the API.
* </p>
*
* @return a map containing the specification extensions defined in the "info" section of the API,
* where keys are extension names and values are extension values
*/
Map<String, String> getApiInfoExtensions();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.citrusframework.testapi;

/**
* Interface representing a generated API request corresponding to an operation in an OpenAPI specification.
* Provides methods to retrieve metadata about the request such as operation name, HTTP method, and path.
*/
public interface GeneratedApiRequest {

/**
* Retrieves the name of the OpenAPI operation associated with the request.
*
* @return the name of the OpenAPI operation
*/
String getOperationName();

/**
* Retrieves the HTTP method used for the request.
*
* @return the HTTP method used for the request (e.g., GET, POST)
*/
String getMethod();

/**
* Retrieves the path used for the request.
*
* @return the path used for the request
*/
String getPath();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,56 +16,79 @@

package org.citrusframework.message;

import static org.testng.Assert.assertEquals;

import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class MessagePayloadUtilsTest {

@Test
public void shouldPrettyPrintJson() {
Assert.assertEquals(MessagePayloadUtils.prettyPrint(""), "");
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{}"), "{}");
Assert.assertEquals(MessagePayloadUtils.prettyPrint("[]"), "[]");
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\"}"),
assertEquals(MessagePayloadUtils.prettyPrint(""), "");
assertEquals(MessagePayloadUtils.prettyPrint("{}"), "{}");
assertEquals(MessagePayloadUtils.prettyPrint("[]"), "[]");
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\"}"),
String.format("{%n \"user\": \"citrus\"%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"text\":\"<?;,{}' '[]:>\"}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"text\":\"<?;,{}' '[]:>\"}"),
String.format("{%n \"text\": \"<?;,{}' '[]:>\"%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n { \"user\":%n%n \"citrus\" }")),
assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n { \"user\":%n%n \"citrus\" }")),
String.format("{%n \"user\": \"citrus\"%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32}"),
String.format("{%n \"user\": \"citrus\",%n \"age\": 32%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("[22, 32]"),
assertEquals(MessagePayloadUtils.prettyPrint("[22, 32]"),
String.format("[%n22,%n32%n]"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}]"),
assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}]"),
String.format("[%n {%n \"user\": \"citrus\",%n \"age\": 32%n }%n]"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}, {\"user\":\"foo\",\"age\": 99}]"),
assertEquals(MessagePayloadUtils.prettyPrint("[{\"user\":\"citrus\",\"age\": 32}, {\"user\":\"foo\",\"age\": 99}]"),
String.format("[%n {%n \"user\": \"citrus\",%n \"age\": 32%n },%n {%n \"user\": \"foo\",%n \"age\": 99%n }%n]"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pet\":{\"name\": \"fluffy\", \"age\": 4}}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pet\":{\"name\": \"fluffy\", \"age\": 4}}"),
String.format("{%n \"user\": \"citrus\",%n \"age\": 32,%n \"pet\": {%n \"name\": \"fluffy\",%n \"age\": 4%n }%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pets\":[\"fluffy\",\"hasso\"]}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"age\": 32,\"pets\":[\"fluffy\",\"hasso\"]}"),
String.format("{%n \"user\": \"citrus\",%n \"age\": 32,%n \"pets\": [%n \"fluffy\",%n \"hasso\"%n ]%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[\"fluffy\",\"hasso\"],\"age\": 32}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[\"fluffy\",\"hasso\"],\"age\": 32}"),
String.format("{%n \"user\": \"citrus\",%n \"pets\": [%n \"fluffy\",%n \"hasso\"%n ],%n \"age\": 32%n}"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[{\"name\": \"fluffy\", \"age\": 4},{\"name\": \"hasso\", \"age\": 2}],\"age\": 32}"),
assertEquals(MessagePayloadUtils.prettyPrint("{\"user\":\"citrus\",\"pets\":[{\"name\": \"fluffy\", \"age\": 4},{\"name\": \"hasso\", \"age\": 2}],\"age\": 32}"),
String.format("{%n \"user\": \"citrus\",%n \"pets\": [%n {%n \"name\": \"fluffy\",%n \"age\": 4%n },%n {%n \"name\": \"hasso\",%n \"age\": 2%n }%n ],%n \"age\": 32%n}"));
}

@Test
public void shouldPrettyPrintXml() {
Assert.assertEquals(MessagePayloadUtils.prettyPrint(""), "");
Assert.assertEquals(MessagePayloadUtils.prettyPrint("<root></root>"),
assertEquals(MessagePayloadUtils.prettyPrint(""), "");
assertEquals(MessagePayloadUtils.prettyPrint("<root></root>"),
String.format("<root>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("<root><text>Citrus rocks!</text></root>"),
assertEquals(MessagePayloadUtils.prettyPrint("<root><text>Citrus rocks!</text></root>"),
String.format("<root>%n <text>Citrus rocks!</text>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><text>Citrus rocks!</text></root>"),
assertEquals(MessagePayloadUtils.prettyPrint("<?xml version=\"1.0\" encoding=\"UTF-8\"?><root><text>Citrus rocks!</text></root>"),
String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n<root>%n <text>Citrus rocks!</text>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root>%n<text>%nCitrus rocks!%n</text>%n</root>")),
assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root>%n<text>%nCitrus rocks!%n</text>%n</root>")),
String.format("<root>%n <text>Citrus rocks!</text>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root>%n <text language=\"eng\">%nCitrus rocks!%n </text>%n</root>")),
assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root>%n <text language=\"eng\">%nCitrus rocks!%n </text>%n</root>")),
String.format("<root>%n <text language=\"eng\">Citrus rocks!</text>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n <root><text language=\"eng\"><![CDATA[Citrus rocks!]]></text></root>")),
assertEquals(MessagePayloadUtils.prettyPrint(String.format("%n%n <root><text language=\"eng\"><![CDATA[Citrus rocks!]]></text></root>")),
String.format("<root>%n <text language=\"eng\">%n <![CDATA[Citrus rocks!]]>%n </text>%n</root>%n"));
Assert.assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root><text language=\"eng\" important=\"true\"><![CDATA[%n Citrus rocks!%n ]]></text></root>")),
assertEquals(MessagePayloadUtils.prettyPrint(String.format("<root><text language=\"eng\" important=\"true\"><![CDATA[%n Citrus rocks!%n ]]></text></root>")),
String.format("<root>%n <text language=\"eng\" important=\"true\">%n <![CDATA[%n Citrus rocks!%n ]]>%n </text>%n</root>%n"));
}

@DataProvider
public Object[][] normalizeWhitespaceProvider() {
return new Object[][] {
// Test data: payload, ignoreWhitespace, ignoreNewLineType, expected result
{"Hello \t\r\nWorld\r\n", true, true, "Hello World"},
{"Hello \t\r\nWorld\r\n", true, false, "Hello World"},
{"Hello \t\r\nWorld\r\n", false, true, "Hello \t\nWorld\n"},
{"Hello \t\r\nWorld\r\n", false, false, "Hello \t\r\nWorld\r\n"},
{"", true, true, ""},
{"", false, false, ""},
{null, true, true, null},
{null, false, false, null}
};
}

@Test(dataProvider = "normalizeWhitespaceProvider")
public void normalizeWhitespace(String text, boolean normalizeWhitespace, boolean normalizeLineEndingsToUnix, String expected) {
assertEquals(MessagePayloadUtils.normalizeWhitespace(text, normalizeWhitespace, normalizeLineEndingsToUnix), expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.citrusframework.testapi;

import org.citrusframework.TestAction;
import org.citrusframework.actions.SendMessageAction.SendMessageActionBuilder;
import org.citrusframework.context.TestContext;

/**
* Implementors of this interface are used to customize the SendMessageActionBuilder with application specific information. E.g. cookies
* or transactionIds.
*/
public interface ApiActionBuilderCustomizerService {
<T extends SendMessageActionBuilder<?,?,?>> T build(GeneratedApi generatedApi, TestAction action, TestContext context, T builder);
}
20 changes: 20 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@
<maven.nexus-staging.plugin.version>1.6.13</maven.nexus-staging.plugin.version>
<maven.plugin.plugin.version>3.9.0</maven.plugin.plugin.version>
<maven.plugin.annotations.version>3.13.1</maven.plugin.annotations.version>
<maven.plugin.testing.harness.version>3.3.0</maven.plugin.testing.harness.version>
<maven.release.plugin.version>3.0.1</maven.release.plugin.version>
<maven.resource.plugin.version>3.3.1</maven.resource.plugin.version>
<maven.scm.plugin.version>1.11.2</maven.scm.plugin.version>
Expand Down Expand Up @@ -250,6 +251,7 @@
<mockftpserver.version>3.2.0</mockftpserver.version>
<netty.version>4.1.105.Final</netty.version>
<okhttp.version>4.12.0</okhttp.version>
<openapi-generator-maven-plugin>7.5.0</openapi-generator-maven-plugin>
<picoli-version>4.7.6</picoli-version>
<postgresql.version>42.7.4</postgresql.version>
<quarkus.platform.version>3.16.4</quarkus.platform.version>
Expand Down Expand Up @@ -523,6 +525,19 @@
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
</dependency>

<dependency>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator</artifactId>
<version>${openapi-generator-maven-plugin}</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
Expand Down Expand Up @@ -990,6 +1005,11 @@
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-jaxb-annotations</artifactId>
Expand Down
Loading

0 comments on commit 0de512a

Please sign in to comment.