b/159709036 create pipeline's document base parser. Change-Id: Icc2999dfefd887547ae9dc86992b89213c9462a1
diff --git a/build.gradle b/build.gradle index 5d69eca..5b3649f 100644 --- a/build.gradle +++ b/build.gradle
@@ -36,6 +36,7 @@ // Test "junit": "4.13", // 22 June 2020 "mockito": "3.3.3", // 22 June 2020 + "assertj": "3.16.1", // 26 June 2020 // Command Line Utility Libraries "jcommander": "1.78", // 22 June 2020
diff --git a/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParser.java b/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParser.java index 9204695..c070896 100644 --- a/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParser.java +++ b/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParser.java
@@ -1,3 +1,15 @@ package com.apigee.security.oas.parser; -public class BaseParser {} +import java.io.File; +import java.net.URL; +import org.openapi4j.parser.model.v3.OpenApi3; + +/** Parses a {@linkplain File file} or {@link URL} into an {@code OpenApi3} object. */ +public interface BaseParser { + + /** Parses a valid OpenAPI Specification (v3) document from a {@link URL}. */ + OpenApi3 parse(URL url); + + /** Parses a valid OpenAPI Specification (v3) document from a {@linkplain File file}. */ + OpenApi3 parse(File specFile); +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParserModule.java b/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParserModule.java new file mode 100644 index 0000000..92c705e --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/parser/BaseParserModule.java
@@ -0,0 +1,19 @@ +package com.apigee.security.oas.parser; + +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import org.openapi4j.parser.OpenApi3Parser; + +/** Module with instructions for instantiating instances of {@code BaseParser}. */ +public final class BaseParserModule extends AbstractModule { + + @Override + protected void configure() { + bind(BaseParser.class).to(DefaultBaseParser.class); + } + + @Provides + OpenApi3Parser provideOpenApiForJavaOasParser() { + return new OpenApi3Parser(); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/parser/DefaultBaseParser.java b/oas-core/src/main/java/com/apigee/security/oas/parser/DefaultBaseParser.java new file mode 100644 index 0000000..f3404f9 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/parser/DefaultBaseParser.java
@@ -0,0 +1,44 @@ +package com.apigee.security.oas.parser; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import javax.inject.Inject; +import org.openapi4j.core.exception.ResolutionException; +import org.openapi4j.core.validation.ValidationException; +import org.openapi4j.parser.OpenApi3Parser; +import org.openapi4j.parser.model.v3.OpenApi3; + +/** Validates format of and parses an OpenAPI specification (v3) JSON or YAML document. */ +final class DefaultBaseParser implements BaseParser { + + private static final String PARSER_ERROR_MSG = "Failed to parse OAS document."; + private final OpenApi3Parser openApiParser; + + @Inject + DefaultBaseParser(OpenApi3Parser openApiParser) { + this.openApiParser = openApiParser; + } + + @Override + public OpenApi3 parse(URL url) { + checkNotNull(url); + try { + return openApiParser.parse(url, /* validate= */ true); + } catch (ResolutionException | ValidationException e) { + throw new ParserException(PARSER_ERROR_MSG, e); + } + } + + @Override + public OpenApi3 parse(File specFile) { + checkNotNull(specFile); + try { + return parse(specFile.toURI().toURL()); + } catch (MalformedURLException e) { + throw new ParserException(PARSER_ERROR_MSG, e); + } + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/parser/ParserException.java b/oas-core/src/main/java/com/apigee/security/oas/parser/ParserException.java new file mode 100644 index 0000000..601c41b --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/parser/ParserException.java
@@ -0,0 +1,11 @@ +package com.apigee.security.oas.parser; + +/** + * Exception thrown when an error has occurred while parsing and validating an OpenApi Specification + * document. + */ +public final class ParserException extends RuntimeException { + ParserException(String s, Exception childException) { + super(s, childException); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/parser/ParserModule.java b/oas-core/src/main/java/com/apigee/security/oas/parser/ParserModule.java new file mode 100644 index 0000000..4c7600a --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/parser/ParserModule.java
@@ -0,0 +1,12 @@ +package com.apigee.security.oas.parser; + +import com.google.inject.AbstractModule; + +/** Top level module that imports other Guice modules relied upon. */ +public final class ParserModule extends AbstractModule { + @Override + protected void configure() { + install(new BaseParserModule()); + binder().requireExplicitBindings(); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/parser/BaseParserTest.java b/oas-core/src/test/java/com/apigee/security/oas/parser/BaseParserTest.java deleted file mode 100644 index 9f28094..0000000 --- a/oas-core/src/test/java/com/apigee/security/oas/parser/BaseParserTest.java +++ /dev/null
@@ -1,3 +0,0 @@ -package com.apigee.security.oas.parser; - -public class BaseParserTest {}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/parser/DefaultBaseParserTest.java b/oas-core/src/test/java/com/apigee/security/oas/parser/DefaultBaseParserTest.java new file mode 100644 index 0000000..1c914ac --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/parser/DefaultBaseParserTest.java
@@ -0,0 +1,96 @@ +package com.apigee.security.oas.parser; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.ThrowableAssert.catchThrowable; + +import com.google.common.io.Resources; +import com.google.inject.Guice; +import java.io.File; +import java.net.URL; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.openapi4j.parser.model.v3.OpenApi3; + +@RunWith(JUnit4.class) +public class DefaultBaseParserTest { + private BaseParser defaultBaseParser; + + private URL validUrl; + private URL invalidUrl; + + private File validOasDocYaml; + private File validOasDocJson; + private File invalidOasDocYaml; + private File invalidOasDocJson; + + /** Sets up variables tests need. */ + @Before + public void setup() { + defaultBaseParser = Guice.createInjector(new ParserModule()).getInstance(BaseParser.class); + + URL validOasJsonUrl = Resources.getResource("Valid_OAS_v3.json"); + validOasDocJson = new File(validOasJsonUrl.getFile()); + URL validOasYamlUrl = Resources.getResource("Valid_OAS_v3.yaml"); + validOasDocYaml = new File(validOasYamlUrl.getFile()); + URL invalidOasYamlUrl = Resources.getResource("Invalid_OAS_v3.yaml"); + invalidOasDocYaml = new File(invalidOasYamlUrl.getFile()); + URL invalidOasJsonUrl = Resources.getResource("Invalid_OAS_v3.json"); + invalidOasDocJson = new File(invalidOasJsonUrl.getFile()); + + validUrl = validOasJsonUrl; + invalidUrl = invalidOasJsonUrl; + } + + @Test + public void parse_nullOasFile_throwsNullPointerException() { + assertThat(catchThrowable(() -> defaultBaseParser.parse((File) null))) + .isInstanceOf(NullPointerException.class); + } + + @Test + public void parse_nullOasUrl_throwsNullPointerException() { + assertThat(catchThrowable(() -> defaultBaseParser.parse((URL) null))) + .isInstanceOf(NullPointerException.class); + } + + @Test + public void parse_urlWithInvalidFormattedOas_throwsParserExceptionWithCause() { + assertThat(catchThrowable(() -> defaultBaseParser.parse(invalidUrl))) + .isInstanceOf(ParserException.class) + .getCause() + .isNotNull(); + } + + @Test + public void parse_jsonFileWithInvalidFormattedOas_throwsParserExceptionWithCause() { + assertThat(catchThrowable(() -> defaultBaseParser.parse(invalidOasDocJson))) + .isInstanceOf(ParserException.class) + .getCause() + .isNotNull(); + } + + @Test + public void parse_yamlFileWithInvalidFormattedOas_throwsParserExceptionWithCause() { + assertThat(catchThrowable(() -> defaultBaseParser.parse(invalidOasDocYaml))) + .isInstanceOf(ParserException.class) + .getCause() + .isNotNull(); + } + + @Test + public void parse_validOasYamlDoc_returnsOpenApiObject() { + assertThat(defaultBaseParser.parse(validOasDocYaml)).isInstanceOf(OpenApi3.class); + } + + @Test + public void parse_validOasJsonDoc_returnsOpenApiObject() { + assertThat(defaultBaseParser.parse(validOasDocJson)).isInstanceOf(OpenApi3.class); + } + + @Test + public void parse_validOasUrl_returnsOpenApiObject() { + assertThat(defaultBaseParser.parse(validUrl)).isInstanceOf(OpenApi3.class); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/parser/ParserModuleTest.java b/oas-core/src/test/java/com/apigee/security/oas/parser/ParserModuleTest.java new file mode 100644 index 0000000..79e3f4f --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/parser/ParserModuleTest.java
@@ -0,0 +1,21 @@ +package com.apigee.security.oas.parser; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.ThrowableAssert.catchThrowable; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ParserModuleTest { + @Test + public void createDefaultBaseParserShouldNotFail() { + Injector injector = Guice.createInjector(new ParserModule()); + + assertThat(catchThrowable(() -> injector.getInstance(BaseParser.class))) + .doesNotThrowAnyException(); + } +}
diff --git a/oas-core/src/test/resources/Invalid_OAS_v3.json b/oas-core/src/test/resources/Invalid_OAS_v3.json new file mode 100644 index 0000000..577cd49 --- /dev/null +++ b/oas-core/src/test/resources/Invalid_OAS_v3.json
@@ -0,0 +1,54 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Simple API overview", + "version": "2.0.0" + }, + "/": { + "paths": { + "summary": "List API versions", + "get": { + "operationId": "listVersionsv2", + "responses": { + "200": { + "description": "200 response", + "application/json": { + "content": { + "examples": { + "value": { + "foo": { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + } + } + } + } + } + } + } + } + } + } +}
diff --git a/oas-core/src/test/resources/Invalid_OAS_v3.yaml b/oas-core/src/test/resources/Invalid_OAS_v3.yaml new file mode 100644 index 0000000..a9f23ae --- /dev/null +++ b/oas-core/src/test/resources/Invalid_OAS_v3.yaml
@@ -0,0 +1,79 @@ +--- +openapi: "3.0.0" +info: + title: Simple API overview + version: 2.0.0 +summary: List API versions +paths: + /: + operationId: listVersionsv2 + get: + responses: + '200': + description: |- + 200 response + application/json: + content: + examples: + foo: + value: + { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + } + '300': + description: |- + 300 response + content: + application/json: + examples: + foo: + value: | + { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + }
diff --git a/oas-core/src/test/resources/Valid_OAS_v3.json b/oas-core/src/test/resources/Valid_OAS_v3.json new file mode 100644 index 0000000..1d40e7e --- /dev/null +++ b/oas-core/src/test/resources/Valid_OAS_v3.json
@@ -0,0 +1,54 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Simple API overview", + "version": "2.0.0" + }, + "paths": { + "/": { + "get": { + "operationId": "listVersionsv2", + "summary": "List API versions", + "responses": { + "200": { + "description": "200 response", + "content": { + "application/json": { + "examples": { + "foo": { + "value": { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + } + } + } + } + } + } + } + } + } + } +} \ No newline at end of file
diff --git a/oas-core/src/test/resources/Valid_OAS_v3.yaml b/oas-core/src/test/resources/Valid_OAS_v3.yaml new file mode 100644 index 0000000..d853ab6 --- /dev/null +++ b/oas-core/src/test/resources/Valid_OAS_v3.yaml
@@ -0,0 +1,79 @@ +--- +openapi: "3.0.0" +info: + title: Simple API overview + version: 2.0.0 +paths: + /: + get: + operationId: listVersionsv2 + summary: List API versions + responses: + '200': + description: |- + 200 response + content: + application/json: + examples: + foo: + value: + { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + } + '300': + description: |- + 300 response + content: + application/json: + examples: + foo: + value: | + { + "versions": [ + { + "status": "CURRENT", + "updated": "2011-01-21T11:33:21Z", + "id": "v2.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v2/", + "rel": "self" + } + ] + }, + { + "status": "EXPERIMENTAL", + "updated": "2013-07-23T11:33:21Z", + "id": "v3.0", + "links": [ + { + "href": "http://127.0.0.1:8774/v3/", + "rel": "self" + } + ] + } + ] + }
diff --git a/oas-test/build.gradle b/oas-test/build.gradle index 377662e..4324ede 100644 --- a/oas-test/build.gradle +++ b/oas-test/build.gradle
@@ -1,4 +1,9 @@ +plugins { + id 'java-library' +} + dependencies { - implementation "junit:junit:${libVersions.junit}" - implementation "org.mockito:mockito-core:${libVersions.mockito}" + api "junit:junit:${libVersions.junit}" + api "org.mockito:mockito-core:${libVersions.mockito}" + api "org.assertj:assertj-core:${libVersions.assertj}" } \ No newline at end of file