diff --git a/.gitignore b/.gitignore index 623cefc..3734eca 100644 --- a/.gitignore +++ b/.gitignore @@ -21,7 +21,6 @@ *.tar.gz *.rar *.har -*.json # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/NST/src/main/java/com/ebay/nst/schema/validation/OpenApiSchemaValidator.java b/NST/src/main/java/com/ebay/nst/schema/validation/OpenApiSchemaValidator.java index 7eb3cfd..3026464 100644 --- a/NST/src/main/java/com/ebay/nst/schema/validation/OpenApiSchemaValidator.java +++ b/NST/src/main/java/com/ebay/nst/schema/validation/OpenApiSchemaValidator.java @@ -5,6 +5,8 @@ import com.ebay.nst.schema.validation.support.SchemaValidatorUtil; import com.ebay.openapi.export.jsonschema.OpenApiToJsonSchema; import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.v3.parser.core.models.ParseOptions; + import java.util.Objects; /** @@ -51,6 +53,7 @@ public boolean getValue() { private final boolean allowAdditionalProperties; private final StatusCode statusCode; private final Payload payload; + private final ParseOptions parseOptions; /** * Initialize the OpenAPI validator with the following values. @@ -62,7 +65,7 @@ public boolean getValue() { * @param requestMethod Request method to apply from the schema definition. * @param allowAdditionalProperties Allow properties which are not in the schema definition */ - private OpenApiSchemaValidator(String schemaResourcePath, String schemaPath, NstRequestType requestMethod, AllowAdditionalProperties allowAdditionalProperties, Payload payload, StatusCode statusCode) { + private OpenApiSchemaValidator(String schemaResourcePath, String schemaPath, NstRequestType requestMethod, AllowAdditionalProperties allowAdditionalProperties, Payload payload, StatusCode statusCode, ParseOptions parseOptions) { this.schemaResourcePath = Objects.requireNonNull(schemaResourcePath, "Schema resource path cannot be null."); this.schemaPath = Objects.requireNonNull(schemaPath, "Schema path cannot be null."); this.requestMethod = Objects.requireNonNull(requestMethod, "Request method cannot be null."); @@ -73,13 +76,14 @@ private OpenApiSchemaValidator(String schemaResourcePath, String schemaPath, Nst } this.payload = payload; this.statusCode = statusCode; + this.parseOptions = parseOptions; } @Override public void validate(String responseBody) throws SchemaValidationException { OpenApiToJsonSchema openApiToJsonSchema = new OpenApiToJsonSchema(schemaResourcePath, schemaPath, - requestMethod, allowAdditionalProperties, payload.getValue(), statusCode.getValue()); + requestMethod, allowAdditionalProperties, payload.getValue(), statusCode.getValue(), parseOptions); openApiToJsonSchema.convert(); JsonNode jsonSchema = openApiToJsonSchema.getJsonSchema(); @@ -102,6 +106,7 @@ public static class Builder { private AllowAdditionalProperties allowAdditionalProperties = AllowAdditionalProperties.YES; private Payload payload = Payload.RESPONSE; private StatusCode statusCode = StatusCode._200; + private ParseOptions parseOptions; public Builder(String schemaResourcePath, String schemaPath, NstRequestType requestMethod) { this.schemaResourcePath = Objects.requireNonNull(schemaResourcePath, "Schema resource path cannot be null."); @@ -144,6 +149,16 @@ public Builder setStatusCode(StatusCode statusCode) { return this; } + /** + * Set the swagger parsing options. See: https://github.com/swagger-api/swagger-parser/tree/master?tab=readme-ov-file#options + * @param parseOptions Parsing options to use. + * @return Builder instance. + */ + public Builder setParseOptions(ParseOptions parseOptions) { + this.parseOptions = parseOptions; + return this; + } + /** * Create a new OpenApiSchemaValidator instance based on the builder * configuration. @@ -152,7 +167,7 @@ public Builder setStatusCode(StatusCode statusCode) { */ public OpenApiSchemaValidator build() { return new OpenApiSchemaValidator(schemaResourcePath, schemaPath, requestMethod, allowAdditionalProperties, - payload, statusCode); + payload, statusCode, parseOptions); } } diff --git a/NST/src/main/java/com/ebay/openapi/export/jsonschema/OpenApiToJsonSchema.java b/NST/src/main/java/com/ebay/openapi/export/jsonschema/OpenApiToJsonSchema.java index 4d46c5c..0dccbc7 100644 --- a/NST/src/main/java/com/ebay/openapi/export/jsonschema/OpenApiToJsonSchema.java +++ b/NST/src/main/java/com/ebay/openapi/export/jsonschema/OpenApiToJsonSchema.java @@ -38,6 +38,7 @@ public class OpenApiToJsonSchema { private final List transformers; private final boolean useRequestModel; private final String statusCode; + private final ParseOptions parseOptions; /** * Convert an OpenAPI yaml spec to JSON schema. Call 'convert()' to begin the @@ -54,28 +55,37 @@ public class OpenApiToJsonSchema { * @param statusCode Response code to use. */ public OpenApiToJsonSchema(String openApiSpecFilePath, String requestPath, NstRequestType requestMethod, boolean allowAdditionalProperties, boolean useRequestModel, String statusCode) { - this.openApiSpecFilePath = openApiSpecFilePath; - this.requestPath = requestPath; - this.requestMethod = requestMethod; - this.allowAdditionalProperties = allowAdditionalProperties; - this.useRequestModel = useRequestModel; - this.statusCode = statusCode; - this.transformers = createTransformers(); + this(openApiSpecFilePath, requestPath, requestMethod, allowAdditionalProperties, useRequestModel, statusCode, new ParseOptions()); } /** * Convert an OpenAPI yaml spec to JSON schema. Call 'convert()' to begin the * operation. * - * @param openApiSpecFilePath Path to yaml spec to convert. - * @param requestPath The API request path to evaluate in the schema. - * @param requestMethod Request method corresponding to the requestPath to - * evaluate. - * @deprecated use {@link OpenApiToJsonSchema#OpenApiToJsonSchema(String, String, NstRequestType, boolean, boolean, String )}} + * @param openApiSpecFilePath Path to yaml spec to convert. + * @param requestPath The API request path to evaluate in the schema. + * @param requestMethod Request method corresponding to the requestPath to + * evaluate. + * @param allowAdditionalProperties when false, validation will fail if properties are + * present which are not defined in the schema + * @param useRequestModel True to use the request model path, false to use the + * response model path. + * @param statusCode Response code to use. + * @param parseOptions Swagger parsing options to use. */ - @Deprecated - public OpenApiToJsonSchema(String openApiSpecFilePath, String requestPath, NstRequestType requestMethod) { - this(openApiSpecFilePath, requestPath, requestMethod, true, false, "200"); + public OpenApiToJsonSchema(String openApiSpecFilePath, String requestPath, NstRequestType requestMethod, boolean allowAdditionalProperties, boolean useRequestModel, String statusCode, ParseOptions parseOptions) { + this.openApiSpecFilePath = openApiSpecFilePath; + this.requestPath = requestPath; + this.requestMethod = requestMethod; + this.allowAdditionalProperties = allowAdditionalProperties; + this.useRequestModel = useRequestModel; + this.statusCode = statusCode; + this.transformers = createTransformers(); + if (parseOptions != null) { + this.parseOptions = parseOptions; + } else { + this.parseOptions = new ParseOptions(); + } } /** @@ -107,9 +117,7 @@ public synchronized JsonNode getJsonSchema() { */ public void convert() { - // Parse the OpenAPI yaml - ParseOptions options = new ParseOptions(); - SwaggerParseResult parseResult = new OpenAPIV3Parser().readLocation(openApiSpecFilePath, null, options); + SwaggerParseResult parseResult = new OpenAPIV3Parser().readLocation(openApiSpecFilePath, null, parseOptions); if (parseResult == null || parseResult.getOpenAPI() == null) { throw new IllegalStateException("Unable to read yaml file from path: " + openApiSpecFilePath); } diff --git a/NST/src/test/java/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest.java b/NST/src/test/java/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest.java new file mode 100644 index 0000000..aeb7f50 --- /dev/null +++ b/NST/src/test/java/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest.java @@ -0,0 +1,88 @@ +package com.ebay.nst.schema.validation; + +import com.ebay.nst.NstRequestType; +import com.ebay.nst.schema.validation.support.SchemaValidationException; +import com.ebay.utility.ResourceParser; +import io.swagger.v3.parser.core.models.ParseOptions; +import org.testng.annotations.Test; + +public class OpenApiSchemaValidatorTest { + + @Test + public void schemaValidatePassWithRelativePathRefs() throws Exception { + + ParseOptions parseOptions = new ParseOptions(); + parseOptions.setResolve(true); + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/root.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO).setParseOptions(parseOptions) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json"); + + validator.validate(testResponsePayload); + } + + @Test + public void schemaValidatePassWithAllLocalReferences() throws Exception { + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentWithReferences.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json"); + + validator.validate(testResponsePayload); + } + + @Test + public void schemaValidatePassEverythingInline() throws Exception { + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentInlined.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json"); + + validator.validate(testResponsePayload); + } + + @Test(expectedExceptions = SchemaValidationException.class) + public void schemaValidateFailWithRelativePathRefs() throws Exception { + + ParseOptions parseOptions = new ParseOptions(); + parseOptions.setResolve(true); + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/root.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO).setParseOptions(parseOptions) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json"); + + validator.validate(testResponsePayload); + } + + @Test(expectedExceptions = SchemaValidationException.class) + public void schemaValidateFailWithAllLocalReferences() throws Exception { + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentWithReferences.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json"); + + validator.validate(testResponsePayload); + } + + @Test(expectedExceptions = SchemaValidationException.class) + public void schemaValidateFailEverythingInline() throws Exception { + + OpenApiSchemaValidator validator = new OpenApiSchemaValidator.Builder("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentInlined.yaml", "/test", NstRequestType.GET) + .allowAdditionalProperties(OpenApiSchemaValidator.AllowAdditionalProperties.NO) + .build(); + + String testResponsePayload = ResourceParser.readInResourceFile("/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json"); + + validator.validate(testResponsePayload); + } +} \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json new file mode 100644 index 0000000..69eff0c --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/invalidResponse.json @@ -0,0 +1,23 @@ +{ + "numberOfFruit": 100, + "typesOfApples": [ + { + "name": "Fuji", + "color": 1 + }, + { + "name": "Gala", + "color": "YELLOW" + } + ], + "typesOfBananas": [ + { + "name": "Big Yellow", + "color": "YELLOW" + }, + { + "name": "Old Brown", + "color": 2 + } + ] +} \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json new file mode 100644 index 0000000..ea48829 --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/json/validResponse.json @@ -0,0 +1,23 @@ +{ + "numberOfFruit": 100, + "typesOfApples": [ + { + "name": "Fuji", + "color": "RED" + }, + { + "name": "Gala", + "color": "YELLOW" + } + ], + "typesOfBananas": [ + { + "name": "Big Yellow", + "color": "YELLOW" + }, + { + "name": "Old Brown", + "color": "BROWN" + } + ] +} \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/root.yaml b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/root.yaml new file mode 100644 index 0000000..4787a10 --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/root.yaml @@ -0,0 +1,36 @@ +openapi: 3.0.0 +info: + title: Root Schema + description: >- + Root Schema + version: 1.0.0 +servers: + - url: 'http://ebay.com' + description: QATE +paths: + /test: + get: + summary: placeholder summary + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/TestResponse' +components: + schemas: + TestResponse: + type: object + properties: + numberOfFruit: + type: integer + format: int32 + typesOfApples: + type: array + items: + $ref: "types.yaml#/components/schemas/Apple" + typesOfBananas: + type: array + items: + $ref: "types.yaml#/components/schemas/Banana" \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentInlined.yaml b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentInlined.yaml new file mode 100644 index 0000000..93c9072 --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentInlined.yaml @@ -0,0 +1,54 @@ +openapi: 3.0.0 +info: + title: Root Schema + description: >- + Root Schema + version: 1.0.0 +servers: + - url: 'http://ebay.com' + description: QATE +paths: + /test: + get: + summary: placeholder summary + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/TestResponse' +components: + schemas: + TestResponse: + type: object + properties: + numberOfFruit: + type: integer + format: int32 + typesOfApples: + type: array + items: + type: object + properties: + name: + type: string + color: + type: string + enum: + - RED + - GREEN + - YELLOW + typesOfBananas: + type: array + items: + type: object + properties: + name: + type: string + color: + type: string + enum: + - YELLOW + - GREEN + - BROWN \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentWithReferences.yaml b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentWithReferences.yaml new file mode 100644 index 0000000..83fa5d6 --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/singleRootDocumentWithReferences.yaml @@ -0,0 +1,58 @@ +openapi: 3.0.0 +info: + title: Root Schema + description: >- + Root Schema + version: 1.0.0 +servers: + - url: 'http://ebay.com' + description: QATE +paths: + /test: + get: + summary: placeholder summary + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/TestResponse' +components: + schemas: + TestResponse: + type: object + properties: + numberOfFruit: + type: integer + format: int32 + typesOfApples: + type: array + items: + $ref: "#/components/schemas/Apple" + typesOfBananas: + type: array + items: + $ref: "#/components/schemas/Banana" + Apple: + type: object + properties: + name: + type: string + color: + type: string + enum: + - RED + - GREEN + - YELLOW + Banana: + type: object + properties: + name: + type: string + color: + type: string + enum: + - YELLOW + - GREEN + - BROWN \ No newline at end of file diff --git a/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/types.yaml b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/types.yaml new file mode 100644 index 0000000..aee1a63 --- /dev/null +++ b/NST/src/test/resources/com/ebay/nst/schema/validation/OpenApiSchemaValidatorTest/schema/types.yaml @@ -0,0 +1,44 @@ +openapi: 3.0.0 +info: + title: Type Definitions + description: >- + Type Definitions + version: 1.0.0 +servers: + - url: 'http://ebay.com' + description: QATE +paths: + /test: + get: + summary: placeholder summary + responses: + '200': + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Apple' +components: + schemas: + Apple: + type: object + properties: + name: + type: string + color: + type: string + enum: + - RED + - GREEN + - YELLOW + Banana: + type: object + properties: + name: + type: string + color: + type: string + enum: + - YELLOW + - GREEN + - BROWN \ No newline at end of file diff --git a/pom.xml b/pom.xml index 728bc88..a9c4a26 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 3.6.0 2.9 UTF-8 - 1.1.13 + 1.2.0 7.5 true