Add config files for samples, update services declarations, add test resources and code, add Helidon client and server sample profiles to pom

Signed-off-by: tim.quinn@oracle.com <tim.quinn@oracle.com>
This commit is contained in:
tim.quinn@oracle.com 2022-09-23 17:11:16 -05:00
parent 1e029ae935
commit 638c5201c4
20 changed files with 3395 additions and 0 deletions

View File

@ -0,0 +1,12 @@
generatorName: java-helidon-client
library: mp
outputDir: samples/client/petstore/java-helidon-client/mp
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
additionalProperties:
artifactId: petstore-helidon-client-mp
hideGenerationTimestamp: "true"
configureAuth: "false"
build: "all"
test: "spock"
requiredPropertiesInConstructor: "false"
visitable: "true"

View File

@ -0,0 +1,12 @@
generatorName: java-helidon-client
library: se
outputDir: samples/client/petstore/java-helidon-client/se
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
additionalProperties:
artifactId: petstore-helidon-client-se
hideGenerationTimestamp: "true"
configureAuth: "false"
build: "all"
test: "spock"
requiredPropertiesInConstructor: "false"
visitable: "true"

View File

@ -0,0 +1,11 @@
generatorName: java-helidon-server
library: mp
outputDir: samples/server/petstore/java-helidon-server/mp
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/java-helidon/server
additionalProperties:
artifactId: petstore-helidon-server-mp
hideGenerationTimestamp: "true"
build: "all"
test: "spock"
useAuth: "false"

View File

@ -0,0 +1,8 @@
generatorName: java-helidon-server
library: se
outputDir: samples/server/petstore/java-helidon-server/se
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml
templateDir: modules/openapi-generator/src/main/resources/java-helidon/server
additionalProperties:
artifactId: petstore-helidon-server-se
hideGenerationTimestamp: "true"

View File

@ -51,6 +51,8 @@ org.openapitools.codegen.languages.HaskellServantCodegen
org.openapitools.codegen.languages.HaskellYesodServerCodegen
org.openapitools.codegen.languages.JavaClientCodegen
org.openapitools.codegen.languages.JavaCXFClientCodegen
org.openapitools.codegen.languages.JavaHelidonClientCodegen
org.openapitools.codegen.languages.JavaHelidonServerCodegen
org.openapitools.codegen.languages.JavaInflectorServerCodegen
org.openapitools.codegen.languages.JavaMicronautClientCodegen
org.openapitools.codegen.languages.JavaMicronautServerCodegen

View File

@ -0,0 +1,206 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
*
* 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.openapitools.codegen.java.helidon;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class JavaHelidonCommonCodegenPackagePrefixTest {
private static final String INPUT_FILE = "src/test/resources/3_0/helidon/petstore-for-testing.yaml";
private static final String PACKAGE_PREFIX_KEY = "rootJavaEEPackage";
private static final String HELIDON_VERSION_KEY = "helidonVersion";
private static final String EXCEPTION_MESSAGE_FRAGMENT = "namespace but options specified";
// The generated SE client does not depend on the jakarta/javax imports, so no need to test it.
private static final List<List<String>> GENERATOR_LIBRARY_PAIRS = new ArrayList<List<String>>() {
{
add(listOf("java-helidon-client", "mp"));
add(listOf("java-helidon-server", "se"));
add(listOf("java-helidon-server", "mp"));
}
};
private String outputDir;
@BeforeMethod
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputDir = output.getAbsolutePath().replace('\\', '/');
}
@Test(dataProvider = "valid")
public void checkValidCombinations(String explicitHelidonVersion,
String explicitPrefix,
String expectedPrefix,
String generatorName,
String libraryName) {
List<File> files = runTest(explicitHelidonVersion, explicitPrefix, generatorName, libraryName);
checkFileForPackagePrefix(files, generatorName, libraryName, expectedPrefix);
}
@Test(dataProvider = "invalid")
public void checkInvalidCombinations(String explicitHelidonVersion,
String explicitPrefix,
String generatorName,
String libraryName) {
IllegalArgumentException e = Assert.assertThrows(IllegalArgumentException.class,
() -> runTest(explicitHelidonVersion, explicitPrefix, generatorName, libraryName));
Assert.assertTrue("Exception message '" + e.getMessage() + "' contains '" + EXCEPTION_MESSAGE_FRAGMENT + "'",
e.getMessage().contains(EXCEPTION_MESSAGE_FRAGMENT));
}
@DataProvider(name = "valid")
public Object [][] createValidData() {
Object [][] settingsForEachRun = new Object[][] {
{null, null, "jakarta"},
{"3.0.1", null, "jakarta"},
{"2.5.3", null, "javax"},
{null, "jakarta", "jakarta"},
{"3.0.1", "jakarta", "jakarta"},
{"2.5.3", "javax", "javax"}
};
return prepareTestData(settingsForEachRun);
}
@DataProvider(name = "invalid")
public Object [][] createInvalidData() {
Object [][] settingsForEachRun = new Object[][] {
{"2.5.3", "jakarta"},
{null, "javax"},
{"3.0.1", "javax"}
};
return prepareTestData(settingsForEachRun);
}
/**
* Creates test data for each tested generator/library pair for all the version/prefix settings.
*
* @param settingsForEachRun version/prefix settings to test
* @return test data for driving a test method
*/
private Object[][] prepareTestData(Object[][] settingsForEachRun) {
Object [][] result = new Object[GENERATOR_LIBRARY_PAIRS.size() * settingsForEachRun.length][];
int resultSlot = 0;
int settingsLength = settingsForEachRun[0].length;
for (List<String> generatorLibraryPair : GENERATOR_LIBRARY_PAIRS) {
for (Object[] settings : settingsForEachRun) {
result[resultSlot] = Arrays.copyOf(settings, settingsLength + 2);
result[resultSlot][settingsLength] = generatorLibraryPair.get(0); // generator
result[resultSlot][settingsLength + 1] = generatorLibraryPair.get(1); // library
resultSlot++;
}
}
return result;
}
private static List<String> listOf(String... values) {
return new ArrayList<>(Arrays.asList(values));
}
private List<File> runTest(String explicitHelidonVersion,
String explicitPackagePrefix,
String generatorName,
String libraryName) {
Map<String, Object> additionalProperties = new HashMap<>();
CodegenConfigurator clientConfigurator = new CodegenConfigurator()
.setGeneratorName(generatorName)
.setLibrary(libraryName)
.setInputSpec(INPUT_FILE)
.setOutputDir(outputDir);
if (explicitHelidonVersion != null) {
additionalProperties.put(HELIDON_VERSION_KEY, explicitHelidonVersion);
}
if (explicitPackagePrefix != null) {
additionalProperties.put(PACKAGE_PREFIX_KEY, explicitPackagePrefix);
}
// Use JSON-B for serialization to force jakarta or json imports into the generated POJOs.
additionalProperties.put(CodegenConstants.SERIALIZATION_LIBRARY, "jsonb");
clientConfigurator.setAdditionalProperties(additionalProperties);
DefaultGenerator generator = new DefaultGenerator();
generator.opts(clientConfigurator.toClientOptInput());
return generator.generate();
}
private void checkFileForPackagePrefix(List<File> files,
String generatorName,
String libraryName,
String expectedPrefix) {
// The SE client does not use the rootJavaEEPackage so we don't check any file in that case.
if (generatorName.equals("java-helidon-client") && libraryName.equals("se")) {
return;
}
// The MP client and server generator create PetAPI containing a wildcard include.
if (libraryName.equals("mp")) {
TestUtils.ensureContainsFile(files, Paths.get(outputDir).toFile(), generatedFilePath(generatorName, libraryName));
TestUtils.assertFileContains(Paths.get(outputDir + "/" + generatedFilePath(generatorName, libraryName)),
"import " + expectedPrefix + ".ws.rs.*;");
return;
}
// The SE server generates 'import {{rootJavaEEPackage}}.json.stream.JsonParser;' in POJOs for JSON-B seriolization.
TestUtils.ensureContainsFile(files, Paths.get(outputDir).toFile(), generatedFilePath(generatorName, libraryName));
TestUtils.assertFileContains(Paths.get(outputDir + "/" + generatedFilePath(generatorName, libraryName)),
"import " + expectedPrefix + ".json.stream.JsonParser;");
}
private String generatedFilePath(String generatorName, String libraryName) {
// The path to the file depends on client or server.
String serverOrClient = (generatorName.contains("server") ? "server" : "client");
// The file to check depends on the generator: e.g., PetApi for client, PetService for server.
String apiFileNameSuffix = (generatorName.contains("server") ? "Service" : "Api");
// For MP, check api/PetApi or api/PetService; for SE check model/Pet.java.
String filePath = (libraryName.equals("mp")
? "api/Pet" + apiFileNameSuffix
: "model/Pet")
+ ".java";
return "src/main/java/org/openapitools/"
+ serverOrClient
+ "/"
+ filePath;
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.junit.Assert;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class JavaHelidonCommonCodegenTest {
private DefaultGenerator generator;
private CodegenConfigurator configurator;
private String outputDir;
@BeforeMethod
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputDir = output.getAbsolutePath().replace('\\', '/');
configurator = new CodegenConfigurator()
.setGeneratorName("java-helidon-server")
.setLibrary("mp")
.setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
.setOutputDir(outputDir);
generator = new DefaultGenerator();
}
@Test
public void defaultVersionTest() {
runVersionTest(null, null);
}
@Test
public void customHelidonVersionOnlyTest() {
runVersionTest("3.0.0", null);
}
@Test
public void customParentVersionOnlyTest() {
runVersionTest(null, "3.0.0");
}
@Test
public void bothEqualsVersionTest() {
runVersionTest("3.0.0", "3.0.0");
}
@Test
public void bothNotEqualsVersionTest() {
IllegalArgumentException e = Assert.assertThrows(IllegalArgumentException.class,() -> runVersionTest("1.0.0", "2.0.0"));
Assert.assertEquals(
"Both parentVersion and helidonVersion properties were set with different value.",
e.getMessage());
}
private void runVersionTest(String helidonVersion, String parentVersion) {
Map<String, Object> additionalProperties = new HashMap<>();
String expected = "3.0.1";
if (parentVersion != null) {
additionalProperties.put(CodegenConstants.PARENT_VERSION, parentVersion);
expected = parentVersion;
}
if (helidonVersion != null) {
additionalProperties.put("helidonVersion", helidonVersion);
expected = helidonVersion;
}
generator.opts(configurator.setAdditionalProperties(additionalProperties)
.toClientOptInput());
List<File> files = generator.generate();
TestUtils.ensureContainsFile(files, Paths.get(outputDir).toFile(), "pom.xml");
TestUtils.assertFileContains(Paths.get(outputDir + "/pom.xml"),
String.format(Locale.ROOT, "<version>%s</version>", expected));
}
}

View File

@ -0,0 +1,97 @@
package org.openapitools.codegen.java.helidon;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.openapitools.codegen.java.assertions.JavaFileAssert.assertThat;
public class JavaHelidonMpClientCodegenTest {
private String outputPath;
private List<File> generatedFiles;
@BeforeClass
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputPath = output.getAbsolutePath().replace('\\', '/');
System.out.println("Generating java-helidon-client MP project in " + outputPath);
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("java-helidon-client")
.setLibrary("mp")
.setInputSpec("src/test/resources/3_0/helidon/petstore-no-multipart-for-testing.yaml")
.setOutputDir(outputPath);
final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator();
generator.opts(clientOptInput);
generatedFiles = generator.generate();
}
@Test
public void testPom() {
TestUtils.ensureContainsFile(generatedFiles, new File(outputPath), "pom.xml");
}
@Test
public void testPetApi() {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/PetApi.java"))
.assertMethod("addPet", "Pet")
.toFileAssert()
.assertMethod("deletePet", "Long", "String", "Long", "String", "Integer",
"List<Integer>", "List<String>")
.toFileAssert()
.assertMethod("findPetsByStatus", "List<String>")
.toFileAssert()
.assertMethod("findPetsByTags", "List<Integer>")
.toFileAssert()
.assertMethod("getPetById", "Long")
.toFileAssert()
.assertMethod("updatePet", "Pet")
.toFileAssert()
.assertMethod("updatePetWithForm", "Long", "String", "String")
.toFileAssert();
}
@Test
public void testStoreApi() {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/StoreApi.java"))
.assertMethod("deleteOrder", "String")
.toFileAssert()
.assertMethod("getInventory")
.toFileAssert()
.assertMethod("getOrderById", "BigDecimal")
.toFileAssert()
.assertMethod("placeOrder", "Order")
.toFileAssert();
}
@Test
public void testUserApi() {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/UserApi.java"))
.assertMethod("createUser", "User")
.toFileAssert()
.assertMethod("createUsersWithArrayInput", "List<User>")
.toFileAssert()
.assertMethod("createUsersWithListInput", "List<User>")
.toFileAssert()
.assertMethod("getUserByName", "String")
.toFileAssert()
.assertMethod("loginUser", "String", "String", "String", "Long", "BigDecimal")
.toFileAssert()
.assertMethod("updateUser", "String", "User")
.toFileAssert();
}
}

View File

@ -0,0 +1,192 @@
package org.openapitools.codegen.java.helidon;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Objects;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openapitools.codegen.CodegenConstants.SERIALIZATION_LIBRARY;
public class JavaHelidonMpServerCodegenTest {
private DefaultGenerator generator;
private String outputPath;
private String apiPackage;
private String modelPackage;
@BeforeMethod
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputPath = output.getAbsolutePath().replace('\\', '/');
apiPackage = outputPath + "/src/main/java/org/openapitools/server/api";
modelPackage = outputPath + "/src/main/java/org/openapitools/server/model";
generator = new DefaultGenerator();
}
private CodegenConfigurator createConfigurator() {
return new CodegenConfigurator()
.setGeneratorName("java-helidon-server")
.setLibrary("mp")
.setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
.setOutputDir(outputPath);
}
private void generate(CodegenConfigurator config) {
generator.opts(config.toClientOptInput());
generator.setGenerateMetadata(false);
generator.generate();
}
private void generate() {
generate(createConfigurator());
}
@Test
public void testRestApiFilesOnly() {
generate(createConfigurator().addAdditionalProperty("fullProject", "false"));
JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("public interface PetService");
File outputFile = Paths.get(outputPath).toFile();
assertThat(Objects.requireNonNull(outputFile.listFiles()).length, is(1));
}
@Test
public void testJackson() {
generate(createConfigurator().addAdditionalProperty(SERIALIZATION_LIBRARY, "jackson"));
JavaFileAssert.assertThat(Paths.get(modelPackage + "/Color.java"))
.fileContains("com.fasterxml.jackson.annotation.JsonCreator")
.fileContains("com.fasterxml.jackson.annotation.JsonValue");
}
@Test
public void testJsonb() {
generate(createConfigurator().addAdditionalProperty(SERIALIZATION_LIBRARY, "jsonb"));
JavaFileAssert.assertThat(Paths.get(modelPackage + "/Color.java"))
.fileContains(".json.bind.annotation.JsonbCreator");
}
@Test
public void testAbstractClass() {
generate(createConfigurator().addAdditionalProperty("useAbstractClass", "true"));
JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("public abstract class PetService")
.assertMethod("addPet", "Pet")
.doesNotHaveImplementation();
JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreService.java"))
.fileContains("public abstract class StoreService")
.assertMethod("placeOrder", "Order")
.doesNotHaveImplementation()
.hasReturnType("Response");
JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreServiceImpl.java"))
.fileContains("public class StoreServiceImpl extends StoreService")
.assertMethod("placeOrder", "Order")
.hasReturnType("Response")
.bodyContainsLines("return Response.ok().entity(\"magic!\").build();");
}
@Test
public void testFullProject() {
generate(createConfigurator().addAdditionalProperty("fullProject", "true"));
JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("public interface PetService")
.assertMethod("addPet", "Pet");
JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreService.java"))
.fileContains("public interface StoreService")
.assertMethod("placeOrder", "Order")
.hasReturnType("Response");
}
@Test
public void validatePetApi() {
generate();
JavaFileAssert.assertThat(Paths.get(apiPackage + "/PetService.java"))
.fileContains("org.openapitools.server.model.Pet")
.assertMethod("addPet", "Pet")
.toFileAssert()
.assertMethod("addPets", "String", "InputStream", "InputStream", "List<String>", "List<Long>", "Integer")
.toFileAssert()
.assertMethod("deletePet", "Long", "String", "Long", "String", "Integer", "List<Integer>", "List<String>")
.toFileAssert()
.assertMethod("findPetsByStatus", "List<String>")
.toFileAssert()
.assertMethod("findPetsByTags", "List<Integer>")
.toFileAssert()
.assertMethod("getPetById", "Long")
.toFileAssert()
.assertMethod("updatePet", "Pet")
.toFileAssert()
.assertMethod("updatePetWithForm", "Long", "String", "String")
.toFileAssert()
.assertMethod("uploadFile", "Long", "Long", "String", "InputStream");
}
@Test
public void validateStoreApi() {
generate();
JavaFileAssert.assertThat(Paths.get(apiPackage + "/StoreService.java"))
.fileContains("org.openapitools.server.model.Order")
.assertMethod("deleteOrder", "String")
.toFileAssert()
.assertMethod("getInventory")
.toFileAssert()
.assertMethod("getOrderById", "BigDecimal")
.toFileAssert()
.assertMethod("placeOrder", "Order");
}
@Test
public void validateUserApi() {
generate();
JavaFileAssert.assertThat(Paths.get(apiPackage + "/UserService.java"))
.fileContains("org.openapitools.server.model.User")
.assertMethod("createUser", "User")
.toFileAssert()
.assertMethod("createUsersWithArrayInput", "List<User>")
.toFileAssert()
.assertMethod("createUsersWithListInput", "List<User>")
.toFileAssert()
.assertMethod("deleteUser", "String")
.toFileAssert()
.assertMethod("getUserByName", "String")
.toFileAssert()
.assertMethod("loginUser", "String", "String", "String", "Long", "BigDecimal")
.toFileAssert()
.assertMethod("logoutUser")
.toFileAssert()
.assertMethod("updateUser", "String", "User");
}
@Test
public void testGenerateGradleProject() {
generate(createConfigurator().addAdditionalProperty("gradleProject", "true"));
assertThat(Paths.get(outputPath + "/build.gradle").toFile().exists(), is(true));
assertThat(Paths.get(outputPath + "/settings.gradle").toFile().exists(), is(true));
TestUtils.assertFileNotExists(Paths.get(outputPath + "/pom.xml"));
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
*
* 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.openapitools.codegen.java.helidon;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import static org.openapitools.codegen.java.assertions.JavaFileAssert.assertThat;
public class JavaHelidonSeClientCodegenTest {
private String outputPath;
private List<File> generatedFiles;
@BeforeClass
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputPath = output.getAbsolutePath().replace('\\', '/');
System.out.println("Generating java-helidon-client SE project in " + outputPath);
final CodegenConfigurator configurator = new CodegenConfigurator()
.setGeneratorName("java-helidon-client")
.setLibrary("se")
.setInputSpec("src/test/resources/3_0/helidon/petstore-no-multipart-for-testing.yaml")
.setOutputDir(outputPath);
final ClientOptInput clientOptInput = configurator.toClientOptInput();
DefaultGenerator generator = new DefaultGenerator();
generator.opts(clientOptInput);
generatedFiles = generator.generate();
}
@DataProvider(name = "fileSuffix")
public Object[][] fileSuffixes() {
return new Object[][] {
{""},
{"Impl"}
};
}
@Test
public void testPom() {
TestUtils.ensureContainsFile(generatedFiles, new File(outputPath), "pom.xml");
}
@Test(dataProvider = "fileSuffix")
public void testPetApi(String fileSuffix) {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/PetApi" + fileSuffix + ".java"))
.assertMethod("addPet", "Pet")
.toFileAssert()
.assertMethod("deletePet", "Long", "String", "Long", "String", "Integer",
"List<Integer>", "List<String>")
.toFileAssert()
.assertMethod("findPetsByStatus", "List<String>")
.toFileAssert()
.assertMethod("findPetsByTags", "List<Integer>")
.toFileAssert()
.assertMethod("getPetById", "Long")
.toFileAssert()
.assertMethod("updatePet", "Pet")
.toFileAssert()
.assertMethod("updatePetWithForm", "Long", "String", "String")
.toFileAssert();
}
@Test(dataProvider = "fileSuffix")
public void testStoreApi(String fileSuffix) {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/StoreApi" + fileSuffix + ".java"))
.assertMethod("deleteOrder", "String")
.toFileAssert()
.assertMethod("getInventory")
.toFileAssert()
.assertMethod("getOrderById", "BigDecimal")
.toFileAssert()
.assertMethod("placeOrder", "Order")
.toFileAssert();
}
@Test(dataProvider = "fileSuffix")
public void testUserApi(String fileSuffix) {
assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/client/api/UserApi" + fileSuffix + ".java"))
.assertMethod("createUser", "User")
.toFileAssert()
.assertMethod("createUsersWithArrayInput", "List<User>")
.toFileAssert()
.assertMethod("createUsersWithListInput", "List<User>")
.toFileAssert()
.assertMethod("getUserByName", "String")
.toFileAssert()
.assertMethod("loginUser", "String", "String", "String", "Long", "BigDecimal")
.toFileAssert()
.assertMethod("updateUser", "String", "User")
.toFileAssert();
}
}

View File

@ -0,0 +1,289 @@
package org.openapitools.codegen.java.helidon;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.Generator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.java.assertions.JavaFileAssert;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class JavaHelidonSeServerCodegenTest {
private DefaultGenerator generator;
private String outputPath;
@BeforeMethod
public void setup() throws IOException {
File output = Files.createTempDirectory("test").toFile();
output.deleteOnExit();
outputPath = output.getAbsolutePath().replace('\\', '/');
final CodegenConfigurator configurator = codegenConfigurator(new HashMap<>());
final ClientOptInput clientOptInput = configurator.toClientOptInput();
generator = new DefaultGenerator();
generator.opts(clientOptInput);
}
private CodegenConfigurator codegenConfigurator(Map<String, Object> additionalProperties) {
return new CodegenConfigurator()
.setGeneratorName("java-helidon-server")
.setLibrary("se")
.setAdditionalProperties(additionalProperties)
.setInputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml")
.setOutputDir(outputPath);
}
@Test
public void testGenerateFullProject() {
generator.generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetServiceImpl.java"))
.fileContains(
"public class PetServiceImpl",
"response.status(HTTP_CODE_NOT_IMPLEMENTED).send();"
);
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/Main.java"))
.fileContains(
"import org.openapitools.server.api.PetServiceImpl;",
".register(\"/\", new PetServiceImpl())"
);
}
@Test
public void testGenerateProjectByDefault() {
generator.generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.fileContains(
"public interface PetService extends Service {",
"default void update(Routing.Rules rules) {",
"void addPet(ServerRequest request, ServerResponse response, Pet pet);",
"void deletePet(ServerRequest request, ServerResponse response);"
);
TestUtils.assertFileNotExists(Paths.get(outputPath + "/build.gradle"));
TestUtils.assertFileNotExists(Paths.get(outputPath + "/settings.gradle"));
}
@Test
public void testGenerateGradleProject() {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("gradleProject", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
assertTrue(Paths.get(outputPath + "/build.gradle").toFile().exists());
assertTrue(Paths.get(outputPath + "/settings.gradle").toFile().exists());
TestUtils.assertFileNotExists(Paths.get(outputPath + "/pom.xml"));
}
@Test
public void testGeneratePathParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
.bodyContainsLines(
"Long petId = Optional.ofNullable(request.path().param(\"petId\")).map(Long::valueOf).orElse" +
"(null);",
"ValidatorUtils.checkNonNull(petId);"
)
.toFileAssert()
.assertMethod("getPetById")
.bodyContainsLines(
"Long petId = Optional.ofNullable(request.path().param(\"petId\")).map(Long::valueOf).orElse" +
"(null);",
"ValidatorUtils.checkNonNull(petId);"
);
}
@Test
public void testGenerateQueryParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.fileContains("import java.util.List;")
.assertMethod("findPetsByTags")
.bodyContainsLines(
"List<String> tags = Optional.ofNullable(request.queryParams().toMap().get(\"tags\"))" +
".orElse(null);",
"ValidatorUtils.checkNonNull(tags);"
)
.toFileAssert()
.assertMethod("findPetsByStatus")
.bodyContainsLines(
"List<String> status = Optional.ofNullable(request.queryParams().toMap().get(\"status\")).orElse" +
"(null);",
"ValidatorUtils.checkNonNull(status);"
);
}
@Test
public void testGenerateBodyParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("update")
.bodyContainsLines(
"rules.post(\"/pet\", Handler.create(Pet.class, this::addPet));",
"rules.put(\"/pet\", Handler.create(Pet.class, this::updatePet));"
)
.toFileAssert()
.assertMethod("addPet", "ServerRequest", "ServerResponse", "Pet")
.bodyContainsLines(
"ValidatorUtils.checkNonNull(pet);",
"handleAddPet(request, response, pet);"
)
.toFileAssert()
.assertMethod("updatePet", "ServerRequest", "ServerResponse", "Pet")
.bodyContainsLines(
"ValidatorUtils.checkNonNull(pet);",
"handleUpdatePet(request, response, pet);"
);
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/UserService.java"))
.assertMethod("update")
.bodyContainsLines(
"rules.post(\"/user\", Handler.create(User.class, this::createUser));",
"rules.post(\"/user/createWithArray\", this::createUsersWithArrayInput);",
"rules.post(\"/user/createWithList\", this::createUsersWithListInput);",
"rules.put(\"/user/{username}\", Handler.create(User.class, this::updateUser));"
)
.toFileAssert()
.assertMethod("createUser", "ServerRequest", "ServerResponse", "User")
.bodyContainsLines(
"ValidatorUtils.checkNonNull(user);",
"handleCreateUser(request, response, user);"
)
.toFileAssert()
.assertMethod("createUsersWithArrayInput", "ServerRequest", "ServerResponse")
.bodyContainsLines(
"Single.create(request.content().as(new GenericType<List<User>>() { }))",
".thenAccept(user -> {",
"ValidatorUtils.checkNonNull(user);",
"handleCreateUsersWithArrayInput(request, response, user);",
".exceptionally(throwable -> handleError(request, response, throwable));"
);
}
@Test
public void testGenerateHeaderParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
.bodyContainsLines(
"String apiKey = request.headers().value(\"api_key\").orElse(null);",
"Long headerLong = request.headers().value(\"headerLong\").map(Long::valueOf).orElse(null);",
"ValidatorUtils.checkNonNull(headerLong);"
);
}
@Test
public void testGenerateCookiesParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("deletePet", "ServerRequest", "ServerResponse")
.bodyContainsLines(
"String cookieString = request.headers().cookies().toMap().getOrDefault(\"cookieString\", List.of" +
"()).stream().findFirst().orElse(null);",
"ValidatorUtils.checkNonNull(cookieString);",
"Integer cookieInt = request.headers().cookies().toMap().getOrDefault(\"cookieInt\", List.of())" +
".stream().findFirst().map(Integer::valueOf).orElse(null);",
"List<String> cookieIntArray = Optional.ofNullable(request.headers().cookies().toMap().get" +
"(\"cookieIntArray\")).orElse(null);",
"List<String> cookieStringArray = Optional.ofNullable(request.headers().cookies().toMap().get" +
"(\"cookieStringArray\")).orElse(null);"
);
}
@Test
public void testGenerateFormParams() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("addPets", "ServerRequest", "ServerResponse")
.bodyContainsLines(
"Map<String, List<String>> nonFileFormContent = new HashMap<>();",
"Map<String, List<InputStream>> fileFormContent = new HashMap<>();",
" Single<Void> formSingle = request.content().asStream(ReadableBodyPart.class)",
"if (\"images[]\".equals(name)) {",
"processFileFormField(name, fileFormContent, part);",
"if (\"image\".equals(name)) {",
"if (\"titles[]\".equals(name)) {",
"processNonFileFormField(name, nonFileFormContent, part);",
"if (\"longArray\".equals(name)) {",
"if (\"stringParam\".equals(name)) {",
"if (\"intParam\".equals(name)) {",
"List<InputStream> images = Optional.ofNullable(fileFormContent.get(\"images[]\")).orElse(null);",
"InputStream image = Optional.ofNullable(fileFormContent.get(\"image\")).flatMap(list->list" +
".stream().findFirst()).orElse(null);",
"List<String> titles = Optional.ofNullable(nonFileFormContent.get(\"titles[]\")).orElse(null);",
"List<String> longArray = Optional.ofNullable(nonFileFormContent.get(\"longArray\")).orElse(null);",
"Integer intParam = Optional.ofNullable(nonFileFormContent.get(\"intParam\")).flatMap(list->list" +
".stream().findFirst()).map(Integer::valueOf).orElse(null);"
);
}
@Test
public void testGenerateParamsValidation() throws IOException {
Map<String, Object> additionalProperties = new HashMap<>();
additionalProperties.put("useAbstractClass", true);
final CodegenConfigurator configurator = codegenConfigurator(additionalProperties);
generator.opts(configurator.toClientOptInput()).generate();
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/PetService.java"))
.assertMethod("findPetsByStatus")
.bodyContainsLines(
"ValidatorUtils.checkNonNull(status);",
"List<String> status = Optional.ofNullable(request.queryParams().toMap().get(\"status\")).orElse" +
"(null);"
)
.toFileAssert()
.assertMethod("findPetsByTags")
.bodyContainsLines(
"List<String> tags = Optional.ofNullable(request.queryParams().toMap().get(\"tags\")).orElse" +
"(null);",
"ValidatorUtils.checkNonNull(tags);"
);
JavaFileAssert.assertThat(Paths.get(outputPath + "/src/main/java/org/openapitools/server/api/UserService.java"))
.assertMethod("loginUser")
.bodyContainsLines(
"ValidatorUtils.validatePattern(username, \"^[a-zA-Z0-9]+[a-zA-Z0-9\\\\" +
".\\\\-_]*[a-zA-Z0-9]+$\");",
""
);
}
}

View File

@ -0,0 +1,360 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon.functional;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.JavaHelidonCommonCodegen;
import org.testng.SkipException;
import static java.util.Objects.requireNonNull;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
abstract class FunctionalBase {
private static final Logger LOGGER = Logger.getLogger(FunctionalBase.class.getName());
private static final String MAVEN_SHIM_TARGET = "libexec/bin/mvn";
private static final String MAVEN_HOME_VAR = "MAVEN_HOME";
private static final String MVN_HOME_VAR = "MVN_HOME";
private static final String PATH_VAR = "PATH";
private static final String MAVEN_BINARY_NAME;
private static final boolean IS_WINDOWS_OS;
private static final List<Map.Entry<Integer, String>> DEFAULT_HELIDON_VERSIONS_FOR_JAVA_VERSIONS = new ArrayList<>();
protected static final String FULL_PROJECT = "fullProject";
protected static final String USE_ABSTRACT_CLASS = "useAbstractClass";
static {
/*
The inferred Helidon version for tests is from the entry for which the Java major version does not exceed
the current runtime Java major version.
For example, for Java 8 or 9 or 11: 2.5.3. For Java 13 or later: 3.0.1.
*/
DEFAULT_HELIDON_VERSIONS_FOR_JAVA_VERSIONS.add(new AbstractMap.SimpleEntry<>(11, "2.5.3"));
DEFAULT_HELIDON_VERSIONS_FOR_JAVA_VERSIONS.add(new AbstractMap.SimpleEntry<>(13, "3.0.1"));
}
private String library;
private String generatorName;
private String inputSpec;
protected Path outputPath;
private Path mvn;
static {
IS_WINDOWS_OS = System.getProperty("os.name", "unknown")
.toLowerCase(Locale.ENGLISH)
.contains("win");
MAVEN_BINARY_NAME = IS_WINDOWS_OS ? "mvn.cmd" : "mvn";
}
protected CodegenConfigurator createConfigurator() {
try {
return createConfigurator(Files.createTempDirectory("test"));
} catch (IOException e) {
throw new UncheckedIOException("Can not create temp directory", e);
}
}
protected CodegenConfigurator createConfigurator(Path outputPath) {
Objects.requireNonNull(inputSpec);
this.outputPath = outputPath;
String sanitizedPath = outputPath.toFile()
.getAbsolutePath()
.replace('\\', '/');
return new CodegenConfigurator()
.setGeneratorName(generatorName)
.setLibrary(library)
.setInputSpec(inputSpec)
.setOutputDir(sanitizedPath);
}
protected void generate(CodegenConfigurator config) {
String helidonVersionToUse = chooseHelidonVersion(config);
enforceJavaVersion(helidonVersionToUse);
DefaultGenerator generator = new DefaultGenerator();
generator.opts(config.toClientOptInput());
generator.generate();
}
protected void generate() {
generate(createConfigurator());
}
protected void generate(String inputSpec) {
inputSpec(inputSpec);
generate(createConfigurator());
}
protected void generatorName(String generatorName) {
this.generatorName = generatorName;
}
protected void library(String library) {
this.library = library;
}
protected void inputSpec(String inputSpec) {
this.inputSpec = inputSpec;
}
/**
* Run maven command with provided arguments.
*
* @param args maven command arguments
* @return a {@link ProcessReader}
*/
protected ProcessReader runMavenProcess(String... args) {
return runMavenProcess(outputPath.toFile(), args);
}
/**
* Run maven command and causes the current thread to wait for {@link Process} to terminate.
*
* @param args maven command arguments
* @return a {@link ProcessReader}
*/
protected ProcessReader runMavenProcessAndWait(String... args) {
ProcessReader process = runMavenProcess(args);
process.waitFor(10, TimeUnit.MINUTES);
return process;
}
/**
* Run maven command in the provided directory.
*
* @param directory from where the command is executed
* @param args maven command arguments
* @return a {@link ProcessReader}
*/
protected ProcessReader runMavenProcess(File directory, String... args) {
List<String> command = new ArrayList<>(Collections.singleton(mavenExecutable()));
Collections.addAll(command, args);
try {
Process process = new ProcessBuilder()
.directory(directory)
.command(command)
.start();
return new ProcessReader(process);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* Finds the {@code mvn} executable. Searches using the following, in order:
* <ol>
* <li>The {@code MAVEN_HOME} environment variable</li>
* <li>The {@code MVN_HOME} environment variable</li>
* <li>The {@code PATH} environment variable</li>
* </ol>
*
* @return The path.
*/
public String mavenExecutable() {
if (mvn == null) {
Path maven;
Optional<Path> path = findExecutableInPath();
if (path.isPresent()) {
maven = path.get();
} else {
maven = toMavenExecutable(MAVEN_HOME_VAR);
if (maven == null) {
maven = toMavenExecutable(MVN_HOME_VAR);
}
}
try {
assumeTrue( "Maven not found, test is skipped", maven != null);
maven = maven.toRealPath();
Path shimmed = maven.getParent().getParent().resolve(MAVEN_SHIM_TARGET);
if (Files.exists(shimmed)) {
maven = shimmed;
}
mvn = maven.toRealPath();
} catch (IOException ex) {
throw new IllegalStateException(ex.getMessage());
}
}
return mvn.toString();
}
private String chooseHelidonVersion(CodegenConfigurator config) {
Map<String, Object> unprocessedAdditionalProperties = config.toContext()
.getGeneratorSettings()
.getAdditionalProperties();
if (unprocessedAdditionalProperties.containsKey(JavaHelidonCommonCodegen.HELIDON_VERSION)) {
return unprocessedAdditionalProperties.get(JavaHelidonCommonCodegen.HELIDON_VERSION).toString();
}
String result = inferredHelidonVersion();
config.addAdditionalProperty(JavaHelidonCommonCodegen.HELIDON_VERSION, result);
return result;
}
private void enforceJavaVersion(String helidonVersionToUse) {
int currentJavaVersion = getCurrentJavaMajorVersion();
int requiredJavaVersion = getRequiredJavaVersion(helidonVersionToUse);
String errorJavaVersion = String.format(Locale.ROOT, "Java version must be %s, test is skipped", requiredJavaVersion);
assumeTrue(errorJavaVersion, currentJavaVersion == requiredJavaVersion);
}
private int getRequiredJavaVersion(String helidonVersionToUse) {
return helidonVersionToUse
.startsWith("3.") ? 17 : 11;
}
private int getCurrentJavaMajorVersion() {
String[] versionElements = System.getProperty("java.version").split("\\.");
int firstElement = Integer.parseInt(versionElements[0]);
if (firstElement == 1) {
return Integer.parseInt(versionElements[1]);
} else {
return firstElement;
}
}
private String inferredHelidonVersion() {
int javaMajorVersion = getCurrentJavaMajorVersion();
String result = null;
for (Map.Entry<Integer, String> javaToHelidonVersionMapping : DEFAULT_HELIDON_VERSIONS_FOR_JAVA_VERSIONS) {
if (javaToHelidonVersionMapping.getKey() <= javaMajorVersion) {
result = javaToHelidonVersionMapping.getValue();
}
}
if (result == null) {
String message = String.format(Locale.ROOT, "Unable to infer Helidon version from current Java major version %d using mapping %s",
javaMajorVersion, DEFAULT_HELIDON_VERSIONS_FOR_JAVA_VERSIONS);
LOGGER.log(Level.WARNING, message);
throw new SkipException(message);
}
return result;
}
/**
* Find an executable in the {@code PATH} environment variable, if present.
*
* @return The path.
*/
private Optional<Path> findExecutableInPath() {
return Arrays.stream(requireNonNull(System.getenv(PATH_VAR)).split(File.pathSeparator))
.map(Paths::get)
.map(path -> path.resolve(FunctionalBase.MAVEN_BINARY_NAME))
.filter(Files::isExecutable)
.findFirst();
}
private Path toMavenExecutable(String mavenHomeEnvVar) {
Path mavenHome = envVarPath(mavenHomeEnvVar);
if (mavenHome != null) {
if (Files.isDirectory(mavenHome)) {
Path executable = mavenHome.resolve("bin").resolve(MAVEN_BINARY_NAME);
if (Files.exists(executable) && (IS_WINDOWS_OS || Files.isExecutable(executable))) {
return executable;
}
}
}
return null;
}
private static Path envVarPath(String var) {
final String path = System.getenv(var);
return path == null ? null : Paths.get(path);
}
/**
* Allow junit to skip test without throwing an exception and report tests as failed.
*
* @param message warning message
* @param condition to be checked
*/
protected static void assumeTrue(String message, boolean condition) {
if (!condition) {
LOGGER.log(Level.WARNING, message);
throw new SkipException(message);
}
}
/**
* Convenience method to build project using Maven and verify test output.
*
* @param jarPath path to expected jar file
*/
protected void buildAndVerify(String jarPath) {
ProcessReader reader = runMavenProcessAndWait("package");
Path executableJar = outputPath.resolve(jarPath);
String output = reader.readOutputConsole();
assertThat(output, containsString("BUILD SUCCESS"));
assertThat(output, containsString("Errors: 0"));
assertThat(output, containsString("Failures: 0"));
assertThat(output, containsString("Skipped: 0"));
assertThat(Files.exists(executableJar), is(true));
}
/**
* {@link Process} wrapper to read I/O Stream.
*/
static class ProcessReader {
private final Process process;
private final BufferedReader consoleReader;
ProcessReader(Process process) {
this.process = process;
this.consoleReader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
}
public String readOutputConsole() {
return consoleReader.lines().collect(Collectors.joining("\n"));
}
@SuppressWarnings("UnusedReturnValue")
public boolean waitFor(long timeout, TimeUnit unit) {
try {
return process.waitFor(timeout, unit);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
*
* 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.openapitools.codegen.java.helidon.functional;
import org.testng.annotations.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
public class FunctionalHelidonClientBase extends FunctionalBase {
@Test
void buildPetstore() {
generate("src/test/resources/3_0/petstore.yaml");
buildAndVerify("target/openapi-java-client.jar");
}
@Test
void buildPetstoreWithFakeEndpoints() {
generate("src/test/resources/3_0/petstore-with-fake-endpoints-models-for-testing.yaml");
buildAndVerify("target/openapi-java-client.jar");
}
@Test
void buildPetstoreNoMultipart() {
generate("src/test/resources/3_0/helidon/petstore-no-multipart-for-testing.yaml");
buildAndVerify("target/openapi-java-client.jar");
}
@Test
void verifyFullProjectSemantics() {
inputSpec("src/test/resources/3_0/petstore.yaml");
// Generate project for first time and record pom's timestamp
generate(createConfigurator());
buildAndVerify("target/openapi-java-client.jar");
Path pom1 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom1), is(true));
long lastModified = pom1.toFile().lastModified();
// Re-generate project over same directory with fullProject unspecified
generate(createConfigurator(outputPath));
Path pom2 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom2), is(true));
assertThat(pom2.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject false
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "false"));
Path pom3 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom3), is(true));
assertThat(pom3.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject true
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "true"));
Path pom4 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom4), is(true));
assertThat(pom4.toFile().lastModified(), is(not(lastModified))); // overwritten
}
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon.functional;
import org.testng.annotations.BeforeClass;
public class FunctionalHelidonMPClientTest extends FunctionalHelidonClientBase {
@BeforeClass
public void setup() {
library("mp");
generatorName("java-helidon-client");
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon.functional;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.openapitools.codegen.CodegenConstants.SERIALIZATION_LIBRARY;
public class FunctionalHelidonMPServerTest extends FunctionalBase {
@BeforeClass
public void setup() {
library("mp");
generatorName("java-helidon-server");
inputSpec("src/test/resources/3_0/helidon/petstore-for-testing.yaml");
}
@Test
void buildProjectDefaultOptions() {
generate();
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void buildProjectAbstractClasses() {
generate(createConfigurator().addAdditionalProperty(USE_ABSTRACT_CLASS, "true"));
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void buildFullProject() {
generate(createConfigurator().addAdditionalProperty(FULL_PROJECT, "true"));
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void verifyFullProjectSemantics() {
// Generate project for first time and record pom's timestamp
generate(createConfigurator());
buildAndVerify("target/openapi-java-server.jar");
Path pom1 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom1), is(true));
long lastModified = pom1.toFile().lastModified();
// Re-generate project over same directory with fullProject unspecified
generate(createConfigurator(outputPath));
Path pom2 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom2), is(true));
assertThat(pom2.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject false
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "false"));
Path pom3 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom3), is(true));
assertThat(pom3.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject true
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "true"));
Path pom4 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom4), is(true));
assertThat(pom4.toFile().lastModified(), is(not(lastModified))); // overwritten
}
@Test
void buildJsonbProject() {
generate(createConfigurator().addAdditionalProperty(SERIALIZATION_LIBRARY, "jsonb"));
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void buildJacksonProject() {
generate(createConfigurator().addAdditionalProperty(SERIALIZATION_LIBRARY, "jackson"));
buildAndVerify("target/openapi-java-server.jar");
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon.functional;
import org.testng.annotations.BeforeClass;
public class FunctionalHelidonSEClientTest extends FunctionalHelidonClientBase {
@BeforeClass
public void setup() {
library("se");
generatorName("java-helidon-client");
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates
*
* 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
*
* https://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.openapitools.codegen.java.helidon.functional;
import java.nio.file.Files;
import java.nio.file.Path;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
public class FunctionalHelidonSeServerTest extends FunctionalBase {
@BeforeClass
public void setup() {
library("se");
generatorName("java-helidon-server");
}
@Test
void buildPetstoreWithDefaultOptions() {
generate("src/test/resources/3_0/petstore.yaml");
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void buildPetstoreWithAbstractClasses() {
inputSpec("src/test/resources/3_0/petstore.yaml");
generate(createConfigurator().addAdditionalProperty(FunctionalBase.USE_ABSTRACT_CLASS, "true"));
buildAndVerify("target/openapi-java-server.jar");
}
@Test
void verifyFullProject() {
inputSpec("src/test/resources/3_0/petstore.yaml");
// Generate project for first time and record pom's timestamp
generate(createConfigurator());
buildAndVerify("target/openapi-java-server.jar");
Path pom1 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom1), is(true));
long lastModified = pom1.toFile().lastModified();
// Re-generate project over same directory with fullProject unspecified
generate(createConfigurator(outputPath));
Path pom2 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom2), is(true));
assertThat(pom2.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject false
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "false"));
Path pom3 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom3), is(true));
assertThat(pom3.toFile().lastModified(), is(lastModified)); // not overwritten
// Re-generate project over same directory with fullProject true
generate(createConfigurator(outputPath).addAdditionalProperty(FULL_PROJECT, "true"));
Path pom4 = outputPath.resolve("pom.xml");
assertThat(Files.exists(pom4), is(true));
assertThat(pom4.toFile().lastModified(), is(not(lastModified))); // overwritten
}
}

View File

@ -0,0 +1,860 @@
openapi: 3.0.0
servers:
- url: 'http://petstore.helidon.io:8080/v2'
info:
description: >-
This spec is mainly for testing Petstore server and contains fake endpoints,
models. Please do not use this for any other purpose. For this sample, you can use the api key
`special-key` to test the authorization filters. Special characters: "
\
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: pet
description: Everything about your Pets
- name: store
description: Access to Petstore orders
- name: user
description: Operations about user
paths:
/pet:
post:
tags:
- pet
summary: Add a new pet to the store
description: ''
operationId: addPet
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'
requestBody:
$ref: '#/components/requestBodies/Pet'
put:
tags:
- pet
summary: Update an existing pet
description: ''
operationId: updatePet
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'
requestBody:
$ref: '#/components/schemas/Pet'
/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: true
style: form
explode: false
schema:
type: array
items:
type: string
enum:
- available
- pending
- sold
default: available
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:
- '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: true
style: form
explode: false
schema:
type: array
items:
type: integer
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:
- 'read:pets'
deprecated: true
'/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: []
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
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
name:
description: Updated name of the pet
type: string
status:
description: Updated status of the pet
type: string
delete:
tags:
- pet
summary: Deletes a pet
description: ''
operationId: deletePet
parameters:
- name: api_key
in: header
required: false
schema:
type: string
- name: headerLong
in: header
required: true
schema:
type: integer
format: int64
- name: cookieString
in: cookie
schema:
type: string
required: true
- name: cookieInt
in: cookie
schema:
type: integer
format: int32
required: false
- name: cookieIntArray
in: cookie
schema:
type: array
items:
type: integer
required: false
- name: cookieStringArray
in: cookie
schema:
type: array
items:
type: string
required: false
- 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
minimum: 1
maximum: 5
- name: petDate
in: path
description: Date for test
required: true
schema:
type: integer
format: int64
minimum: 1
maximum: 5
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
additionalMetadata:
description: Additional data to pass to server
type: string
file:
description: file to upload
type: string
format: binary
/pet/upload:
post:
tags:
- pet
summary: Add a few pets using form
description: ''
operationId: addPets
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/PetsForm'
description: Object that that contains info about pets
required: true
responses:
'200':
description: successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/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: ''
operationId: placeOrder
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Order'
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid Order
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
description: order placed for purchasing the pet
required: true
'/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 generated exceptions
operationId: getOrderById
parameters:
- name: orderId
in: path
description: ID of pet that needs to be fetched
required: true
schema:
type: number
minimum: 1
maximum: 5
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: 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
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
description: Created user object
required: true
/user/createWithArray:
post:
tags:
- user
summary: Creates list of users with given input array
description: ''
operationId: createUsersWithArrayInput
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
$ref: '#/components/requestBodies/UserArray'
/user/createWithList:
post:
tags:
- user
summary: Creates list of users with given input array
description: ''
operationId: createUsersWithListInput
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
$ref: '#/components/requestBodies/UserArray'
/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: true
schema:
type: string
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
- name: password
in: query
description: The password for login in clear text
required: true
schema:
type: string
- name: sizeString
in: query
description: String param to test Size constraint
required: true
schema:
type: string
minLength: 5
maxLength: 10
- name: minLong
in: query
description: Min Long param for test
required: true
schema:
type: integer
format: int64
minimum: 10
- name: minDecimal
in: query
description: Min Decimal param for test
required: true
schema:
type: number
minimum: 0
exclusiveMinimum: true
responses:
'200':
description: successful operation
headers:
Set-Cookie:
description: >-
Cookie authentication key for use with the `api_key`
apiKey authentication.
schema:
type: string
example: AUTH_KEY=abcde12345; Path=/; HttpOnly
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
responses:
default:
description: successful operation
security:
- api_key: []
'/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: Updated user
description: This can only be done by the logged in user.
operationId: updateUser
parameters:
- name: username
in: path
description: name that need to be deleted
required: true
schema:
type: string
responses:
'400':
description: Invalid user supplied
'404':
description: User not found
security:
- api_key: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
description: Updated user object
required: true
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
security:
- api_key: []
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
components:
requestBodies:
UserArray:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
description: List of user object
required: true
Pet:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/xml:
schema:
$ref: '#/components/schemas/Pet'
description: Pet object that needs to be added to the store
required: true
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
scopes:
'write:pets': modify pets in your account
'read:pets': read your pets
api_key:
type: apiKey
name: api_key
in: header
schemas:
AnyValue: {}
Color:
type: string
enum:
- black
- white
- red
- green
- blue
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
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
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: '#/components/schemas/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: '#/components/schemas/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
PetsForm:
type: object
properties:
images[]:
type: array
items:
type: string
format: binary
image:
type: string
format: binary
titles[]:
type: array
items:
type: string
longArray:
type: array
items:
type: integer
format: int64
stringParam:
type: string
intParam:
type: integer
format: int32
required:
- stringParam

View File

@ -0,0 +1,789 @@
openapi: 3.0.0
servers:
- url: 'http://petstore.helidon.io:8080/v2'
info:
description: >-
This spec is mainly for testing Petstore server and contains fake endpoints,
models. Please do not use this for any other purpose. For this sample, you can use the api key
`special-key` to test the authorization filters. Special characters: "
\
version: 1.0.0
title: OpenAPI Petstore
license:
name: Apache-2.0
url: 'https://www.apache.org/licenses/LICENSE-2.0.html'
tags:
- name: pet
description: Everything about your Pets
- name: store
description: Access to Petstore orders
- name: user
description: Operations about user
paths:
/pet:
post:
tags:
- pet
summary: Add a new pet to the store
description: ''
operationId: addPet
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'
requestBody:
$ref: '#/components/requestBodies/Pet'
put:
tags:
- pet
summary: Update an existing pet
description: ''
operationId: updatePet
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'
requestBody:
$ref: '#/components/schemas/Pet'
/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: true
style: form
explode: false
schema:
type: array
items:
type: string
enum:
- available
- pending
- sold
default: available
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:
- '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: true
style: form
explode: false
schema:
type: array
items:
type: integer
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:
- 'read:pets'
deprecated: true
'/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: []
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
responses:
'405':
description: Invalid input
security:
- petstore_auth:
- 'write:pets'
- 'read:pets'
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
name:
description: Updated name of the pet
type: string
status:
description: Updated status of the pet
type: string
delete:
tags:
- pet
summary: Deletes a pet
description: ''
operationId: deletePet
parameters:
- name: api_key
in: header
required: false
schema:
type: string
- name: headerLong
in: header
required: true
schema:
type: integer
format: int64
- name: cookieString
in: cookie
schema:
type: string
required: true
- name: cookieInt
in: cookie
schema:
type: integer
format: int32
required: false
- name: cookieIntArray
in: cookie
schema:
type: array
items:
type: integer
required: false
- name: cookieStringArray
in: cookie
schema:
type: array
items:
type: string
required: false
- 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'
/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: ''
operationId: placeOrder
responses:
'200':
description: successful operation
content:
application/xml:
schema:
$ref: '#/components/schemas/Order'
application/json:
schema:
$ref: '#/components/schemas/Order'
'400':
description: Invalid Order
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Order'
description: order placed for purchasing the pet
required: true
'/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 generated exceptions
operationId: getOrderById
parameters:
- name: orderId
in: path
description: ID of pet that needs to be fetched
required: true
schema:
type: number
minimum: 1
maximum: 5
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: 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
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
description: Created user object
required: true
/user/createWithArray:
post:
tags:
- user
summary: Creates list of users with given input array
description: ''
operationId: createUsersWithArrayInput
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
$ref: '#/components/requestBodies/UserArray'
/user/createWithList:
post:
tags:
- user
summary: Creates list of users with given input array
description: ''
operationId: createUsersWithListInput
responses:
default:
description: successful operation
security:
- api_key: []
requestBody:
$ref: '#/components/requestBodies/UserArray'
/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: true
schema:
type: string
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
- name: password
in: query
description: The password for login in clear text
required: true
schema:
type: string
- name: sizeString
in: query
description: String param to test Size constraint
required: true
schema:
type: string
minLength: 5
maxLength: 10
- name: minLong
in: query
description: Min Long param for test
required: true
schema:
type: integer
format: int64
minimum: 10
- name: minDecimal
in: query
description: Min Decimal param for test
required: true
schema:
type: number
minimum: 0
exclusiveMinimum: true
responses:
'200':
description: successful operation
headers:
Set-Cookie:
description: >-
Cookie authentication key for use with the `api_key`
apiKey authentication.
schema:
type: string
example: AUTH_KEY=abcde12345; Path=/; HttpOnly
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
responses:
default:
description: successful operation
security:
- api_key: []
'/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: Updated user
description: This can only be done by the logged in user.
operationId: updateUser
parameters:
- name: username
in: path
description: name that need to be deleted
required: true
schema:
type: string
responses:
'400':
description: Invalid user supplied
'404':
description: User not found
security:
- api_key: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/User'
description: Updated user object
required: true
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
security:
- api_key: []
externalDocs:
description: Find out more about Swagger
url: 'http://swagger.io'
components:
requestBodies:
UserArray:
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/User'
description: List of user object
required: true
Pet:
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/xml:
schema:
$ref: '#/components/schemas/Pet'
description: Pet object that needs to be added to the store
required: true
securitySchemes:
petstore_auth:
type: oauth2
flows:
implicit:
authorizationUrl: 'http://petstore.swagger.io/api/oauth/dialog'
scopes:
'write:pets': modify pets in your account
'read:pets': read your pets
api_key:
type: apiKey
name: api_key
in: header
schemas:
AnyValue: {}
Color:
type: string
enum:
- black
- white
- red
- green
- blue
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
pattern: '^[a-zA-Z0-9]+[a-zA-Z0-9\.\-_]*[a-zA-Z0-9]+$'
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: '#/components/schemas/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: '#/components/schemas/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
PetsForm:
type: object
properties:
images[]:
type: array
items:
type: string
format: binary
image:
type: string
format: binary
titles[]:
type: array
items:
type: string
longArray:
type: array
items:
type: integer
format: int64
stringParam:
type: string
intParam:
type: integer
format: int32
required:
- stringParam

24
pom.xml
View File

@ -744,6 +744,30 @@
<module>samples/server/petstore/java-micronaut-server</module>
</modules>
</profile>
<profile>
<id>java-helidon-client</id>
<activation>
<property>
<name>env</name>
<value>java</value>
</property>
</activation>
<modules>
<module>samples/client/petstore/java-helidon-client</module>
</modules>
</profile>
<profile>
<id>java-helidon-server</id>
<activation>
<property>
<name>env</name>
<value>java</value>
</property>
</activation>
<modules>
<module>samples/server/petstore/java-helidon-server</module>
</modules>
</profile>
<profile>
<id>java-msf4j-server</id>
<activation>