Skip to content

Commit 99e6942

Browse files
authored
Apply minor refactoring (#122)
* Handle error code 42201 in Registry storage * Reorganize Plain codec in-test fixtures * Return error on undefined reference lookup fun * Update wording in tests
1 parent 8e9bd41 commit 99e6942

File tree

5 files changed

+95
-84
lines changed

5 files changed

+95
-84
lines changed

lib/avrora/schema/encoder.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ defmodule Avrora.Schema.Encoder do
4848
An example of a reference lookup which returns empty JSON body
4949
"""
5050
@spec reference_lookup(String.t()) :: {:ok, String.t()} | {:error, term()}
51-
def reference_lookup(_), do: {:ok, ~s({})}
51+
def reference_lookup(_), do: {:error, :undefined_reference_lookup_function}
5252

5353
@doc """
5454
Convert `erlavro` format to the Schema struct.
@@ -160,6 +160,7 @@ defmodule Avrora.Schema.Encoder do
160160
defp do_parse(payload) do
161161
{:ok, :avro_json_decoder.decode_schema(payload, allow_bad_references: true)}
162162
rescue
163+
_ in FunctionClauseError -> {:error, :invalid_schema}
163164
error in ArgumentError -> {:error, error.message}
164165
error in ErlangError -> {:error, error.original}
165166
end

lib/avrora/storage/registry.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ defmodule Avrora.Storage.Registry do
168168
40401 -> :unknown_subject
169169
40402 -> :unknown_version
170170
40403 -> :unknown_schema
171+
42201 -> :invalid_schema
171172
409 -> :conflict
172173
422 -> :unprocessable
173174
_ -> payload

test/avrora/codec/plain_test.exs

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ defmodule Avrora.Codec.PlainTest do
6060
Avrora.Storage.RegistryMock
6161
|> expect(:put, fn key, value ->
6262
assert key == "io.acme.Payment"
63-
assert value == payment_json_schema()
63+
assert value == payment_json()
6464

6565
{:error, :unconfigured_registry_url}
6666
end)
@@ -80,13 +80,13 @@ defmodule Avrora.Codec.PlainTest do
8080
test "when payload is a valid binary and null values must be as is" do
8181
stub(Avrora.ConfigMock, :convert_null_values, fn -> false end)
8282

83-
{:ok, decoded} = Codec.Plain.decode(null_value_message(), schema: null_value_schema())
83+
{:ok, decoded} = Codec.Plain.decode(null_value_message(), schema: record_with_null_union_field_schema())
8484

8585
assert decoded == %{"key" => "user-1", "value" => :null}
8686
end
8787

8888
test "when payload is a valid binary and null values must be converted" do
89-
{:ok, decoded} = Codec.Plain.decode(null_value_message(), schema: null_value_schema())
89+
{:ok, decoded} = Codec.Plain.decode(null_value_message(), schema: record_with_null_union_field_schema())
9090

9191
assert decoded == %{"key" => "user-1", "value" => nil}
9292
end
@@ -114,8 +114,8 @@ defmodule Avrora.Codec.PlainTest do
114114
end
115115

116116
test "when payload is valid binary and union type must be decoded without decoding hook" do
117-
{:ok, decoded_int} = Codec.Plain.decode(<<2, 84>>, schema: union_schema())
118-
{:ok, decoded_str} = Codec.Plain.decode(<<0, 4, 52, 50>>, schema: union_schema())
117+
{:ok, decoded_int} = Codec.Plain.decode(<<2, 84>>, schema: record_with_record_union_field_schema())
118+
{:ok, decoded_str} = Codec.Plain.decode(<<0, 4, 52, 50>>, schema: record_with_record_union_field_schema())
119119

120120
assert decoded_int == %{"union_field" => %{"value" => 42}}
121121
assert decoded_str == %{"union_field" => %{"value" => "42"}}
@@ -129,8 +129,8 @@ defmodule Avrora.Codec.PlainTest do
129129
end
130130
end)
131131

132-
{:ok, decoded_int} = Codec.Plain.decode(<<2, 84>>, schema: union_schema())
133-
{:ok, decoded_str} = Codec.Plain.decode(<<0, 4, 52, 50>>, schema: union_schema())
132+
{:ok, decoded_int} = Codec.Plain.decode(<<2, 84>>, schema: record_with_record_union_field_schema())
133+
{:ok, decoded_str} = Codec.Plain.decode(<<0, 4, 52, 50>>, schema: record_with_record_union_field_schema())
134134

135135
assert decoded_int == %{"union_field" => {"io.acme.as_int", %{"value" => 42}}}
136136
assert decoded_str == %{"union_field" => {"io.acme.as_str", %{"value" => "42"}}}
@@ -171,7 +171,7 @@ defmodule Avrora.Codec.PlainTest do
171171
Avrora.Storage.RegistryMock
172172
|> expect(:put, fn key, value ->
173173
assert key == "io.acme.Payment"
174-
assert value == payment_json_schema()
174+
assert value == payment_json()
175175

176176
{:error, :unconfigured_registry_url}
177177
end)
@@ -207,7 +207,7 @@ defmodule Avrora.Codec.PlainTest do
207207
Avrora.Storage.RegistryMock
208208
|> expect(:put, fn key, value ->
209209
assert key == "io.acme.CardType"
210-
assert value == enum_json_schema()
210+
assert value == enum_json()
211211

212212
{:error, :unconfigured_registry_url}
213213
end)
@@ -243,7 +243,7 @@ defmodule Avrora.Codec.PlainTest do
243243
Avrora.Storage.RegistryMock
244244
|> expect(:put, fn key, value ->
245245
assert key == "io.acme.CRC32"
246-
assert value == fixed_json_schema()
246+
assert value == fixed_json()
247247

248248
{:error, :unconfigured_registry_url}
249249
end)
@@ -277,56 +277,56 @@ defmodule Avrora.Codec.PlainTest do
277277
defp payment_payload, do: %{"id" => "00000000-0000-0000-0000-000000000000", "amount" => 15.99}
278278

279279
defp payment_schema do
280-
{:ok, schema} = Schema.Encoder.from_json(payment_json_schema())
280+
{:ok, schema} = Schema.Encoder.from_json(payment_json())
281281
%{schema | id: nil, version: nil}
282282
end
283283

284-
defp null_value_schema do
285-
{:ok, schema} = Schema.Encoder.from_json(null_value_json_schema())
284+
defp record_with_null_union_field_schema do
285+
{:ok, schema} = Schema.Encoder.from_json(record_with_null_union_field_json())
286+
%{schema | id: nil, version: nil}
287+
end
288+
289+
defp record_with_record_union_field_schema do
290+
{:ok, schema} = Schema.Encoder.from_json(record_with_record_union_field_json())
286291
%{schema | id: nil, version: nil}
287292
end
288293

289294
defp map_schema do
290-
{:ok, schema} = Schema.Encoder.from_json(map_json_schema())
295+
{:ok, schema} = Schema.Encoder.from_json(record_with_map_field_json())
291296
%{schema | id: nil, version: nil}
292297
end
293298

294299
defp enum_schema do
295-
{:ok, schema} = Schema.Encoder.from_json(enum_json_schema())
300+
{:ok, schema} = Schema.Encoder.from_json(enum_json())
296301
%{schema | id: nil, version: nil}
297302
end
298303

299304
defp fixed_schema do
300-
{:ok, schema} = Schema.Encoder.from_json(fixed_json_schema())
305+
{:ok, schema} = Schema.Encoder.from_json(fixed_json())
301306
%{schema | id: nil, version: nil}
302307
end
303308

304-
defp union_schema do
305-
{:ok, schema} = Schema.Encoder.from_json(union_json_schema())
306-
%{schema | id: nil, version: nil}
309+
defp payment_json do
310+
~s({"namespace":"io.acme","name":"Payment","type":"record","fields":[{"name":"id","type":"string"},{"name":"amount","type":"double"}]})
307311
end
308312

309-
defp payment_json_schema do
310-
~s({"namespace":"io.acme","name":"Payment","type":"record","fields":[{"name":"id","type":"string"},{"name":"amount","type":"double"}]})
313+
defp record_with_null_union_field_json do
314+
~s({"namespace":"io.acme","name":"NullValue","type":"record","fields":[{"name":"key","type":"string"},{"name":"value","type":["null","int"]}]})
311315
end
312316

313-
defp null_value_json_schema do
314-
~s({"namespace":"io.acme","name":"Null_Value","type":"record","fields":[{"name":"key","type":"string"},{"name":"value","type":["null","int"]}]})
317+
defp record_with_record_union_field_json do
318+
~s({"namespace":"io.acme","name":"UnionValue","type":"record","fields":[{"name":"union_field","type":[{"type":"record","name":"as_str","fields":[{"name":"value","type":"string"}]},{"type":"record","name":"as_int","fields":[{"name":"value","type":"int"}]}]}]})
315319
end
316320

317-
defp map_json_schema do
318-
~s({"namespace":"io.acme","name":"Map_Value","type":"record","fields":[{"name":"map_field", "type": {"type": "map", "values": "string"}}]})
321+
defp record_with_map_field_json do
322+
~s({"namespace":"io.acme","name":"MapValue","type":"record","fields":[{"name":"map_field", "type": {"type": "map", "values": "string"}}]})
319323
end
320324

321-
defp enum_json_schema do
325+
defp enum_json do
322326
~s({"namespace":"io.acme","name":"CardType","type":"enum","symbols":["MASTERCARD","VISA","AMERICANEXPRESS"]})
323327
end
324328

325-
defp fixed_json_schema do
329+
defp fixed_json do
326330
~s({"namespace":"io.acme","name":"CRC32","type":"fixed","size":8})
327331
end
328-
329-
defp union_json_schema do
330-
~s({"namespace":"io.acme","name":"Union_Value","type":"record","fields":[{"name":"union_field","type":[{"type":"record","name":"as_str","fields":[{"name":"value","type":"string"}]},{"type":"record","name":"as_int","fields":[{"name":"value","type":"int"}]}]}]})
331-
end
332332
end

test/avrora/schema/encoder_test.exs

Lines changed: 48 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,54 +13,66 @@ defmodule Avrora.Schema.EncoderTest do
1313
{:ok, {type, _, _, _, _, fields, full_name, _}} = Schema.Encoder.to_erlavro(schema)
1414

1515
assert type == :avro_record_type
16-
assert full_name == "io.confluent.Payment"
16+
assert full_name == "io.acme.Payment"
1717
assert length(fields) == 2
1818

19-
assert schema.full_name == "io.confluent.Payment"
19+
assert schema.full_name == "io.acme.Payment"
2020
assert schema.json == payment_json()
2121
end
2222

23-
test "when payload is a valid Enum schema" do
23+
test "when schema is Enum type" do
2424
{:ok, schema} = Schema.Encoder.from_json(card_type_json())
2525
{:ok, {type, _, _, _, _, fields, full_name, _}} = Schema.Encoder.to_erlavro(schema)
2626

2727
assert type == :avro_enum_type
28-
assert full_name == "io.confluent.CardType"
28+
assert full_name == "io.acme.CardType"
2929
assert length(fields) == 3
3030

31-
assert schema.full_name == "io.confluent.CardType"
31+
assert schema.full_name == "io.acme.CardType"
3232
assert schema.json == card_type_json()
3333
end
3434

35-
test "when payload is a valid Fixed schema" do
35+
test "when payload is Fixed type" do
3636
{:ok, schema} = Schema.Encoder.from_json(crc32_json())
3737
{:ok, {type, _, _, _, value, full_name, _}} = Schema.Encoder.to_erlavro(schema)
3838

3939
assert type == :avro_fixed_type
40-
assert full_name == "io.confluent.CRC32"
40+
assert full_name == "io.acme.CRC32"
4141
assert value == 8
4242

43-
assert schema.full_name == "io.confluent.CRC32"
43+
assert schema.full_name == "io.acme.CRC32"
4444
assert schema.json == crc32_json()
4545
end
4646

47-
test "when payload is a valid json schema with external reference and callback returns valid schema" do
47+
test "when schema is Record type with primitive fields types" do
48+
{:ok, schema} = Schema.Encoder.from_json(payment_json())
49+
{:ok, {type, _, _, _, _, fields, full_name, _}} = Schema.Encoder.to_erlavro(schema)
50+
51+
assert type == :avro_record_type
52+
assert full_name == "io.acme.Payment"
53+
assert length(fields) == 2
54+
55+
assert schema.full_name == "io.acme.Payment"
56+
assert schema.json == payment_json()
57+
end
58+
59+
test "when schema is Record type with nested type ref" do
4860
{:ok, schema} =
4961
Schema.Encoder.from_json(message_with_reference_json(), fn name ->
5062
case name do
51-
"io.confluent.Attachment" -> {:ok, attachment_json()}
52-
"io.confluent.Signature" -> {:ok, signature_json()}
63+
"io.acme.Signature" -> {:ok, signature_json()}
64+
"io.acme.Attachment" -> {:ok, attachment_json()}
5365
_ -> raise "unknown reference name!"
5466
end
5567
end)
5668

5769
{:ok, {type, _, _, _, _, fields, full_name, _}} = Schema.Encoder.to_erlavro(schema)
5870

5971
assert type == :avro_record_type
60-
assert full_name == "io.confluent.Message"
72+
assert full_name == "io.acme.Message"
6173
assert length(fields) == 2
6274

63-
assert schema.full_name == "io.confluent.Message"
75+
assert schema.full_name == "io.acme.Message"
6476
assert schema.json == message_json()
6577

6678
{:avro_record_field, _, _, body_type, _, _, _} = List.first(fields)
@@ -70,48 +82,46 @@ defmodule Avrora.Schema.EncoderTest do
7082
{:avro_array_type, {type, _, _, _, _, fields, full_name, _}, []} = attachments_type
7183

7284
assert type == :avro_record_type
73-
assert full_name == "io.confluent.Attachment"
85+
assert full_name == "io.acme.Attachment"
7486
assert length(fields) == 2
7587

7688
{:avro_record_field, _, _, signature_type, _, _, _} = List.last(fields)
7789
{type, _, _, _, _, fields, full_name, _} = signature_type
7890

7991
assert type == :avro_record_type
80-
assert full_name == "io.confluent.Signature"
92+
assert full_name == "io.acme.Signature"
8193
assert length(fields) == 1
8294
end
8395

84-
test "when payload is a valid json schema with external reference and callback returns invalid schema" do
96+
test "when schema is Record type with type ref of invalid schema" do
8597
result =
8698
Schema.Encoder.from_json(message_with_reference_json(), fn name ->
87-
assert name == "io.confluent.Attachment"
99+
assert name == "io.acme.Attachment"
88100
{:ok, ~s({})}
89101
end)
90102

91103
assert {:error, {:not_found, "type"}} == result
92104
end
93105

94-
test "when payload is a valid json schema with external reference and callback returns error" do
106+
test "when schema is Record type with type ref and resolution failed" do
95107
result =
96108
Schema.Encoder.from_json(message_with_reference_json(), fn name ->
97-
assert name == "io.confluent.Attachment"
109+
assert name == "io.acme.Attachment"
98110
{:error, :bad_thing_happen}
99111
end)
100112

101113
assert {:error, :bad_thing_happen} == result
102114
end
103115

104-
test "when payload is a valid json schema with external reference and no callback is given" do
105-
assert {:error, {:not_found, "type"}} == Schema.Encoder.from_json(message_with_reference_json())
106-
end
107-
108-
test "when payload is not a named type schema" do
109-
assert Schema.Encoder.from_json(unnamed_json()) == {:error, :unnamed_type}
116+
test "when schema is Record type with type ref and lookup function given" do
117+
assert {:error, :undefined_reference_lookup_function} ==
118+
Schema.Encoder.from_json(message_with_reference_json())
110119
end
111120

112-
test "when payload is an invalid json schema" do
121+
test "when schema is an invalid" do
113122
assert Schema.Encoder.from_json("a:b") == {:error, "argument error"}
114123
assert Schema.Encoder.from_json("{}") == {:error, {:not_found, "type"}}
124+
assert Schema.Encoder.from_json("[null]") == {:error, :invalid_schema}
115125
end
116126
end
117127

@@ -121,7 +131,7 @@ defmodule Avrora.Schema.EncoderTest do
121131
{:ok, {type, _, _, _, _, fields, full_name, _}} = Schema.Encoder.to_erlavro(schema)
122132

123133
assert type == :avro_record_type
124-
assert full_name == "io.confluent.Payment"
134+
assert full_name == "io.acme.Payment"
125135
assert length(fields) == 2
126136
end
127137
end
@@ -133,7 +143,7 @@ defmodule Avrora.Schema.EncoderTest do
133143
assert is_nil(schema.id)
134144
assert is_nil(schema.version)
135145

136-
assert schema.full_name == "io.confluent.Payment"
146+
assert schema.full_name == "io.acme.Payment"
137147
assert schema.json == payment_json()
138148
end
139149

@@ -143,7 +153,7 @@ defmodule Avrora.Schema.EncoderTest do
143153
assert is_nil(schema.id)
144154
assert is_nil(schema.version)
145155

146-
assert schema.full_name == "io.confluent.Payment"
156+
assert schema.full_name == "io.acme.Payment"
147157
assert schema.json == "{}"
148158
end
149159

@@ -153,38 +163,37 @@ defmodule Avrora.Schema.EncoderTest do
153163
end
154164

155165
defp payment_erlavro do
156-
{:avro_record_type, "Payment", "io.confluent", "", [],
166+
{:avro_record_type, "Payment", "io.acme", "", [],
157167
[
158168
{:avro_record_field, "id", "", {:avro_primitive_type, "string", []}, :undefined, :ascending, []},
159169
{:avro_record_field, "amount", "", {:avro_primitive_type, "double", []}, :undefined, :ascending, []}
160-
], "io.confluent.Payment", []}
170+
], "io.acme.Payment", []}
161171
end
162172

163173
defp unnamed_erlavro, do: {:avro_array_type, {:avro_primitive_type, "string", []}, []}
164-
defp unnamed_json, do: ~s({"type":"array","items":"string","default":[]})
165-
defp crc32_json, do: ~s({"namespace":"io.confluent","name":"CRC32","type":"fixed","size":8})
174+
defp crc32_json, do: ~s({"namespace":"io.acme","name":"CRC32","type":"fixed","size":8})
166175

167176
defp signature_json do
168-
~s({"namespace":"io.confluent","name":"Signature","type":"record","fields":[{"name":"checksum","type":{"name":"SignatureChecksum","type":"fixed","size":1048576}}]})
177+
~s({"namespace":"io.acme","name":"Signature","type":"record","fields":[{"name":"checksum","type":{"name":"SignatureChecksum","type":"fixed","size":1048576}}]})
169178
end
170179

171180
defp attachment_json do
172-
~s({"namespace":"io.confluent","name":"Attachment","type":"record","fields":[{"name":"name","type":"string"},{"name":"signature","type":"io.confluent.Signature"}]})
181+
~s({"namespace":"io.acme","name":"Attachment","type":"record","fields":[{"name":"name","type":"string"},{"name":"signature","type":"io.acme.Signature"}]})
173182
end
174183

175184
defp payment_json do
176-
~s({"namespace":"io.confluent","name":"Payment","type":"record","fields":[{"name":"id","type":"string"},{"name":"amount","type":"double"}]})
185+
~s({"namespace":"io.acme","name":"Payment","type":"record","fields":[{"name":"id","type":"string"},{"name":"amount","type":"double"}]})
177186
end
178187

179188
defp card_type_json do
180-
~s({"namespace":"io.confluent","name":"CardType","type":"enum","symbols":["MASTERCARD","VISA","AMERICANEXPRESS"]})
189+
~s({"namespace":"io.acme","name":"CardType","type":"enum","symbols":["MASTERCARD","VISA","AMERICANEXPRESS"]})
181190
end
182191

183192
defp message_with_reference_json do
184-
~s({"namespace":"io.confluent","name":"Message","type":"record","fields":[{"name":"body","type":"string"},{"name":"attachments","type":{"type":"array","items":"io.confluent.Attachment"}}]})
193+
~s({"namespace":"io.acme","name":"Message","type":"record","fields":[{"name":"body","type":"string"},{"name":"attachments","type":{"type":"array","items":"io.acme.Attachment"}}]})
185194
end
186195

187196
defp message_json do
188-
~s({"namespace":"io.confluent","name":"Message","type":"record","fields":[{"name":"body","type":"string"},{"name":"attachments","type":{"type":"array","items":{"name":"Attachment","type":"record","fields":[{"name":"name","type":"string"},{"name":"signature","type":{"name":"Signature","type":"record","fields":[{"name":"checksum","type":{"name":"SignatureChecksum","type":"fixed","size":1048576}}]}}]}}}]})
197+
~s({"namespace":"io.acme","name":"Message","type":"record","fields":[{"name":"body","type":"string"},{"name":"attachments","type":{"type":"array","items":{"name":"Attachment","type":"record","fields":[{"name":"name","type":"string"},{"name":"signature","type":{"name":"Signature","type":"record","fields":[{"name":"checksum","type":{"name":"SignatureChecksum","type":"fixed","size":1048576}}]}}]}}}]})
189198
end
190199
end

0 commit comments

Comments
 (0)