From af39db21ab115f6a42811a39660830aa94ec41b3 Mon Sep 17 00:00:00 2001 From: jayandran Date: Mon, 20 Apr 2020 21:41:56 +0530 Subject: [PATCH 1/3] Initial Commit for SchemaValidator from file --- .../swagger/test/JsonSchemaValidator.java | 40 ++++ .../SwaggerConsumerDrivenAssertTest.java | 39 +++- src/test/resources/invalidResponse.json | 6 + src/test/resources/swaggerContacts.json | 218 ++++++++++++++++++ src/test/resources/validResponse.json | 6 + 5 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java create mode 100644 src/test/resources/invalidResponse.json create mode 100644 src/test/resources/swaggerContacts.json create mode 100644 src/test/resources/validResponse.json diff --git a/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java new file mode 100644 index 0000000..0271ade --- /dev/null +++ b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java @@ -0,0 +1,40 @@ +package io.github.robwin.swagger.test; + +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.cfg.ValidationConfiguration; +import com.github.fge.jsonschema.core.exceptions.ProcessingException; +import com.github.fge.jsonschema.core.report.ListReportProvider; +import com.github.fge.jsonschema.core.report.LogLevel; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchema; +import com.github.fge.jsonschema.main.JsonSchemaFactory; + +import java.io.IOException; +import java.io.Reader; + +public class JsonSchemaValidator { + + private JsonNode schemaObj; + + public JsonSchemaValidator(Reader schemaSpec) throws IOException { + this.schemaObj = JsonLoader.fromReader(schemaSpec); + } + + public JsonSchemaFactory getSchemaFactory(final LogLevel logLevel, final LogLevel exceptionThreshold) { + return JsonSchemaFactory + .newBuilder() + .setValidationConfiguration(ValidationConfiguration.byDefault()) + .setReportProvider(new ListReportProvider(logLevel, exceptionThreshold)) + .freeze(); + } + + public ProcessingReport validateSchemaWithParams(String definition,JsonNode jsonNode) throws ProcessingException { + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.INFO, LogLevel.FATAL); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj,definition); + return jsonSchemaVal.validate(jsonNode); + } + + + +} diff --git a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java index 1fb6ce9..eb57fad 100644 --- a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java +++ b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java @@ -18,13 +18,24 @@ */ package io.github.robwin.swagger; +import com.fasterxml.jackson.databind.JsonNode; +import com.github.fge.jackson.JsonLoader; +import com.github.fge.jsonschema.core.exceptions.ProcessingException; +import com.github.fge.jsonschema.core.report.LogLevel; +import com.github.fge.jsonschema.core.report.ProcessingReport; +import com.github.fge.jsonschema.main.JsonSchema; +import com.github.fge.jsonschema.main.JsonSchemaFactory; +import io.github.robwin.swagger.test.JsonSchemaValidator; import io.github.robwin.swagger.test.SwaggerAssert; import io.github.robwin.swagger.test.SwaggerAssertions; import io.swagger.parser.SwaggerParser; import org.apache.commons.lang3.Validate; +import org.junit.Assert; import org.junit.Test; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; public class SwaggerConsumerDrivenAssertTest { @@ -62,7 +73,7 @@ public void shouldFindDifferencesInInfo() { File implFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger.json").getPath()); File designFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger.yaml").getPath()); new SwaggerAssert(new SwaggerParser().read(implFirstSwaggerLocation.getAbsolutePath()), "/assertj-swagger-info.properties") - .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); } @Test(expected = AssertionError.class) @@ -117,7 +128,7 @@ public void shouldHandleExpectedPathsWithPrefix() { Validate.notNull(implFirstSwaggerLocation.getAbsolutePath(), "actualLocation must not be null!"); new SwaggerAssert(new SwaggerParser().read(implFirstSwaggerLocation.getAbsolutePath()), "/assertj-swagger-path-prefix.properties") - .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); } @Test @@ -146,7 +157,7 @@ public void shouldntFailWhenDesignHasNoDefinitionsButImplHasDefinitions() { File implFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger-pets-by-petId-without-get-and-post.json").getPath()); File designFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger-no-definitions.json").getPath()); SwaggerAssertions.assertThat(implFirstSwaggerLocation.getAbsolutePath()) - .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); } @Test(expected = AssertionError.class) @@ -168,7 +179,7 @@ public void shouldntFailWhenImplHasMoreOperationsOfSamePath() { File implFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger.json").getPath()); File designFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger-path-without-some-operations.json").getPath()); SwaggerAssertions.assertThat(implFirstSwaggerLocation.getAbsolutePath()) - .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); } @Test @@ -176,6 +187,24 @@ public void shouldPassWhenParameterDescriptionIsDifferent() { File implFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger.json").getPath()); File designFirstSwaggerLocation = new File(SwaggerConsumerDrivenAssertTest.class.getResource("/swagger-different-parameter-description.json").getPath()); SwaggerAssertions.assertThat(implFirstSwaggerLocation.getAbsolutePath()) - .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + .satisfiesContract(designFirstSwaggerLocation.getAbsolutePath()); + } + + @Test + public void performSchemaValidationWithValidResponse() throws IOException, ProcessingException { + String schema = "/swaggerContacts.json", definition = "/validResponse.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + ProcessingReport report = schemaValidator.validateSchemaWithParams("/definitions/Contacts", jsonNode); + Assert.assertTrue(report.isSuccess()); + } + + @Test + public void performSchemaValidationWithInvalidResponse() throws IOException, ProcessingException { + String schema = "/swaggerContacts.json", definition = "/invalidResponse.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + ProcessingReport report = schemaValidator.validateSchemaWithParams("/definitions/Contacts", jsonNode); + Assert.assertTrue(report.isSuccess()); } } diff --git a/src/test/resources/invalidResponse.json b/src/test/resources/invalidResponse.json new file mode 100644 index 0000000..147273b --- /dev/null +++ b/src/test/resources/invalidResponse.json @@ -0,0 +1,6 @@ +{ + "id": "1", + "firstName": "Samuel", + "LastName": "Sampath", + "emailID": "abc1@gmail.com" + } diff --git a/src/test/resources/swaggerContacts.json b/src/test/resources/swaggerContacts.json new file mode 100644 index 0000000..d758ba0 --- /dev/null +++ b/src/test/resources/swaggerContacts.json @@ -0,0 +1,218 @@ +{ + "swagger": "2.0", + "info": { + "description": "Api Documentation", + "version": "1.0", + "title": "Api Documentation", + "termsOfService": "urn:tos", + "contact": {}, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + }, + "host": "localhost:8080", + "basePath": "/", + "tags": [ + { + "name": "basic-error-controller", + "description": "Basic Error Controller" + }, + { + "name": "contacts", + "description": "Contacts" + }, + { + "name": "operation-handler", + "description": "Operation Handler" + }, + { + "name": "web-mvc-links-handler", + "description": "Web Mvc Links Handler" + } + ], + "paths": { + "/contacts": { + "get": { + "tags": [ + "contacts" + ], + "summary": "getAllEmployees", + "operationId": "getAllEmployeesUsingGET_1", + "produces": [ + "*/*" + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Contacts" + } + } + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden" + }, + "404": { + "description": "Not Found" + } + }, + "deprecated": false + } + } + }, + "definitions": { + "Contacts": { + "type": "object", + "properties": { + "emailID": { + "type": "string" + }, + "firstName": { + "type": "string" + }, + "id": { + "type": "integer", + "format": "int64" + }, + "lastName": { + "type": "string" + } + }, + "title": "Contacts" + }, + "Link": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "templated": { + "type": "boolean" + } + }, + "title": "Link" + }, + "Map«string,Link»": { + "type": "object", + "title": "Map«string,Link»", + "additionalProperties": { + "$ref": "#/definitions/Link" + } + }, + "ModelAndView": { + "type": "object", + "properties": { + "empty": { + "type": "boolean" + }, + "model": { + "type": "object" + }, + "modelMap": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "reference": { + "type": "boolean" + }, + "status": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "view": { + "$ref": "#/definitions/View" + }, + "viewName": { + "type": "string" + } + }, + "title": "ModelAndView" + }, + "View": { + "type": "object", + "properties": { + "contentType": { + "type": "string" + } + }, + "title": "View" + } + } +} diff --git a/src/test/resources/validResponse.json b/src/test/resources/validResponse.json new file mode 100644 index 0000000..a8b40ca --- /dev/null +++ b/src/test/resources/validResponse.json @@ -0,0 +1,6 @@ +{ + "id": 1, + "firstName": "Samuel", + "LastName": "Sampath", + "emailID": "abc1@gmail.com" + } From 5fb2e28f5881d953a7a62684adb55305879e2a7b Mon Sep 17 00:00:00 2001 From: jayandran Date: Fri, 24 Apr 2020 00:02:19 +0530 Subject: [PATCH 2/3] Updated tested to validate --- .../swagger/SwaggerConsumerDrivenAssertTest.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java index eb57fad..948b669 100644 --- a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java +++ b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java @@ -30,12 +30,20 @@ import io.github.robwin.swagger.test.SwaggerAssertions; import io.swagger.parser.SwaggerParser; import org.apache.commons.lang3.Validate; +import org.apache.http.HttpEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.junit.Assert; import org.junit.Test; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; +import java.net.URL; public class SwaggerConsumerDrivenAssertTest { @@ -205,6 +213,7 @@ public void performSchemaValidationWithInvalidResponse() throws IOException, Pro JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); ProcessingReport report = schemaValidator.validateSchemaWithParams("/definitions/Contacts", jsonNode); - Assert.assertTrue(report.isSuccess()); + Assert.assertFalse(report.isSuccess()); } + } From 000e1a23e2f1b3998b7ea6f6ef3622cbf9725b9b Mon Sep 17 00:00:00 2001 From: jayandran Date: Sun, 24 May 2020 15:59:51 +0530 Subject: [PATCH 3/3] Added feature of response schema validation by providing path of the endpoint --- .../swagger/test/JsonSchemaValidator.java | 264 +++++++++++++++++- .../test/JsonSchemaValidatorException.java | 17 ++ .../SwaggerConsumerDrivenAssertTest.java | 89 ++++-- .../resources/InvalidResponseForPets.json | 20 ++ src/test/resources/greeting-schema.json | 27 ++ src/test/resources/validResponse.json | 10 +- src/test/resources/validResponseArray.json | 8 + src/test/resources/validResponseForPets.json | 20 ++ 8 files changed, 423 insertions(+), 32 deletions(-) create mode 100644 src/main/java/io/github/robwin/swagger/test/JsonSchemaValidatorException.java create mode 100644 src/test/resources/InvalidResponseForPets.json create mode 100644 src/test/resources/greeting-schema.json create mode 100644 src/test/resources/validResponseArray.json create mode 100644 src/test/resources/validResponseForPets.json diff --git a/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java index 0271ade..3425038 100644 --- a/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java +++ b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidator.java @@ -3,24 +3,64 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonLoader; import com.github.fge.jsonschema.cfg.ValidationConfiguration; -import com.github.fge.jsonschema.core.exceptions.ProcessingException; import com.github.fge.jsonschema.core.report.ListReportProvider; import com.github.fge.jsonschema.core.report.LogLevel; import com.github.fge.jsonschema.core.report.ProcessingReport; import com.github.fge.jsonschema.main.JsonSchema; import com.github.fge.jsonschema.main.JsonSchemaFactory; +import io.swagger.models.Response; +import io.swagger.models.Swagger; +import io.swagger.parser.SwaggerParser; +import io.swagger.util.Json; -import java.io.IOException; import java.io.Reader; +import java.util.Map; public class JsonSchemaValidator { private JsonNode schemaObj; + private Swagger actual; + + /** + * @param schemaSpec - io.Reader of schema + * @throws JsonSchemaValidatorException + */ + public JsonSchemaValidator(Reader schemaSpec) throws JsonSchemaValidatorException { + try { + validateNotNull(schemaSpec); + this.schemaObj = JsonLoader.fromReader(schemaSpec); + this.actual = new SwaggerParser().read(schemaObj); + }catch (NullPointerException nx){ + throw new JsonSchemaValidatorException("Schema Object cannot be null / empty"); + }catch (Exception e){ + throw new JsonSchemaValidatorException("Invalid Schema Object, Unable to create schema object"); + } + + } + + /** + * @param schemaSpec - String of schema + * @throws JsonSchemaValidatorException + */ + public JsonSchemaValidator(String schemaSpec) throws JsonSchemaValidatorException { + try { + validateNotNull(schemaSpec); + this.schemaObj = JsonLoader.fromString(schemaSpec); + this.actual = new SwaggerParser().read(schemaObj); + }catch (NullPointerException nx){ + throw new JsonSchemaValidatorException("Schema Object cannot be null / empty"); + }catch (Exception e){ + throw new JsonSchemaValidatorException("Invalid Schema Object, Unable to create schema object"); + } - public JsonSchemaValidator(Reader schemaSpec) throws IOException { - this.schemaObj = JsonLoader.fromReader(schemaSpec); } + /** + * @param logLevel + * @param exceptionThreshold + * + * @return - Javaschemafactory to validate schema + */ public JsonSchemaFactory getSchemaFactory(final LogLevel logLevel, final LogLevel exceptionThreshold) { return JsonSchemaFactory .newBuilder() @@ -29,12 +69,220 @@ public JsonSchemaFactory getSchemaFactory(final LogLevel logLevel, final LogLeve .freeze(); } - public ProcessingReport validateSchemaWithParams(String definition,JsonNode jsonNode) throws ProcessingException { - JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.INFO, LogLevel.FATAL); - JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj,definition); - return jsonSchemaVal.validate(jsonNode); + /** + * @return - Javaschemafactory to validate schema + */ + public JsonSchemaFactory getSchemaFactory() { + return JsonSchemaFactory.byDefault(); + } + + /** + * @param definition - Definition path in schema + * @param jsonNode - Response json node to validate against schema + * + * This method can be used if validation needs to be done directly with Definition + * @return + * @throws JsonSchemaValidatorException + */ + public Boolean validateSchemaWithDefinitionPath(String definition, JsonNode jsonNode) throws JsonSchemaValidatorException { + try { + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.ERROR, LogLevel.FATAL); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj, definition); + ProcessingReport report = jsonSchemaVal.validate(jsonNode); + if(report.isSuccess()){ + return true; + }else{ + System.err.println(report.toString()); + return false; + } + }catch (Exception e){ + throw new JsonSchemaValidatorException("Unable to get parse schema object for given parameter"); + } + } + + /** + * @param jsonNode - Response json node to validate against schema + * + * This method can be used if there is one to one schema mapping for each request + * + * @return + * @throws JsonSchemaValidatorException + */ + public Boolean validateSchema(JsonNode jsonNode) throws JsonSchemaValidatorException { + try{ + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.ERROR, LogLevel.FATAL); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj); + ProcessingReport report = jsonSchemaVal.validate(jsonNode); + if(report.isSuccess()){ + return true; + }else{ + System.err.println(report); + return false; + } + }catch (Exception e){ + throw new JsonSchemaValidatorException("Unable to get parse schema object for given parameter"); + } } + /** + * @param endPoint - Request endpoint to validate schema + * @param jsonNode - Response json node to validate against schema + * + * This method will extract Schema for given end point & request type [get] & response schema [200] and + * validate jsonNode value against schema provided + * + * @return - True / false + * @throws JsonSchemaValidatorException + */ + public Boolean validateSchema(String endPoint, JsonNode jsonNode) throws JsonSchemaValidatorException { + try{ + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.ERROR, LogLevel.FATAL); + schemaObj = JsonLoader.fromString(identifyResponseSchemaFromSwagger(endPoint, "get","200")); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj); + ProcessingReport report = jsonSchemaVal.validate(jsonNode); + if(report.isSuccess()){ + return true; + }else{ + System.err.println(report); + return false; + } + }catch (Exception e){ + throw new JsonSchemaValidatorException("Unable to get parse schema object for given parameter"); + } + + } + /** + * @param endPoint - Request endpoint to validate schema + * @param requestType - Request type [get,post,put,delete,patch] + * @param jsonNode - Response json node to validate against schema + * + * This method will extract Schema for given end point & requestType & response code [200] and + * validate jsonNode value against schema provided + * + * @return - True / False + * @throws JsonSchemaValidatorException + */ + public Boolean validateSchema(String endPoint, String requestType, JsonNode jsonNode) throws JsonSchemaValidatorException { + try{ + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.ERROR, LogLevel.FATAL); + schemaObj = JsonLoader.fromString(identifyResponseSchemaFromSwagger(endPoint, requestType, "200")); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj); + ProcessingReport report = jsonSchemaVal.validate(jsonNode); + if(report.isSuccess()){ + return true; + }else{ + System.err.println(report); + return false; + } + }catch (Exception e){ + throw new JsonSchemaValidatorException("Unable to get parse schema object for given parameter"); + } + } + + /** + * @param endPoint - Request endpoint to validate schema + * @param requestType - Request type [get,post,put,delete,patch] + * @param responseCode - Response code of schema [200,400 etc..] + * @param jsonNode - Response json node to validate against schema + * + * This method will extract Schema for given end point & requestType & responsecode and + * validate jsonNode value against schema provided + * @return + * @throws JsonSchemaValidatorException + */ + public Boolean validateSchema(String endPoint, String requestType, String responseCode, JsonNode jsonNode) throws JsonSchemaValidatorException { + try{ + JsonSchemaFactory schemaVal = getSchemaFactory(LogLevel.ERROR, LogLevel.FATAL); + schemaObj = JsonLoader.fromString(identifyResponseSchemaFromSwagger(endPoint, requestType, responseCode)); + JsonSchema jsonSchemaVal = schemaVal.getJsonSchema(schemaObj); + ProcessingReport report = jsonSchemaVal.validate(jsonNode); + if(report.isSuccess()){ + return true; + }else{ + System.err.println(report); + return false; + } + }catch (Exception e){ + throw new JsonSchemaValidatorException("Unable to get parse schema object for given parameter"); + } + + } + + /** + * @param schema - validate schema object/value as not null + */ + void validateNotNull(Object schema) { + if (schema == null) { + throw new NullPointerException("Schema Object cannot be null"); + }else if ((schema instanceof String) && (((String) schema).isEmpty() || schema == null)){ + throw new NullPointerException("Schema Object cannot be null"); + } + } + + /** + * @param endPoint - Request End Point to validate schema + * @param operation - Request Type of Schema [get,post,put,delete,patch] + * @return + * @throws JsonSchemaValidatorException + */ + String identifyResponseSchemaFromSwagger(String endPoint, String operation, String responseCode) throws JsonSchemaValidatorException { + try { + Map sr; + String jsonResponse; + switch (operation.toLowerCase()) { + case "get": + sr = actual.getPath(endPoint).getGet().getResponses(); + break; + + case "post": + sr = actual.getPath(endPoint).getPost().getResponses(); + break; + + case "put": + sr = actual.getPath(endPoint).getPut().getResponses(); + break; + + case "delete": + sr = actual.getPath(endPoint).getDelete().getResponses(); + break; + + case "patch": + sr = actual.getPath(endPoint).getPatch().getResponses(); + break; + + default: + sr = null; + System.err.println("Invalid Request Type : "+operation); + throw new JsonSchemaValidatorException("Invalid Request Type "); + + } + jsonResponse = Json.pretty(sr.get(responseCode).getResponseSchema()); + if (jsonResponse.contains("#")) { + jsonResponse = getDefinition(jsonResponse); + } + return jsonResponse; + }catch (Exception e){ + System.err.println("Unable to get response schema object with given parameter"); + throw new JsonSchemaValidatorException("Unable to get response schema object for given parameter"); + } + + } + + /** + * @param jsonResponse + * @return Schema add all definitions to solve reference issue + * @throws JsonSchemaValidatorException + */ + public String getDefinition(String jsonResponse) throws JsonSchemaValidatorException { + try { + String sr = "\"definitions\" : " + Json.pretty(actual.getDefinitions()) + ","; + jsonResponse = jsonResponse.replace("{", "{\n" + sr); + return jsonResponse; + }catch (Exception e){ + System.err.println("Unable to get definition from schema"); + throw new JsonSchemaValidatorException("Unable to get definition from schema"); + } + } } diff --git a/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidatorException.java b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidatorException.java new file mode 100644 index 0000000..854b74b --- /dev/null +++ b/src/main/java/io/github/robwin/swagger/test/JsonSchemaValidatorException.java @@ -0,0 +1,17 @@ +package io.github.robwin.swagger.test; + +public class JsonSchemaValidatorException extends Exception { + @Override + public String toString() { + return "JsonSchemaValidatorException{" + + "exceptionMessage='" + exceptionMessage + '\'' + + '}'; + } + + String exceptionMessage; + + public JsonSchemaValidatorException(String message){ + exceptionMessage = message; + } + +} diff --git a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java index 948b669..3896e4e 100644 --- a/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java +++ b/src/test/java/io/github/robwin/swagger/SwaggerConsumerDrivenAssertTest.java @@ -20,30 +20,18 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.fge.jackson.JsonLoader; -import com.github.fge.jsonschema.core.exceptions.ProcessingException; -import com.github.fge.jsonschema.core.report.LogLevel; -import com.github.fge.jsonschema.core.report.ProcessingReport; -import com.github.fge.jsonschema.main.JsonSchema; -import com.github.fge.jsonschema.main.JsonSchemaFactory; import io.github.robwin.swagger.test.JsonSchemaValidator; +import io.github.robwin.swagger.test.JsonSchemaValidatorException; import io.github.robwin.swagger.test.SwaggerAssert; import io.github.robwin.swagger.test.SwaggerAssertions; import io.swagger.parser.SwaggerParser; import org.apache.commons.lang3.Validate; -import org.apache.http.HttpEntity; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; import org.junit.Assert; import org.junit.Test; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.net.URL; public class SwaggerConsumerDrivenAssertTest { @@ -199,21 +187,84 @@ public void shouldPassWhenParameterDescriptionIsDifferent() { } @Test - public void performSchemaValidationWithValidResponse() throws IOException, ProcessingException { + public void performSchemaValidationWithValidResponse() throws IOException, JsonSchemaValidatorException { String schema = "/swaggerContacts.json", definition = "/validResponse.json"; JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); - ProcessingReport report = schemaValidator.validateSchemaWithParams("/definitions/Contacts", jsonNode); - Assert.assertTrue(report.isSuccess()); + Boolean report = schemaValidator.validateSchemaWithDefinitionPath("/definitions/Contacts", jsonNode); + Assert.assertTrue(report); } @Test - public void performSchemaValidationWithInvalidResponse() throws IOException, ProcessingException { + public void performSchemaValidationWithInvalidResponse() throws IOException, JsonSchemaValidatorException { String schema = "/swaggerContacts.json", definition = "/invalidResponse.json"; JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); - ProcessingReport report = schemaValidator.validateSchemaWithParams("/definitions/Contacts", jsonNode); - Assert.assertFalse(report.isSuccess()); + Boolean report = schemaValidator.validateSchemaWithDefinitionPath("/definitions/Contacts", jsonNode); + Assert.assertFalse(report); + + } + + @Test + public void performSchemaValidation() throws IOException, JsonSchemaValidatorException { + + String greetingJson = "{\n" + + " \"greeting\": {\n" + + " \"firstName\": \"Doe\",\n" + + " \"lastName\": \"Doe\"\n" + + " }\n" + + "}"; + String schema = "/greeting-schema.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromString(greetingJson); + Boolean report = schemaValidator.validateSchema(jsonNode); + Assert.assertTrue(report); + + } + + @Test + public void performSchemaValidationWithEndPoint() throws IOException, JsonSchemaValidatorException { + String schema = "/swaggerContacts.json", definition = "/validResponseArray.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + Boolean report = schemaValidator.validateSchema("/contacts", jsonNode); + Assert.assertTrue(report); + } + + @Test + public void performSchemaValidationUsingEndPointForInvalidResponse() throws IOException,JsonSchemaValidatorException { + String schema = "/swagger.json", definition = "/InvalidResponseForPets.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + Boolean bool = schemaValidator.validateSchema("/pets/findByStatus", jsonNode); + Assert.assertFalse(bool); + } + + @Test + public void performSchemaValidationWithEndPointHavingMultipleRef() throws IOException,JsonSchemaValidatorException { + String schema = "/swagger.json", definition = "/validResponseForPets.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + Boolean bool = schemaValidator.validateSchema("/pets/findByStatus", jsonNode); + Assert.assertTrue(bool); + } + + @Test + public void performSchemaValidationWithEndPointAndRequestType() throws IOException,JsonSchemaValidatorException { + String schema = "/swagger.json", definition = "/validResponseForPets.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + Boolean bool = schemaValidator.validateSchema("/pets/findByStatus", "get",jsonNode); + Assert.assertTrue(bool); + } + + @Test + public void performSchemaValidationWithEndPointRequestTypeResponseCode() throws IOException,JsonSchemaValidatorException { + String schema = "/swagger.json", definition = "/validResponseForPets.json"; + JsonSchemaValidator schemaValidator = new JsonSchemaValidator(new InputStreamReader(getClass().getResourceAsStream(schema))); + JsonNode jsonNode = JsonLoader.fromReader(new InputStreamReader(getClass().getResourceAsStream(definition))); + Boolean bool = schemaValidator.validateSchema("/pets/findByStatus", "get","200",jsonNode); + Assert.assertTrue(bool); } } diff --git a/src/test/resources/InvalidResponseForPets.json b/src/test/resources/InvalidResponseForPets.json new file mode 100644 index 0000000..2c7db61 --- /dev/null +++ b/src/test/resources/InvalidResponseForPets.json @@ -0,0 +1,20 @@ +[ + { + "id": "0", + "category": { + "id": 0, + "name": "tester1" + }, + "name": null, + "photoUrls": [ + "abccccc" + ], + "tags": [ + { + "id": 0, + "name": "string" + } + ], + "status": "available" + } +] diff --git a/src/test/resources/greeting-schema.json b/src/test/resources/greeting-schema.json new file mode 100644 index 0000000..4d3d321 --- /dev/null +++ b/src/test/resources/greeting-schema.json @@ -0,0 +1,27 @@ +{ + "type": "object", + "$schema": "http://json-schema.org/draft-03/schema", + "title": "Greeting", + "description": "Will greet you", + "id": "http://jsonschema.net", + "required": true, + "properties": { + "greeting": { + "type": "object", + "id": "http://jsonschema.net/greeting", + "required": true, + "properties": { + "firstName": { + "type": "string", + "id": "http://jsonschema.net/greeting/firstName", + "required": true + }, + "lastName": { + "type": "string", + "id": "http://jsonschema.net/greeting/lastName", + "required": true + } + } + } + } +} diff --git a/src/test/resources/validResponse.json b/src/test/resources/validResponse.json index a8b40ca..8954218 100644 --- a/src/test/resources/validResponse.json +++ b/src/test/resources/validResponse.json @@ -1,6 +1,6 @@ { - "id": 1, - "firstName": "Samuel", - "LastName": "Sampath", - "emailID": "abc1@gmail.com" - } + "id": 1, + "firstName": "Samuel", + "lastName": "Sampath", + "emailID": "abc1@gmail.com" +} diff --git a/src/test/resources/validResponseArray.json b/src/test/resources/validResponseArray.json new file mode 100644 index 0000000..7fc1e90 --- /dev/null +++ b/src/test/resources/validResponseArray.json @@ -0,0 +1,8 @@ +[ + { + "id": 1, + "firstName": "Samuel", + "lastName": "Sampath", + "emailID": "abc1@gmail.com" + } +] diff --git a/src/test/resources/validResponseForPets.json b/src/test/resources/validResponseForPets.json new file mode 100644 index 0000000..689d220 --- /dev/null +++ b/src/test/resources/validResponseForPets.json @@ -0,0 +1,20 @@ +[ + { + "id": 0, + "category": { + "id": 0, + "name": "tester1" + }, + "name": "doggie", + "photoUrls": [ + "abccccc" + ], + "tags": [ + { + "id": 0, + "name": "string" + } + ], + "status": "available" + } +]