b/161148892 create extension value class and extension factory Change-Id: Ieffdf5dbb5ce547f424750598c410bdeda17bb7e
diff --git a/build.gradle b/build.gradle index 76a7207..dc3dcd7 100644 --- a/build.gradle +++ b/build.gradle
@@ -17,7 +17,7 @@ ext.libVersions = [ // Core Libraries "guava": "29.0-jre", // 22 June 2020 - "guice": "4.2.3", // 22 June 2020 + "guice": "4.2.3", // 22 June 2020, // Logging "flogger": "0.5.1", // 22 June 2020 @@ -85,11 +85,6 @@ implementation "com.google.guava:guava:${libVersions.guava}" implementation "com.google.inject:guice:${libVersions.guice}" implementation "commons-validator:commons-validator:${libVersions.apacheCommonsValidator}" - - //testCompile project(':oas-test') - - //testImplementation "junit:junit:${libVersions.junit}" - //testImplementation "org.mockito:mockito-core:${libVersions.mockito}" } checkstyle {
diff --git a/oas-core/build.gradle b/oas-core/build.gradle index 4556733..25acf9d 100644 --- a/oas-core/build.gradle +++ b/oas-core/build.gradle
@@ -1,6 +1,7 @@ dependencies { implementation "org.openapi4j:openapi-parser:${libVersions.openapiParser}" implementation "org.openapi4j:openapi-core:${libVersions.openapiCore}" + implementation "com.google.inject.extensions:guice-assistedinject:${libVersions.guice}" testImplementation project(":oas-test") } \ No newline at end of file
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java new file mode 100644 index 0000000..0526ba4 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/BaseExtension.java
@@ -0,0 +1,46 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableSet; +import com.google.errorprone.annotations.Var; +import com.google.inject.assistedinject.Assisted; +import javax.inject.Inject; +import org.openapi4j.parser.model.OpenApiSchema; + +/** Stores extensions information and validates the extension. */ +final class BaseExtension implements Extension { + private final String extensionName; + private final JsonNode extensionContent; + private final ImmutableSet<Class<? extends OpenApiSchema>> extensionPath; + + @Inject + BaseExtension( + @Var @Assisted String extensionName, + @Var @Assisted JsonNode extensionContent, + @Var @Assisted ImmutableSet<Class<? extends OpenApiSchema>> extensionPath) { + this.extensionName = extensionName; + this.extensionContent = extensionContent; + this.extensionPath = extensionPath; + } + + @Override + public JsonNode getExtensionContent() { + return extensionContent; + } + + @Override + public ImmutableSet<Class<? extends OpenApiSchema>> getExtensionPath() { + return extensionPath; + } + + @Override + public String getExtensionName() { + return extensionName; + } + + /** Validates the extension with given {@link ExtensionValidator}. */ + @Override + public boolean validate(@Var ExtensionValidator extensionValidator) { + return extensionValidator.validate(this); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java new file mode 100644 index 0000000..2451529 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModule.java
@@ -0,0 +1,14 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.google.inject.AbstractModule; + +/** + * An {@link AbstractModule} that installs all required bindings for the ExtendedValidator module. + */ +public class ExtendedValidatorMainModule extends AbstractModule { + @Override + protected void configure() { + install(new ExtensionModule()); + binder().requireExplicitBindings(); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java new file mode 100644 index 0000000..3428e2d --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/Extension.java
@@ -0,0 +1,24 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableSet; +import org.openapi4j.parser.model.OpenApiSchema; + +/** Stores details of and validates the extension. */ +public interface Extension { + + /** Validates the {@code Extension} with {@link ExtensionValidator}. */ + boolean validate(ExtensionValidator extensionValidator); + + /** Returns the content of the Extension. */ + JsonNode getExtensionContent(); + + /** + * Returns the path of {@link org.openapi4j.parser.model.OpenApiSchema} classes from the root + * node. + */ + ImmutableSet<Class<? extends OpenApiSchema>> getExtensionPath(); + + /** Returns the name of the Extension. */ + String getExtensionName(); +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java new file mode 100644 index 0000000..22d7b9b --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionFactory.java
@@ -0,0 +1,18 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.fasterxml.jackson.databind.JsonNode; +import com.google.common.collect.ImmutableSet; +import org.openapi4j.parser.model.OpenApiSchema; + +/** Factory to create an {@link Extension}. */ +public interface ExtensionFactory { + + /** + * Generates an {@link Extension} class object with {@code extensionContent} and {@code + * extensionPath} of the extension from {@code extensionName}. + */ + Extension create( + String extensionName, + JsonNode extensionContent, + ImmutableSet<Class<? extends OpenApiSchema>> extensionPath); +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java new file mode 100644 index 0000000..c595190 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionModule.java
@@ -0,0 +1,18 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.google.inject.AbstractModule; +import com.google.inject.assistedinject.FactoryModuleBuilder; + +/** + * Module with instructions for instantiating instances of {@link Extension} and building {@link + * ExtensionFactory}. + */ +public class ExtensionModule extends AbstractModule { + @Override + protected void configure() { + install( + new FactoryModuleBuilder() + .implement(Extension.class, BaseExtension.class) + .build(ExtensionFactory.class)); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java new file mode 100644 index 0000000..cacee5a --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionName.java
@@ -0,0 +1,37 @@ +package com.apigee.security.oas.extendedvalidator; + +import com.google.common.base.Optional; +import com.google.errorprone.annotations.Var; + +/** Stores all the supported {@code x-security-*} extensions as constants. */ +enum ExtensionName { + X_SECURITY_TYPE("x-security-type"); + + private final String extensionName; + + ExtensionName(String extensionName) { + this.extensionName = extensionName; + } + + String getExtensionName() { + return extensionName; + } + + /** + * Returns an {@code Optional<ExtensionName>} from an extension name. + * + * <p>The method will return an empty {@code Optional} if the extensionName is not found, and an + * {@link ExtensionName} if extensionName is found. + * + * @param extensionName The name of the extension in OpenApi3 Specification. + */ + static Optional<ExtensionName> valueOfExtensionName(String extensionName) { + @Var ExtensionName extensionEnum = null; + for (ExtensionName extension : values()) { + if (extension.extensionName.equals(extensionName)) { + extensionEnum = extension; + } + } + return Optional.fromNullable(extensionEnum); + } +}
diff --git a/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java new file mode 100644 index 0000000..d944371 --- /dev/null +++ b/oas-core/src/main/java/com/apigee/security/oas/extendedvalidator/ExtensionValidator.java
@@ -0,0 +1,8 @@ +package com.apigee.security.oas.extendedvalidator; + +/** Validates a {@link Extension} based on the type of {@code Extension}. */ +public interface ExtensionValidator { + + /** Validates a {@link Extension}. */ + boolean validate(Extension extension); +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java new file mode 100644 index 0000000..02d9b05 --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/BaseExtensionTest.java
@@ -0,0 +1,77 @@ +package com.apigee.security.oas.extendedvalidator; + +import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.openapi4j.parser.model.OpenApiSchema; +import org.openapi4j.parser.model.v3.Operation; +import org.openapi4j.parser.model.v3.Path; + +@RunWith(JUnit4.class) +public class BaseExtensionTest { + + @Rule public final MockitoRule rule = MockitoJUnit.rule(); + private static final ObjectMapper mapper = new ObjectMapper(); + private static final ExtensionFactory factory = + Guice.createInjector(new ExtensionModule()).getInstance(ExtensionFactory.class); + + private JsonNode node; + private Extension extension; + private ImmutableSet<Class<? extends OpenApiSchema>> extensionPath; + @Mock private ExtensionValidator extensionValidator; + + /** Setting up an {@link Extension} using {@link ExtensionFactory}. */ + @Before + public void setup() { + node = mapper.valueToTree("[]"); + extensionPath = ImmutableSet.copyOf(Arrays.asList(Path.class, Operation.class)); + extension = factory.create(X_SECURITY_TYPE.getExtensionName(), node, extensionPath); + } + + @Test + public void create_returnsExtension() { + assertThat(extension).isInstanceOf(Extension.class); + } + + @Test + public void validate_callsExtensionValidator() { + when(extensionValidator.validate(any(Extension.class))).thenReturn(true); + + boolean isValid = extension.validate(extensionValidator); + + assertThat(isValid).isTrue(); + verify(extensionValidator, atLeastOnce()).validate(any(Extension.class)); + } + + @Test + public void getExtensionName_returnsString() { + assertThat(extension.getExtensionName()).isEqualTo(X_SECURITY_TYPE.getExtensionName()); + } + + @Test + public void getExtensionPath_returnsImmutableSetInstance() { + assertThat(extension.getExtensionPath()).isEqualTo(extensionPath); + } + + @Test + public void getExtensionContent_returnsJsonNodeInstance() { + assertThat(extension.getExtensionContent()).isEqualTo(node); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java new file mode 100644 index 0000000..7c020e9 --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtendedValidatorMainModuleTest.java
@@ -0,0 +1,28 @@ +package com.apigee.security.oas.extendedvalidator; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ExtendedValidatorMainModuleTest { + private Injector injector; + + /** Sets up main module Guice {@link Injector}. */ + @Before + public void setup() { + injector = Guice.createInjector(new ExtendedValidatorMainModule()); + } + + @Test + public void createExtensionFactory_shouldNotFail() { + assertThat(catchThrowable(() -> injector.getInstance(ExtensionFactory.class))) + .doesNotThrowAnyException(); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java new file mode 100644 index 0000000..0216741 --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionFactoryTest.java
@@ -0,0 +1,49 @@ +package com.apigee.security.oas.extendedvalidator; + +import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE; +import static org.assertj.core.api.Assertions.assertThat; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Guice; +import com.google.inject.Injector; +import java.util.Arrays; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.openapi4j.parser.model.OpenApiSchema; +import org.openapi4j.parser.model.v3.Operation; +import org.openapi4j.parser.model.v3.Path; + +@RunWith(JUnit4.class) +public class ExtensionFactoryTest { + + private JsonNode node; + private ImmutableSet<Class<? extends OpenApiSchema>> extensionPath; + private ExtensionFactory factory; + + /** Setting up parameters and {@link ExtensionFactory} instance.. */ + @Before + public void setup() { + node = new ObjectMapper().valueToTree("[]"); + extensionPath = ImmutableSet.copyOf(Arrays.asList(Path.class, Operation.class)); + Injector injector = Guice.createInjector(new ExtensionModule()); + factory = injector.getInstance(ExtensionFactory.class); + } + + @Test + public void generateExtension_xSecurityExtensionName_returnsExtension() { + Extension extension = factory.create(X_SECURITY_TYPE.getExtensionName(), node, extensionPath); + + assertThat(extension).isInstanceOf(Extension.class); + } + + @Test + public void generateExtension_unsupportedExtensionName_returnsExtension() { + Extension extension = factory.create("x-unsupported", node, extensionPath); + + assertThat(extension).isInstanceOf(Extension.class); + } +}
diff --git a/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java new file mode 100644 index 0000000..4024b9d --- /dev/null +++ b/oas-core/src/test/java/com/apigee/security/oas/extendedvalidator/ExtensionNameTest.java
@@ -0,0 +1,32 @@ +package com.apigee.security.oas.extendedvalidator; + +import static com.apigee.security.oas.extendedvalidator.ExtensionName.X_SECURITY_TYPE; +import static com.apigee.security.oas.extendedvalidator.ExtensionName.valueOfExtensionName; +import static org.assertj.core.api.Assertions.assertThat; + +import com.google.common.base.Optional; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ExtensionNameTest { + + @Test + public void valueOfExtensionName_supportedExtension_returnsExtensionNameOptional() { + Optional<ExtensionName> extensionNameOptional = + valueOfExtensionName(X_SECURITY_TYPE.getExtensionName()); + + assertThat(extensionNameOptional.isPresent()).isTrue(); + assertThat(extensionNameOptional.get()) + .isInstanceOf(ExtensionName.class) + .isEqualTo(X_SECURITY_TYPE); + } + + @Test + public void valueOfExtensionName_unsupportedExtension_returnsEmptyOptional() { + Optional<ExtensionName> extensionNameOptional = valueOfExtensionName("x-unsupported"); + + assertThat(extensionNameOptional.isPresent()).isFalse(); + } +}