Skip to content

Commit 4e3f267

Browse files
author
Ron Serruya
committed
Add tests for jsonschema
1 parent 5557900 commit 4e3f267

File tree

4 files changed

+187
-9
lines changed

4 files changed

+187
-9
lines changed

tests/integration/kafka/test_kafka_integration.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77

88
from aws_schema_registry import DataAndSchema, SchemaRegistryClient
99
from aws_schema_registry.avro import AvroSchema
10+
from aws_schema_registry.jsonschema import JsonSchema
1011
from aws_schema_registry.adapter.kafka import (
1112
KafkaDeserializer, KafkaSerializer
1213
)
13-
from aws_schema_registry.naming import record_name_strategy
14+
from aws_schema_registry.naming import (record_name_strategy,
15+
topic_name_strategy)
1416

1517
BOOTSTRAP_STRING = '127.0.0.1:9092'
1618

@@ -24,6 +26,8 @@
2426
SCHEMA_V1 = AvroSchema(f.read())
2527
with open(os.path.join(os.path.dirname(__file__), 'user.v2.avsc'), 'r') as f:
2628
SCHEMA_V2 = AvroSchema(f.read())
29+
with open(os.path.join(os.path.dirname(__file__), 'user.json'), 'r') as f:
30+
SCHEMA_JSON = JsonSchema(f.read())
2731

2832
PRODUCER_PROPERTIES = {
2933
'bootstrap_servers': BOOTSTRAP_STRING,
@@ -65,12 +69,25 @@ def test_produce_consume_with_ser_de_schema_registry(
6569
serializer = KafkaSerializer(
6670
client, schema_naming_strategy=record_name_strategy
6771
)
72+
73+
# jsonschema has no fqn, so we use topic_name_strategy for it
74+
# (which also requires a separate producer)
75+
json_serializer = KafkaSerializer(
76+
client, schema_naming_strategy=topic_name_strategy
77+
)
78+
6879
deserializer = KafkaDeserializer(client)
6980

7081
producer = KafkaProducer(
7182
value_serializer=serializer,
7283
**PRODUCER_PROPERTIES
7384
)
85+
86+
json_producer = KafkaProducer(
87+
value_serializer=json_serializer,
88+
**PRODUCER_PROPERTIES
89+
)
90+
7491
data1 = {
7592
'name': 'John Doe',
7693
'favorite_number': 6,
@@ -85,6 +102,13 @@ def test_produce_consume_with_ser_de_schema_registry(
85102
}
86103
producer.send(topic, DataAndSchema(data2, SCHEMA_V2))
87104

105+
data3 = {
106+
'name': 'John Doe',
107+
'favorite_number': 6,
108+
'favorite_colors': ['red', 'blue', "yello"]
109+
}
110+
json_producer.send(topic, DataAndSchema(data3, SCHEMA_JSON))
111+
88112
consumer = KafkaConsumer(
89113
topic,
90114
value_deserializer=deserializer,
@@ -93,8 +117,10 @@ def test_produce_consume_with_ser_de_schema_registry(
93117
batch = consumer.poll(timeout_ms=1000)
94118
assert len(batch) == 1
95119
messages = batch[list(batch.keys())[0]]
96-
assert len(messages) == 2
120+
assert len(messages) == 3
97121
assert messages[0].value.data == data1
98122
assert messages[0].value.schema == SCHEMA_V1
99123
assert messages[1].value.data == data2
100124
assert messages[1].value.schema == SCHEMA_V2
125+
assert messages[2].value.data == data3
126+
assert messages[2].value.schema == SCHEMA_JSON

tests/integration/kafka/user.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"type": "object",
4+
"properties": {
5+
"name": {
6+
"type": "string"
7+
},
8+
"favorite_number": {
9+
"type": "integer"
10+
},
11+
"favorite_colors": {
12+
"type": "array",
13+
"items": {
14+
"type": "string"
15+
}
16+
}
17+
},
18+
"required": [
19+
"name",
20+
"favorite_number",
21+
"favorite_colors"
22+
]
23+
}

tests/test_client.py

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,27 @@
1010

1111
REGISTRY_NAME = 'user-topic'
1212
SCHEMA_NAME = 'User-Topic'
13+
JSON_SCHEMA_NAME = 'User-Topic'
1314
SCHEMA_ARN = f'arn:aws:glue:us-west-2:123:schema/{REGISTRY_NAME}/{SCHEMA_NAME}'
1415
SCHEMA_VERSION_ID = UUID('b7b4a7f0-9c96-4e4a-a687-fb5de9ef0c63')
16+
JSON_SCHEMA_VERSION_ID = UUID('98718bb6-ca2a-4ac6-b841-748cab68b1b1')
1517
SCHEMA_DEF = '{"name": "Test", "type": "record", "fields": []}'
18+
JSON_SCHEMA_DEF = """{
19+
"$schema": "http://json-schema.org/draft-04/schema#",
20+
"type": "object",
21+
"properties": {
22+
"name": {
23+
"type": "string"
24+
},
25+
"age": {
26+
"type": "integer"
27+
}
28+
},
29+
"required": [
30+
"name",
31+
"age"
32+
]
33+
}"""
1634

1735
METADATA = {
1836
'event-source-1': 'topic1',
@@ -97,6 +115,23 @@ def test_get_or_register_schema_version_creates_schema(client, glue_client):
97115

98116
assert version.version_id == SCHEMA_VERSION_ID
99117

118+
glue_client.get_schema_version = Mock(return_value={
119+
'SchemaVersionId': str(SCHEMA_VERSION_ID),
120+
'SchemaDefinition': SCHEMA_DEF,
121+
'DataFormat': 'JSON',
122+
'SchemaArn': SCHEMA_ARN,
123+
'VersionNumber': 123,
124+
'Status': 'AVAILABLE'
125+
})
126+
127+
version = client.get_or_register_schema_version(
128+
definition=SCHEMA_DEF,
129+
schema_name=SCHEMA_NAME,
130+
data_format='JSON'
131+
)
132+
133+
assert version.version_id == SCHEMA_VERSION_ID
134+
100135

101136
def test_get_or_register_schema_version_registers_version(
102137
client, glue_client
@@ -128,16 +163,22 @@ def test_get_or_register_schema_version_registers_version(
128163
assert version.version_id == SCHEMA_VERSION_ID
129164

130165

131-
def test_register_schema_version(client, glue_client):
166+
@pytest.mark.parametrize(
167+
"schema_def,schema_name,schema_ver_id",
168+
[(SCHEMA_DEF, SCHEMA_NAME, SCHEMA_VERSION_ID),
169+
(JSON_SCHEMA_DEF, JSON_SCHEMA_NAME, JSON_SCHEMA_VERSION_ID)])
170+
def test_register_schema_version(client, glue_client,
171+
schema_name, schema_def, schema_ver_id):
172+
print(schema_name, schema_def, schema_ver_id)
132173
glue_client.register_schema_version = Mock(return_value={
133-
'SchemaVersionId': str(SCHEMA_VERSION_ID),
174+
'SchemaVersionId': str(schema_ver_id),
134175
'VersionNumber': 1,
135176
'Status': 'AVAILABLE'
136177
})
137178

138-
version_id = client.register_schema_version(SCHEMA_DEF, SCHEMA_NAME)
179+
version_id = client.register_schema_version(schema_def, schema_name)
139180

140-
assert version_id == SCHEMA_VERSION_ID
181+
assert version_id == schema_ver_id
141182

142183

143184
def test_wait_for_schema_evolution_check_to_complete(client, glue_client):
@@ -200,16 +241,17 @@ def _make_put_schema_version_metadata_response(
200241
}
201242

202243

203-
def test_create_schema(client, glue_client):
244+
@pytest.mark.parametrize("data_format", ["AVRO", "JSON"])
245+
def test_create_schema(client, glue_client, data_format):
204246
schema_version_id = uuid4()
205247
glue_client.create_schema = Mock(return_value={
206248
'SchemaName': SCHEMA_NAME,
207-
'DataFormat': 'AVRO',
249+
'DataFormat': data_format,
208250
'SchemaVersionId': str(schema_version_id)
209251
})
210252

211253
version_id = client.create_schema(
212-
SCHEMA_NAME, 'AVRO', SCHEMA_DEF
254+
SCHEMA_NAME, data_format, SCHEMA_DEF
213255
)
214256

215257
assert version_id == schema_version_id

tests/test_jsonschema.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import re
2+
import pytest
3+
4+
from aws_schema_registry import ValidationError
5+
from aws_schema_registry.jsonschema import JsonSchema
6+
7+
8+
def test_readwrite():
9+
s = JsonSchema("""{
10+
"$schema": "http://json-schema.org/draft-04/schema#",
11+
"type": "object",
12+
"properties": {
13+
"name": {
14+
"type": "string"
15+
},
16+
"age": {
17+
"type": "integer"
18+
}
19+
},
20+
"required": [
21+
"name",
22+
"age"
23+
]
24+
}""")
25+
26+
d = {
27+
'name': 'Yoda',
28+
'age': 900
29+
}
30+
31+
assert s.read(s.write(d)) == d
32+
33+
34+
def test_validation():
35+
s = JsonSchema("""{
36+
"$schema": "http://json-schema.org/draft-04/schema#",
37+
"type": "object",
38+
"properties": {
39+
"name": {
40+
"type": "string"
41+
},
42+
"age": {
43+
"type": "integer"
44+
}
45+
},
46+
"required": [
47+
"name",
48+
"age"
49+
]
50+
}""")
51+
52+
with pytest.raises(ValidationError, match=re.escape(
53+
"data must contain ['name', 'age'] properties"
54+
)):
55+
56+
s.validate({'name': 'Obi-Wan'})
57+
with pytest.raises(ValidationError, match=re.escape(
58+
"data.name must be string"
59+
)):
60+
61+
s.validate({'name': 1, 'age': 2})
62+
63+
s.validate({'name': 'Jar Jar', 'age': 42, 'sith': True})
64+
65+
s = JsonSchema("""{
66+
"$schema": "http://json-schema.org/draft-04/schema#",
67+
"type": "object",
68+
"properties": {
69+
"name": {
70+
"type": "string"
71+
},
72+
"age": {
73+
"type": "integer"
74+
}
75+
},
76+
"required": [
77+
"name",
78+
"age"
79+
],
80+
"additionalProperties": false
81+
}""")
82+
83+
with pytest.raises(ValidationError, match=re.escape(
84+
"data must not contain {'sith'} properties"
85+
)):
86+
87+
s.validate({'name': 'Jar Jar', 'age': 42, 'sith': True})

0 commit comments

Comments
 (0)