Skip to content

Commit

Permalink
Copy json schema and test vectors from tbdex submodule (#124)
Browse files Browse the repository at this point in the history
* Copy json schema and test vectors from tbdex submodule

* Update tbdex submodule to latest main

* Use http git url for .gitmodules

* WIP rewrite vector tests for new vector structure

* Remove unused private methods

* Translate external URIs to internal resource URIs

* Lint

* Flesh out tests and update README
  • Loading branch information
Diane Huxley authored Jan 12, 2024
1 parent bf5f0ae commit fe212cb
Show file tree
Hide file tree
Showing 25 changed files with 344 additions and 336 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies {

## JSON Schemas

the [tbdex]() repo acts as the source of truth for all json schemas. For this reason, The `tbdex` repo is a git
the [tbdex]() repo acts as the source of truth for all json schemas and test vectors. For this reason, the `tbdex` repo is a git
submodule
of this repo. By default, `git clone` does not actually check out the submodule's files. Using `--recurse-submodules`
option when cloning automatically initializes, fetches, and does a checkout of the appropriate commit for the submodule.
Expand All @@ -41,7 +41,7 @@ If you've already cloned the repo without `--recurse-submodules`, you can do the
git submodule update --init
```

copying the schemas into the procotol package's `resources` directory can be done by running `./gradlew syncSchemas`
copying the schemas and test vectors into the protocol package's `resources` directory can be done by running `./gradlew syncSchemas` and `./gradlew syncTestVectors` respectively.

# Other Docs

Expand Down
7 changes: 6 additions & 1 deletion protocol/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ dependencies {

tasks {
register("syncSchemas", Sync::class) {
from("../tbdex/json-schemas")
from("../tbdex/hosted/json-schemas")
into("./src/main/resources")
}

register("syncTestVectors", Sync::class) {
from("../tbdex/hosted/test-vectors/protocol/vectors")
into("./src/test/resources/test-vectors")
}
}

tasks.test {
Expand Down
19 changes: 17 additions & 2 deletions protocol/src/main/kotlin/tbdex/sdk/protocol/Validator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package tbdex.sdk.protocol
import com.fasterxml.jackson.databind.JsonNode
import com.networknt.schema.JsonSchema
import com.networknt.schema.JsonSchemaFactory
import com.networknt.schema.SchemaValidatorsConfig
import com.networknt.schema.SpecVersion
import tbdex.sdk.protocol.models.MessageKind
import tbdex.sdk.protocol.models.ResourceKind
import java.net.URI

/**
* Thrown by [Validator.validate].
Expand All @@ -19,15 +21,28 @@ class ValidatorException(message: String, val errors: List<String> = listOf()) :
*/
object Validator {
private val schemaMap = mutableMapOf<String, JsonSchema>()
private val config = SchemaValidatorsConfig()

/**
* Initializes the validator by loading schemas for messages and resources.
*/
init {
// Translate external URIs into internal resource URIs
config.addUriTranslator { uri: URI ->
val uriStr = uri.toString()
val prefix = "https://tbdex.dev/"
if (uriStr.startsWith(prefix)) {
val resourceName = uriStr.substring(prefix.length)
val resourceUri = object {}.javaClass.getResource("/$resourceName")?.toURI()
return@addUriTranslator resourceUri
}
return@addUriTranslator uri
}

val factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7)

val definitionsStream = object {}.javaClass.getResourceAsStream("/definitions.json")
factory.getSchema(definitionsStream)
factory.getSchema(definitionsStream, config)

val schemaNames = listOf("message" to "message.schema.json", "resource" to "resource.schema.json") +
MessageKind.entries.map { it.name to "${it.name}.schema.json" } +
Expand All @@ -36,7 +51,7 @@ object Validator {
for (schemaName in schemaNames) {
val (name, fileName) = schemaName
val schemaStream = object {}.javaClass.getResourceAsStream("/$fileName")
schemaMap[name] = factory.getSchema(schemaStream)
schemaMap[name] = factory.getSchema(schemaStream, config)
}
}

Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/close.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/close.schema.json",
"$id": "https://tbdex.dev/close.schema.json",
"type": "object",
"additionalProperties": false,
"properties": {
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/definitions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/definitions.json",
"$id": "https://tbdex.dev/definitions.json",
"type": "object",
"definitions": {
"did": {
Expand Down
43 changes: 0 additions & 43 deletions protocol/src/main/resources/index.html

This file was deleted.

4 changes: 2 additions & 2 deletions protocol/src/main/resources/message.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/message.schema.json",
"$id": "https://tbdex.dev/message.schema.json",
"definitions": {
"MessageMetadata": {
"type": "object",
Expand All @@ -10,7 +10,7 @@
"description": "The sender's DID"
},
"to": {
"$ref": "https://tbdex.dev/json-schemas/definitions.json#/definitions/did",
"$ref": "https://tbdex.dev/definitions.json#/definitions/did",
"description": "The recipient's DID"
},
"kind": {
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/offering.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/offering.schema.json",
"$id": "https://tbdex.dev/offering.schema.json",
"definitions": {
"CurrencyDetails": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/order.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/order.schema.json",
"$id": "https://tbdex.dev/order.schema.json",
"type": "object",
"additionalProperties": false,
"properties": {}
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/orderstatus.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/orderstatus.schema.json",
"$id": "https://tbdex.dev/orderstatus.schema.json",
"type": "object",
"required": [
"orderStatus"
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/quote.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/quote.schema.json",
"$id": "https://tbdex.dev/quote.schema.json",
"definitions": {
"QuoteDetails": {
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/reputation.schema.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/reputation.schema.json"
"$id": "https://tbdex.dev/reputation.schema.json"
}
4 changes: 2 additions & 2 deletions protocol/src/main/resources/resource.schema.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/resource.schema.json",
"$id": "https://tbdex.dev/resource.schema.json",
"type": "object",
"properties": {
"metadata": {
"type": "object",
"properties": {
"from": {
"$ref": "https://tbdex.dev/json-schemas/definitions.json#/definitions/did",
"$ref": "https://tbdex.dev/definitions.json#/definitions/did",
"description": "The PFI's DID"
},
"kind": {
Expand Down
2 changes: 1 addition & 1 deletion protocol/src/main/resources/rfq.schema.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://tbdex.dev/json-schemas/rfq.schema.json",
"$id": "https://tbdex.dev/rfq.schema.json",
"definitions": {
"SelectedPaymentMethod": {
"type": "object",
Expand Down
77 changes: 36 additions & 41 deletions protocol/src/test/kotlin/tbdex/sdk/protocol/MessagesVectorTest.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package tbdex.sdk.protocol

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.jupiter.api.Test
import tbdex.sdk.protocol.models.Close
import tbdex.sdk.protocol.models.Message
Expand All @@ -10,67 +13,59 @@ import tbdex.sdk.protocol.models.Rfq
import tbdex.sdk.protocol.serialization.Json
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull

class MessagesVectorTest {
@Test
fun `parse rfq`() {
testParsing<Rfq>(TestVectors.rfq())
fun `parse-close json`() {
val vector = TestVectors.getVector("parse-close.json")
assertNotNull(vector)
testNonErrorTestVector<Close>(vector)
}

@Test
fun `serialize rfq`() {
testSerialisation(TestVectors.rfq())
}
@Test
fun `parse quote`() {
testParsing<Quote>(TestVectors.quote())
fun `parse-order json`() {
val vector = TestVectors.getVector("parse-order.json")
assertNotNull(vector)
testNonErrorTestVector<Order>(vector)
}

@Test
fun `serialize quote`() {
testSerialisation(TestVectors.quote())
}
@Test
fun `parse order`() {
testParsing<Order>(TestVectors.order())
fun `parse-orderstatus json`() {
val vector = TestVectors.getVector("parse-orderstatus.json")
assertNotNull(vector)
testNonErrorTestVector<OrderStatus>(vector)
}

@Test
fun `serialize order`() {
testSerialisation(TestVectors.order())
}
@Test
fun `parse order status`() {
testParsing<OrderStatus>(TestVectors.orderStatus())
}

@Test
fun `serialize order status`() {
testSerialisation(TestVectors.orderStatus())
}
@Test
fun `parse close`() {
testParsing<Close>(TestVectors.close())
fun `parse-quote json`() {
val vector = TestVectors.getVector("parse-quote.json")
assertNotNull(vector)
testNonErrorTestVector<Quote>(vector)
}

@Test
fun `serialize close`() {
testSerialisation(TestVectors.close())
fun `parse-rfq json`() {
val vector = TestVectors.getVector("parse-rfq.json")
assertNotNull(vector)
testNonErrorTestVector<Rfq>(vector)
}

/**
* Test parse, validate, and verify on the [vectorString].
*/
private inline fun <reified T> testParsing(vectorString: String) {
val tbDEXMessage = Message.parse(vectorString)
assertIs<T>(tbDEXMessage)
}
private inline fun <reified T> testNonErrorTestVector(vector: JsonNode) {
val input = vector["input"].textValue()
assertNotNull(input)

private fun testSerialisation(original: String) {
val tbDEXMessage = Message.parse(original)
val serialized = Json.stringify(tbDEXMessage)
val tbDEXMessage = Message.parse(input)
assertIs<T>(tbDEXMessage)

assertEquals(original, serialized)
assertEquals(vector["output"], Json.jsonMapper.readTree(tbDEXMessage.toString()))
}

// When we create test vectors with `error: true`
// private fun testErrorTestVector(vector: JsonNode) {
// val input = vector["input"].textValue()
// assertNotNull(input)
// assertThrows(Message.parse(vector["input"])
// }
}
24 changes: 13 additions & 11 deletions protocol/src/test/kotlin/tbdex/sdk/protocol/ResourceVectorTest.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
package tbdex.sdk.protocol

import com.fasterxml.jackson.databind.JsonNode
import tbdex.sdk.protocol.models.Offering
import tbdex.sdk.protocol.models.Resource
import tbdex.sdk.protocol.serialization.Json
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertIs
import kotlin.test.assertNotNull

class ResourceVectorTest {
@Test
fun `parse offering`() {
val serializedOffering = TestVectors.offering()
val offering = Resource.parse(serializedOffering)
assertIs<Offering>(offering)
fun `parse-offering json`() {
val vector = TestVectors.getVector("parse-offering.json")
assertNotNull(vector)
testNonErrorTestVector<Offering>(vector)
}

@Test
fun `serialized offering matches original`() {
val serializedOffering = TestVectors.offering()
val offering = Resource.parse(serializedOffering)
val serializedOffering2 = Json.stringify(offering)
private inline fun <reified T> testNonErrorTestVector(vector: JsonNode) {
val input = vector["input"].textValue()
assertNotNull(input)

assertEquals(serializedOffering, serializedOffering2)
}
val tbDEXMessage = Resource.parse(input)
assertIs<T>(tbDEXMessage)

assertEquals(vector["output"], Json.jsonMapper.readTree(tbDEXMessage.toString()))
}
}
Loading

0 comments on commit fe212cb

Please sign in to comment.