Skip to content

Commit

Permalink
Switch from Medeia to NetworkNT Validator
Browse files Browse the repository at this point in the history
Signed-off-by: Simeon Widdis <sawiddis@amazon.com>
  • Loading branch information
Swiddis committed Mar 9, 2023
1 parent b675db2 commit 1731198
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 49 deletions.
10 changes: 5 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ dependencies {
implementation "org.opensearch:opensearch:${opensearch_version}"
implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:${kotlin_version}"
implementation "org.jetbrains.kotlin:kotlin-reflect:${kotlin_version}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9"
implementation "${group}:common-utils:${common_utils_version}"
implementation group: 'com.google.guava', name: 'guava', version: '31.0.1-jre'
Expand All @@ -199,12 +198,13 @@ dependencies {
// json-base, jackson-databind, jackson-annotations are only used by json-flattener.
// see https://github.com/opensearch-project/OpenSearch/issues/5395.
implementation group: 'com.github.wnameless.json', name: 'json-base', version: '2.2.1'
implementation "com.fasterxml.jackson.core:jackson-core:${jackson_version}"
implementation "com.fasterxml.jackson.core:jackson-databind:${jackson_version}"
implementation "com.fasterxml.jackson.core:jackson-annotations:${jackson_version}"
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:${jackson_version}"
implementation group: 'com.worldturner.medeia', name: 'medeia-validator-core', version: '1.1.1'
implementation group: 'com.worldturner.medeia', name: 'medeia-validator-jackson', version: '1.1.1'
// Forced dependency from json-schema-validator, we add nop to deactivate it
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.6'
implementation group: 'org.slf4j', name: 'slf4j-nop', version: '2.0.6'
implementation group: 'com.ethlo.time', name: 'itu', version: '1.7.0'
implementation group: 'com.networknt', name: 'json-schema-validator', version: '1.0.78'
compileOnly "${group}:opensearch-job-scheduler-spi:${job_scheduler_version}"
testImplementation(
'org.assertj:assertj-core:3.16.1',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
package org.opensearch.observability.validation

import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.worldturner.medeia.api.PathSchemaSource
import com.worldturner.medeia.api.ValidationFailedException
import com.worldturner.medeia.api.jackson.MedeiaJacksonApi
import com.worldturner.medeia.schema.validation.SchemaValidator
import org.opensearch.common.xcontent.DeprecationHandler
import org.opensearch.common.xcontent.NamedXContentRegistry
import org.opensearch.common.xcontent.XContentParser
import org.opensearch.common.xcontent.json.JsonXContent
import com.fasterxml.jackson.databind.ObjectMapper
import com.networknt.schema.JsonSchema
import com.networknt.schema.JsonSchemaFactory
import com.networknt.schema.SpecVersionDetector
import com.networknt.schema.ValidationResult
import org.opensearch.commons.utils.logger
import java.io.File
import java.io.FileNotFoundException
Expand All @@ -20,37 +14,23 @@ class Validator(val component: IntegrationComponent) {
private val log by logger(Validator::class.java)
}

private val medeiaApi = MedeiaJacksonApi()
private val mapper = ObjectMapper()

private fun loadComponentSchema(): SchemaValidator {
private fun loadComponentSchema(): JsonSchema {
val schemaFile = File(component.resourcePath)
if (!schemaFile.exists()) {
log.fatal("could not find schema '${schemaFile.path}' for component '$component'")
throw FileNotFoundException("could not find schema '${schemaFile.path}'")
}
val schemaSource = PathSchemaSource(schemaFile.toPath())
return medeiaApi.loadSchema(schemaSource)
val schemaSource = schemaFile.readText(Charsets.UTF_8)
val schemaNode = mapper.readTree(schemaSource)
val factory = JsonSchemaFactory.getInstance(SpecVersionDetector.detect(schemaNode))
return factory.getSchema(schemaNode)
}

fun validate(json: String): Result<XContentParser> {
return try {
val mapper = jacksonObjectMapper()
val medeia = medeiaApi.decorateJsonParser(
loadComponentSchema(),
mapper.createParser(json)
)
// Validation happens when tree is read
medeia.readValueAsTree<JsonNode>()
val xContentParser = JsonXContent.jsonXContent.createParser(
NamedXContentRegistry.EMPTY,
DeprecationHandler.THROW_UNSUPPORTED_OPERATION,
json
)
Result.success(xContentParser)
} catch (ex: JsonParseException) {
Result.failure(ex)
} catch (ex: ValidationFailedException) {
Result.failure(ex)
}
fun validate(json: String): ValidationResult {
val schema = loadComponentSchema()
val node = mapper.readTree(json)
return schema.validateAndCollect(node)
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.opensearch.observability.validation

import com.fasterxml.jackson.core.JsonParseException
import com.worldturner.medeia.api.ValidationFailedException
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import org.opensearch.common.Strings
import org.opensearch.common.xcontent.json.JsonXContent
import java.io.File
import kotlin.test.assertEquals

internal class ValidatorTests {
private fun buildIntegration(with: Map<String, Any> = mapOf(), without: Set<String> = setOf()): String {
Expand Down Expand Up @@ -44,7 +44,7 @@ internal class ValidatorTests {
val config = "{"
val validator = Validator(IntegrationComponent.INTEGRATION)
assertThrows<JsonParseException> {
validator.validate(config).getOrThrow()
validator.validate(config)
}
}

Expand All @@ -65,25 +65,21 @@ internal class ValidatorTests {
val sampleDir = component.resourcePath.substring(0, component.resourcePath.lastIndexOf("/")) + "/samples/"
val samplePath = sampleDir + sampleFiles[component]
val sampleJson = File(samplePath).readText(Charsets.UTF_8)
validator.validate(sampleJson).getOrThrow()
assertEquals(validator.validate(sampleJson).validationMessages.size, 0)
}
}

@Test
fun testValidatorMissingField() {
val config = buildIntegration(without = setOf("name"))
val validator = Validator(IntegrationComponent.INTEGRATION)
assertThrows<ValidationFailedException> {
validator.validate(config).getOrThrow()
}
assertEquals(validator.validate(config).validationMessages.size, 1)
}

@Test
fun testValidatorWrongFieldType() {
val config = buildIntegration(mapOf(Pair("name", 1)))
val validator = Validator(IntegrationComponent.INTEGRATION)
assertThrows<ValidationFailedException> {
validator.validate(config).getOrThrow()
}
assertEquals(validator.validate(config).validationMessages.size, 1)
}
}

0 comments on commit 1731198

Please sign in to comment.