This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 0e8cd2ced57 CAMEL-20943: camel-jbang - Add openapi generate
integration test (#14744)
0e8cd2ced57 is described below
commit 0e8cd2ced5769434fb2c3484597f1100e85d2082
Author: Marco Carletti <[email protected]>
AuthorDate: Fri Jul 5 16:42:12 2024 +0200
CAMEL-20943: camel-jbang - Add openapi generate integration test (#14744)
---
.../apache/camel/dsl/jbang/it/OpenApiITCase.java | 146 +++++++++++++++++++++
.../dsl/jbang/it/support/JBangTestSupport.java | 67 ++++++++++
2 files changed, 213 insertions(+)
diff --git
a/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/OpenApiITCase.java
b/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/OpenApiITCase.java
new file mode 100644
index 00000000000..a2ba0d2915b
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/OpenApiITCase.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.apache.camel.dsl.jbang.it;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.apache.camel.dsl.jbang.it.support.InVersion;
+import org.apache.camel.dsl.jbang.it.support.JBangTestSupport;
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+
+public class OpenApiITCase extends JBangTestSupport {
+
+ final HttpClient httpClient = HttpClient.newHttpClient();
+
+ @Test
+ public void runOpenApiOnExistingImplementation() {
+ final String openApiImpl
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api/Greetings.java";
+ final String openApiUrl
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api/greetings-api.json";
+
+ downloadFile(openApiImpl);
+ downloadFile(openApiUrl);
+ executeBackground("run --open-api greetings-api.json Greetings.java");
+ checkLogContains("HTTP endpoints summary");
+ HttpResponse<String> response =
executeHttpRequest("/camel/greetings/jack", false);
+ Assertions.assertThat(response.statusCode()).isEqualTo(200);
+ Assertions.assertThat(response.body()).isEqualTo("Hello from jack");
+ }
+
+ @Test
+ public void runOpenApiUsingContractFirstApproach() throws IOException {
+ final String openApiUrl
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api-contract-first/petstore-v3.json";
+ final String openApiConfig
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api-contract-first/petstore.camel.yaml";
+
+ downloadFile(openApiUrl);
+ downloadFile(openApiConfig);
+ containerService.executeGenericCommand("mkdir -p camel-mock/pet");
+ downloadFile(
+
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api-contract-first/camel-mock/pet/123.json");
+ containerService.executeGenericCommand("mv 123.json camel-mock/pet/");
+ executeBackground("run petstore-v3.json petstore.camel.yaml");
+ checkLogContains("HTTP endpoints summary");
+
+ //verify mock
+ HttpResponse<String> response = executeHttpRequest("/api/v3/pet/123",
true);
+ Assertions.assertThat(response.statusCode()).isEqualTo(200);
+ Assertions.assertThat(response.body()).contains("donald the dock");
+
+ //verify sample response
+ response = executeHttpRequest("/api/v3/pet/" + new
Random().nextInt(124, 500), true);
+ Assertions.assertThat(response.statusCode()).isEqualTo(200);
+ Assertions.assertThat(response.body()).contains("jack the cat");
+
+ //verify api-doc
+ response = executeHttpRequest("/api-doc", true);
+ Assertions.assertThat(response.statusCode()).isEqualTo(200);
+ final ObjectMapper objectMapper = new ObjectMapper();
+ Map expectedDoc = objectMapper.readValue(new URL(
+ openApiUrl),
+ Map.class);
+ Map actualDoc = objectMapper.readValue(response.body(), Map.class);
+ Assertions.assertThat(((Map) actualDoc.get("paths")).size())
+ .as("check api doc exposed paths size")
+ .isEqualTo(((Map) expectedDoc.get("paths")).size());
+ }
+
+ @Test
+ public void exportOpenApiUsingContractFirstApproach() {
+ final String openApiUrl
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api-contract-first/petstore-v3.json";
+
+ downloadFile(openApiUrl);
+ final String generatedPath = mountPoint() + "/petstore";
+ generateProperties(Map.of("camel.jbang.runtime", "spring-boot",
"camel.jbang.gav", "example:petstore:1.0-SNAPSHOT",
+ "camel.jbang.exportDir", generatedPath, "camel.jbang.open-api",
+ DEFAULT_ROUTE_FOLDER + "/petstore-v3.json"));
+ execute("export");
+ assertFileInDataFolderExists("petstore");
+
assertFileInDataFolderExists("petstore/src/main/resources/petstore-v3.json");
+
assertFileInDataFolderExists("petstore/src/main/resources/camel/generated-openapi.yaml");
+ }
+
+ @Test
+ @InVersion(from = "4.7.00")
+ public void generateOpenApiWithDtoUsingContractFirstApproach() {
+ final String openApiUrl
+ =
"https://raw.githubusercontent.com/apache/camel-kamelets-examples/main/jbang/open-api-contract-first/petstore-v3.json";
+
+ downloadFile(openApiUrl);
+
+ execute("plugin add generate");
+ execute("plugin get");
+ execute("generate rest --dto --input=petstore-v3.json
--output=rest-dsl.yaml --runtime=spring-boot --routes");
+ List<String> generatedDTO =
containerService.listDirectory(DEFAULT_ROUTE_FOLDER + "/model").toList();
+ Assertions.assertThat(generatedDTO).as("check generated DTO
number").hasSize(8);
+ assertFileInContainerExists(DEFAULT_ROUTE_FOLDER + "/rest-dsl.yaml");
+ }
+
+ private HttpResponse<String> executeHttpRequest(final String ctxUrl,
boolean acceptJson) {
+ try {
+ final HttpRequest.Builder builder = HttpRequest
+ .newBuilder(
+ new URI(String.format("http://localhost:%s%s",
containerService.getDevConsolePort(), ctxUrl)))
+ .timeout(Duration.ofSeconds(5))
+ .GET();
+ if (acceptJson) {
+ builder.headers("Accept", "application/json");
+ }
+ return httpClient.send(builder
+ .build(),
+ HttpResponse.BodyHandlers.ofString());
+ } catch (IOException | InterruptedException | URISyntaxException e) {
+ Assertions.fail("unable to execute the request");
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/support/JBangTestSupport.java
b/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/support/JBangTestSupport.java
index 11b5d9e048e..6e6f0164426 100644
---
a/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/support/JBangTestSupport.java
+++
b/dsl/camel-jbang/camel-jbang-it/src/test/java/org/apache/camel/dsl/jbang/it/support/JBangTestSupport.java
@@ -20,6 +20,13 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -28,7 +35,9 @@ import java.nio.file.StandardCopyOption;
import java.nio.file.attribute.PosixFilePermission;
import java.time.Duration;
import java.util.EnumSet;
+import java.util.Map;
import java.util.Optional;
+import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.camel.test.infra.cli.common.CliProperties;
@@ -254,4 +263,62 @@ public abstract class JBangTestSupport {
protected String makeTheFileWriteable(String containerPath) {
return containerService.executeGenericCommand("chmod 777 " +
containerPath);
}
+
+ protected String downloadNewFileInDataFolder(String downloadUrl) {
+ try {
+ return this.downloadNewFileInDataFolder(new URL(downloadUrl),
null);
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected String downloadNewFileInDataFolder(URL downloadUrl, String
fileName) {
+ final String fName = fileName == null ?
Paths.get(downloadUrl.getPath().toString()).getFileName().toString() : fileName;
+
+ final StringWriter sw = new StringWriter();
+ try (ReadableByteChannel channel =
Channels.newChannel(downloadUrl.openStream());
+ Reader reader = Channels.newReader(channel,
Charset.defaultCharset())) {
+ reader.transferTo(sw);
+ sw.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ this.newFileInDataFolder(fName, sw.toString());
+ return fName;
+ }
+
+ protected String downloadFile(String downloadUrl) {
+ String fileName = this.downloadNewFileInDataFolder(downloadUrl);
+ containerService.copyFileInternally(mountPoint() + "/" + fileName,
DEFAULT_ROUTE_FOLDER);
+ return fileName;
+ }
+
+ protected void generateProperties(Map<String, String> properties) {
+ this.generateProperties("application.properties", properties, false);
+ }
+
+ protected void generateProperties(String fileName, Map<String, String>
properties, boolean inDataFolder) {
+ final Properties prop = new Properties();
+ prop.putAll(properties);
+ final StringWriter contentWriter = new StringWriter();
+ try {
+ prop.store(contentWriter, "");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ this.newFileInDataFolder(fileName, contentWriter.toString());
+ if (!inDataFolder) {
+ containerService.executeGenericCommand(
+ String.format("mv %s/%s %s/%s", mountPoint(), fileName,
DEFAULT_ROUTE_FOLDER, fileName));
+ }
+ }
+
+ protected void assertFileInContainerExists(String fileAbsolutePath) {
+ String fileName =
Path.of(fileAbsolutePath).getFileName().toFile().getName();
+
Assertions.assertThat(containerService.listDirectory(Path.of(fileAbsolutePath).getParent().toAbsolutePath().toString())
+ .anyMatch(child -> fileName.equals(child)))
+ .as("check if file " + fileAbsolutePath + " exists")
+ .isTrue();
+ }
+
}