Skip to content

Commit

Permalink
mpOpenAPI-4.0: OpenAPI v3.1 validation FAT tests
Browse files Browse the repository at this point in the history
Copy the existing OpenAPI v3.0 validation FAT tests and adjust them for
the new validation rules in v3.1 and run them against OpenAPI v3.1
documents.
  • Loading branch information
Azquelt committed Sep 20, 2024
1 parent eeb3feb commit ae9f366
Show file tree
Hide file tree
Showing 23 changed files with 4,498 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin" path="fat/src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
<classpathentry kind="output" path="bin"/>
</classpath>
23 changes: 23 additions & 0 deletions dev/io.openliberty.microprofile.openapi.4.0.internal_fat/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.openliberty.microprofile.openapi.4.0.internal_fat</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>bndtools.core.bndbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>bndtools.core.bndnature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
compileErrorAction=build
eclipse.preferences.version=1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/bnd.bnd=UTF-8

Large diffs are not rendered by default.

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions dev/io.openliberty.microprofile.openapi.4.0.internal_fat/bnd.bnd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#*******************************************************************************
# Copyright (c) 2020, 2022 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License 2.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# IBM Corporation - initial API and implementation
#*******************************************************************************
-include= ~../cnf/resources/bnd/bundle.props
bVersion=1.0


src: \
fat/src

fat.project: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package io.openliberty.microprofile.openapi40.fat;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestFive;
import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestFour;
import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestMissing;
import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestNoErrors;
import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestOne;
import io.openliberty.microprofile.openapi40.fat.validation.ValidationTestTwo;

@SuiteClasses({
ValidationTestOne.class,
ValidationTestTwo.class,
ValidationTestMissing.class,
ValidationTestFour.class,
ValidationTestFive.class,
ValidationTestNoErrors.class
})
@RunWith(Suite.class)
public class FATSuite {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package io.openliberty.microprofile.openapi40.fat.validation;

import static com.ibm.websphere.simplicity.ShrinkHelper.DeployOptions.SERVER_ONLY;
import static io.openliberty.microprofile.openapi40.fat.validation.ValidationTestUtils.assertMessage;
import static io.openliberty.microprofile.openapi40.fat.validation.ValidationTestUtils.assertNoMessage;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.ibm.websphere.simplicity.ShrinkHelper;

import componenttest.annotation.Server;
import componenttest.custom.junit.runner.FATRunner;
import componenttest.topology.impl.LibertyServer;

/**
* Validation tests for Tags, Discriminator, Schema and Extension
* <p>
* Ported from OpenAPIValidationTestFive and converted to run on OpenAPI v3.1
* <p>
* The validation tests for Schema in particular are quite different for OpenAPI 3.1
*/
@RunWith(FATRunner.class)
public class ValidationTestFive {
private static final String SERVER_NAME = "OpenAPIValidationServer";

@Server(SERVER_NAME)
public static LibertyServer server;

@BeforeClass
public static void setup() throws Exception {
WebArchive war = ShrinkWrap.create(WebArchive.class, "validation5.war")
.addAsManifestResource(ValidationTestFive.class.getPackage(), "validation5.yml", "openapi.yml");
ShrinkHelper.exportDropinAppToServer(server, war, SERVER_ONLY);

server.startServer();
}

@AfterClass
public static void shutdown() throws Exception {
server.stopServer("CWWKO1650E", // Validation errors found
"CWWKO1651W");// Validation warnings found
}

@Test
public void testTags() throws Exception {
assertMessage(server, "- Message: Required \"name\" field is missing or is set to an invalid value, Location: #/tags");
}

@Test
public void testDiscriminator() throws Exception {
assertMessage(server, "- Message: Required \"propertyName\" field is missing or is set to an invalid value,*");
}

@Test
public void testSchema() throws Exception {
assertMessage(server, " - Message: The Schema Object must have the \"multipleOf\" property set to a number strictly greater than zero, "
+ "Location: #/paths/~1availability/get/parameters/schema");
assertMessage(server, " - Message: The \"minItems\" property of the Schema Object must be greater than or equal to zero, "
+ "Location: #/paths/~1availability/get/parameters/schema");
assertMessage(server, " - Message: The \"maxItems\" property of the Schema Object must be greater than or equal to zero, "
+ "Location: #/paths/~1availability/get/parameters/schema");
assertMessage(server, " - Message: The \"minProperties\" property of the Schema Object must be greater than or equal to zero, "
+ "Location: #/paths/~1availability/get/parameters/schema");
assertMessage(server, " - Message: The \"maxProperties\" property of the Schema Object must be greater than or equal to zero, "
+ "Location: #/paths/~1availability/get/parameters/schema");

// Warnings not currently emitted for 3.1
assertNoMessage(server, " - Message: The \"minItems\" property is not appropriate for the Schema Object of \"object\" type");
assertNoMessage(server, " - Message: The \"maxItems\" property is not appropriate for the Schema Object of \"object\" type");

// Dubious error reported for 3.0, not reported for 3.1
assertNoMessage(server, " - Message: The Schema Object of \"array\" type must have \"items\" property defined");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package io.openliberty.microprofile.openapi40.fat.validation;

import static com.ibm.websphere.simplicity.ShrinkHelper.DeployOptions.SERVER_ONLY;
import static io.openliberty.microprofile.openapi40.fat.validation.ValidationTestUtils.assertMessage;
import static io.openliberty.microprofile.openapi40.fat.validation.ValidationTestUtils.assertNoMessage;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.ibm.websphere.simplicity.ShrinkHelper;

import componenttest.annotation.Server;
import componenttest.custom.junit.runner.FATRunner;
import componenttest.topology.impl.LibertyServer;

/**
* Validation tests for References, Callbacks and PathItems
* <p>
* Ported from OpenAPIValidationTestFour and converted to run on OpenAPI v3.1
*/
@RunWith(FATRunner.class)
public class ValidationTestFour {
private static final String SERVER_NAME = "OpenAPIValidationServer";

@Server(SERVER_NAME)
public static LibertyServer server;

@BeforeClass
public static void setup() throws Exception {
WebArchive war = ShrinkWrap.create(WebArchive.class, "validation4.war")
.addAsManifestResource(ValidationTestFour.class.getPackage(), "validation4.yml", "openapi.yml");
ShrinkHelper.exportDropinAppToServer(server, war, SERVER_ONLY);

server.startServer();
}

@AfterClass
public static void shutdown() throws Exception {
server.stopServer("CWWKO1650E", // Validation errors found
"CWWKO1651W");// Validation warnings found
}

@Test
public void testRef() throws Exception {

// 3.1 Validation cases
// Reference is null/empty (reference is null)
// Reference is not a valid URI (URI.create does not parse it) (reference is not a valid URI)
// Ref is within components and components is missing (reference not defined within Components)
// Ref is to a known name within components and the object is missing (reference not defined within Components)
// Ref is to an object but the object is of the wrong type (is an invalid reference) - only reported if no other errors

// Main differences from 3.0:
// We directly test whether the reference parses as a URI
// We don't report the "is an invalid reference" error if we report another problem with the same reference
// We don't validate references which aren't of the form #/components/<type>/<name> - 3.0 reports some of these as "not in a valid format"
// - the spec doesn't restrict where a json pointer to point to
// - we could do better validation here, but we can't currently navigate the model reflectively by name, so following a json pointer is not easy

// Currently outstanding issues:
// Unqualified schema references do not get automatically prefixed with '#/components/schemas/'
// - https://github.com/smallrye/smallrye-open-api/issues/1987

// assertMessage(server, " - Message: The \"#/components/schemas/\" reference value is not in a valid format, Location: #/paths/~1availability/get/parameters/schema");
// assertMessage(server, " - Message: The \"#/components/schemas/ \" reference value is not defined within the Components Object, "
// + "Location: #/paths/~1availability/get/parameters/schema");
// assertMessage(server, " - Message: The \"#/components/schemas/#\" reference value is not defined within the Components Object, "
// + "Location: #/paths/~1availability/get/parameters/schema");

// 3-part reference with an invalid type
assertMessage(server, " - Message: The \"#/components/Flight\" reference value is not defined within the Components Object, "
+ "Location: #/paths/~1availability/get/responses/200/content/applictaion~1json/schema/items");
// 4-part reference with an invalid type
assertMessage(server, " - Message: The \"#/components//Booking\" reference value is not defined within the Components Object, "
+ "Location: #/paths/~1bookings/get/responses/200/content/application~1json/schema/items");
// 3-part reference with a valid type
// When it's a schema, this is technically a valid reference since almost any map is a valid schema with extra fields
assertNoMessage(server, " - Message: The \"#/components/schemas\" reference");
// When it's not a schema, we should get an error
assertMessage(server, " - Message: The \"#/components/schemas\" value is an invalid reference, "
+ "Location: #/paths/~1availability/get/parameters");

assertMessage(server, " - Message: The \"#/components/requestBodies/Pet\" reference value is not defined within the Components Object, "
+ "Location: #/paths/~1bookings/post/requestBody");
assertMessage(server, " - Message: The \"#/components/responses/Pet\" reference value is not defined within the Components Object,");
assertMessage(server, " - Message: The \"#/components/schemas/schemas\" reference value is not defined within the Components Object,");
assertMessage(server, " - Message: The \"#/components/schemas/Pet\" reference value is not defined within the Components Object,");
assertMessage(server, " - Message: The \"#/components/examples/Pet\" reference value is not defined within the Components Object, "
+ "Location: #/paths/~1reviews/post/requestBody/content/application~1json/examples/review");

// Valid references to something of the wrong type
assertMessage(server, " - Message: The \"#/components/schemas/Flight\" value is an invalid reference, "
+ "Location: #/paths/~1availability/get/parameters");
assertMessage(server, "The \"http://\\{\\}/#/test\" value is not a valid URI, Location: #/paths/~1availability/get/parameters");
}

@Test
public void testCallbacks() throws Exception {
assertMessage(server, " - Message: The URL template of Callback Object is empty and is not a valid URL, Location: #/paths/~1bookings/post/callbacks/getBookings");
assertMessage(server, " - Message: The Callback Object contains invalid substitution variables:*");
assertMessage(server, " - Message: The Callback Object must contain a valid runtime expression as defined in the OpenAPI Specification.*");
}

@Test
public void testPathItems() throws Exception {
assertMessage(server, " - Message: The Path Item Object must contain a valid path\\. "
+ "The \"DELETE\" operation of the \"/bookings/\\{id\\}\" path does not define a path parameter that is declared");
assertMessage(server, " - Message: The Path Item Object must contain a valid path\\. "
+ "The format of the \"http://localhost:9080/o\\{as3-ai\\{rl\\}ines/booking\" path is invalid");
assertMessage(server, " - Message: The Path Item Object must contain a valid path\\. "
+ "The \"GET\" operation from the \"/reviews/\\{airline\\}\" path defines a duplicated \"path\" parameter: \"airline\"");
assertMessage(server, " - Message: The Path Item Object must contain a valid path\\. "
+ "The \"PUT\" operation from the \"/reviews\" path defines one path parameter that is not declared: \"\\[id\\]\"");
assertMessage(server, 4, " - Message: The Path Item Object must contain a valid path.");
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*******************************************************************************
* Copyright (c) 2024 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package io.openliberty.microprofile.openapi40.fat.validation;

import static com.ibm.websphere.simplicity.ShrinkHelper.DeployOptions.SERVER_ONLY;
import static io.openliberty.microprofile.openapi40.fat.validation.ValidationTestUtils.assertNoMessage;

import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import com.ibm.websphere.simplicity.ShrinkHelper;

import componenttest.annotation.Server;
import componenttest.custom.junit.runner.FATRunner;
import componenttest.topology.impl.LibertyServer;

/**
* Validate main required elements being missing
* <p>
* Includes the tests from OpenAPIValidationTestThree, updated for OpenAPI v3.1
*/
@RunWith(FATRunner.class)
public class ValidationTestMissing {
private static final String SERVER_NAME = "OpenAPIValidationServer";

@Server(SERVER_NAME)
public static LibertyServer server;

@BeforeClass
public static void setup() throws Exception {
WebArchive war = ShrinkWrap.create(WebArchive.class, "validation-missing.war")
.addAsManifestResource(ValidationTestMissing.class.getPackage(), "validation-missing.yml", "openapi.yml");
ShrinkHelper.exportDropinAppToServer(server, war, SERVER_ONLY);

server.startServer();
}

@AfterClass
public static void shutdown() throws Exception {
server.stopServer();
}

@Test
public void testEmpty() throws Exception {
// Smallrye OpenAPI always generates an empty paths object and a minimal info object if there isn't one present
// This is explicitly valid: https://spec.openapis.org/oas/v3.1.0.html#paths-object
// This also means we can't actually hit the case where none of paths, components or webhooks are present
assertNoMessage(server, "CWWKO1650E"); // Assert no validation errors
assertNoMessage(server, "CWWKO1651W"); // Assert no validation warnings
}

}
Loading

0 comments on commit ae9f366

Please sign in to comment.