avro_turf 1.19.0 → 1.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +20 -11
  3. data/CHANGELOG.md +12 -0
  4. data/Gemfile +5 -2
  5. data/Rakefile +2 -1
  6. data/avro_turf.gemspec +16 -17
  7. data/lib/avro_turf/cached_confluent_schema_registry.rb +9 -8
  8. data/lib/avro_turf/cached_schema_registry.rb +3 -1
  9. data/lib/avro_turf/confluent_schema_registry.rb +23 -17
  10. data/lib/avro_turf/core_ext/date.rb +2 -0
  11. data/lib/avro_turf/core_ext/enumerable.rb +2 -0
  12. data/lib/avro_turf/core_ext/false_class.rb +2 -0
  13. data/lib/avro_turf/core_ext/hash.rb +4 -2
  14. data/lib/avro_turf/core_ext/nil_class.rb +2 -0
  15. data/lib/avro_turf/core_ext/numeric.rb +2 -0
  16. data/lib/avro_turf/core_ext/string.rb +2 -0
  17. data/lib/avro_turf/core_ext/symbol.rb +2 -0
  18. data/lib/avro_turf/core_ext/time.rb +2 -0
  19. data/lib/avro_turf/core_ext/true_class.rb +2 -0
  20. data/lib/avro_turf/core_ext.rb +12 -10
  21. data/lib/avro_turf/disk_cache.rb +13 -12
  22. data/lib/avro_turf/in_memory_cache.rb +2 -0
  23. data/lib/avro_turf/messaging.rb +25 -15
  24. data/lib/avro_turf/mutable_schema_store.rb +25 -4
  25. data/lib/avro_turf/schema_registry.rb +3 -1
  26. data/lib/avro_turf/schema_store.rb +3 -2
  27. data/lib/avro_turf/schema_to_avro_patch.rb +14 -12
  28. data/lib/avro_turf/test/fake_confluent_schema_registry_server.rb +39 -37
  29. data/lib/avro_turf/test/fake_prefixed_confluent_schema_registry_server.rb +12 -10
  30. data/lib/avro_turf/test/fake_schema_registry_server.rb +3 -1
  31. data/lib/avro_turf/test/fake_server.rb +186 -0
  32. data/lib/avro_turf/version.rb +3 -1
  33. data/lib/avro_turf.rb +15 -13
  34. data/perf/encoding_size.rb +4 -2
  35. data/perf/encoding_speed.rb +4 -2
  36. data/spec/avro_turf_spec.rb +24 -23
  37. data/spec/cached_confluent_schema_registry_spec.rb +9 -7
  38. data/spec/confluent_schema_registry_spec.rb +31 -10
  39. data/spec/core_ext/date_spec.rb +2 -0
  40. data/spec/core_ext/enumerable_spec.rb +2 -0
  41. data/spec/core_ext/false_class_spec.rb +2 -0
  42. data/spec/core_ext/hash_spec.rb +3 -1
  43. data/spec/core_ext/nil_class_spec.rb +2 -0
  44. data/spec/core_ext/numeric_spec.rb +2 -0
  45. data/spec/core_ext/string_spec.rb +2 -0
  46. data/spec/core_ext/symbol_spec.rb +2 -0
  47. data/spec/core_ext/time_spec.rb +2 -0
  48. data/spec/core_ext/true_class_spec.rb +2 -0
  49. data/spec/disk_cached_confluent_schema_registry_spec.rb +23 -21
  50. data/spec/messaging_spec.rb +145 -99
  51. data/spec/mutable_schema_store_spec.rb +134 -0
  52. data/spec/schema_store_spec.rb +23 -21
  53. data/spec/schema_to_avro_patch_spec.rb +8 -7
  54. data/spec/spec_helper.rb +9 -9
  55. data/spec/support/authorized_fake_confluent_schema_registry_server.rb +4 -2
  56. data/spec/support/authorized_fake_prefixed_confluent_schema_registry_server.rb +4 -2
  57. data/spec/support/confluent_schema_registry_context.rb +32 -30
  58. data/spec/test/fake_confluent_schema_registry_server_http_contract_spec.rb +722 -0
  59. data/spec/test/fake_confluent_schema_registry_server_spec.rb +97 -94
  60. metadata +7 -40
@@ -1,5 +1,7 @@
1
- require 'webmock/rspec'
2
- require 'avro_turf/messaging'
1
+ # frozen_string_literal: true
2
+
3
+ require "webmock/rspec"
4
+ require "avro_turf/messaging"
3
5
 
4
6
  describe AvroTurf::Messaging do
5
7
  let(:registry_url) { "http://registry.example.com" }
@@ -19,7 +21,7 @@ describe AvroTurf::Messaging do
19
21
  )
20
22
  }
21
23
 
22
- let(:message) { { "full_name" => "John Doe" } }
24
+ let(:message) { {"full_name" => "John Doe"} }
23
25
  let(:schema_json) do
24
26
  <<-AVSC
25
27
  {
@@ -35,7 +37,7 @@ describe AvroTurf::Messaging do
35
37
  AVSC
36
38
  end
37
39
 
38
- let(:city_message) { { "name" => "Paris" } }
40
+ let(:city_message) { {"name" => "Paris"} }
39
41
  let(:city_schema_json) do
40
42
  <<-AVSC
41
43
  {
@@ -88,39 +90,39 @@ describe AvroTurf::Messaging do
88
90
  end
89
91
  end
90
92
 
91
- shared_examples_for 'encoding and decoding with the schema from registry' do
93
+ shared_examples_for "encoding and decoding with the schema from registry" do
92
94
  before do
93
95
  registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger, path_prefix: path_prefix)
94
- registry.register('person', schema)
95
- registry.register('people', schema)
96
+ registry.register("person", schema)
97
+ registry.register("people", schema)
96
98
  end
97
99
 
98
- it 'encodes and decodes messages' do
99
- data = avro.encode(message, subject: 'person', version: 1)
100
+ it "encodes and decodes messages" do
101
+ data = avro.encode(message, subject: "person", version: 1)
100
102
  expect(avro.decode(data)).to eq message
101
103
  end
102
104
 
103
105
  it "allows specifying a reader's schema by subject and version" do
104
- data = avro.encode(message, subject: 'person', version: 1)
105
- expect(avro.decode(data, schema_name: 'person')).to eq message
106
+ data = avro.encode(message, subject: "person", version: 1)
107
+ expect(avro.decode(data, schema_name: "person")).to eq message
106
108
  end
107
109
 
108
- it 'raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry' do
109
- expect { avro.encode(message, subject: 'missing', version: 1) }.to raise_error(AvroTurf::SchemaNotFoundError)
110
+ it "raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry" do
111
+ expect { avro.encode(message, subject: "missing", version: 1) }.to raise_error(AvroTurf::SchemaNotFoundError)
110
112
  end
111
113
 
112
- it 'raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry and register_schemas false' do
113
- expect { avro.encode(city_message, schema_name: 'city', register_schemas: false) }.
114
- to raise_error(AvroTurf::SchemaNotFoundError, "Schema with structure: #{city_schema} not found on registry")
114
+ it "raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry and register_schemas false" do
115
+ expect { avro.encode(city_message, schema_name: "city", register_schemas: false) }
116
+ .to raise_error(AvroTurf::SchemaNotFoundError, "Schema with structure: #{city_schema} not found on registry")
115
117
  end
116
118
 
117
- it 'encodes with register_schemas false when the schema exists on the registry' do
118
- data = avro.encode(message, schema_name: 'person', register_schemas: false)
119
- expect(avro.decode(data, schema_name: 'person')).to eq message
119
+ it "encodes with register_schemas false when the schema exists on the registry" do
120
+ data = avro.encode(message, schema_name: "person", register_schemas: false)
121
+ expect(avro.decode(data, schema_name: "person")).to eq message
120
122
  end
121
123
 
122
- it 'caches parsed schemas for decoding' do
123
- data = avro.encode(message, subject: 'person', version: 1)
124
+ it "caches parsed schemas for decoding" do
125
+ data = avro.encode(message, subject: "person", version: 1)
124
126
  avro.decode(data)
125
127
  allow(Avro::Schema).to receive(:parse).and_call_original
126
128
  expect(avro.decode(data)).to eq message
@@ -128,23 +130,23 @@ describe AvroTurf::Messaging do
128
130
  end
129
131
  end
130
132
 
131
- shared_examples_for 'encoding and decoding with the schema_id from registry' do
133
+ shared_examples_for "encoding and decoding with the schema_id from registry" do
132
134
  before do
133
135
  registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger, path_prefix: path_prefix)
134
- registry.register('person', schema)
135
- registry.register('people', schema)
136
+ registry.register("person", schema)
137
+ registry.register("people", schema)
136
138
  end
137
139
 
138
- it 'encodes and decodes messages' do
140
+ it "encodes and decodes messages" do
139
141
  data = avro.encode(message, schema_id: 0)
140
142
  expect(avro.decode(data)).to eq message
141
143
  end
142
144
 
143
- it 'raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry' do
145
+ it "raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry" do
144
146
  expect { avro.encode(message, schema_id: 5) }.to raise_error(AvroTurf::SchemaNotFoundError)
145
147
  end
146
148
 
147
- it 'caches parsed schemas for decoding' do
149
+ it "caches parsed schemas for decoding" do
148
150
  data = avro.encode(message, schema_id: 0)
149
151
  avro.decode(data)
150
152
  allow(Avro::Schema).to receive(:parse).and_call_original
@@ -155,9 +157,9 @@ describe AvroTurf::Messaging do
155
157
 
156
158
  it_behaves_like "encoding and decoding with the schema from schema store"
157
159
 
158
- it_behaves_like 'encoding and decoding with the schema from registry'
160
+ it_behaves_like "encoding and decoding with the schema from registry"
159
161
 
160
- it_behaves_like 'encoding and decoding with the schema_id from registry'
162
+ it_behaves_like "encoding and decoding with the schema_id from registry"
161
163
 
162
164
  context "with a provided registry" do
163
165
  let(:registry) { AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger) }
@@ -172,20 +174,20 @@ describe AvroTurf::Messaging do
172
174
 
173
175
  it_behaves_like "encoding and decoding with the schema from schema store"
174
176
 
175
- it_behaves_like 'encoding and decoding with the schema from registry'
177
+ it_behaves_like "encoding and decoding with the schema from registry"
176
178
 
177
- it_behaves_like 'encoding and decoding with the schema_id from registry'
179
+ it_behaves_like "encoding and decoding with the schema_id from registry"
178
180
 
179
181
  it "uses the provided registry" do
180
182
  allow(registry).to receive(:register).and_call_original
181
- message = { "full_name" => "John Doe" }
183
+ message = {"full_name" => "John Doe"}
182
184
  avro.encode(message, schema_name: "person")
183
185
  expect(registry).to have_received(:register).with("person", anything)
184
186
  end
185
187
 
186
188
  it "allows specifying a schema registry subject" do
187
189
  allow(registry).to receive(:register).and_call_original
188
- message = { "full_name" => "John Doe" }
190
+ message = {"full_name" => "John Doe"}
189
191
  avro.encode(message, schema_name: "person", subject: "people")
190
192
  expect(registry).to have_received(:register).with("people", anything)
191
193
  end
@@ -211,7 +213,7 @@ describe AvroTurf::Messaging do
211
213
  end
212
214
  end
213
215
 
214
- describe 'decoding with #decode_message' do
216
+ describe "decoding with #decode_message" do
215
217
  shared_examples_for "encoding and decoding with the schema from schema store" do
216
218
  it "encodes and decodes messages" do
217
219
  data = avro.encode(message, schema_name: "person")
@@ -239,31 +241,31 @@ describe AvroTurf::Messaging do
239
241
  end
240
242
  end
241
243
 
242
- shared_examples_for 'encoding and decoding with the schema from registry' do
244
+ shared_examples_for "encoding and decoding with the schema from registry" do
243
245
  before do
244
246
  registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger)
245
- registry.register('person', schema)
246
- registry.register('people', schema)
247
+ registry.register("person", schema)
248
+ registry.register("people", schema)
247
249
  end
248
250
 
249
- it 'encodes and decodes messages' do
250
- data = avro.encode(message, subject: 'person', version: 1)
251
+ it "encodes and decodes messages" do
252
+ data = avro.encode(message, subject: "person", version: 1)
251
253
  result = avro.decode_message(data)
252
254
  expect(result.message).to eq message
253
255
  expect(result.schema_id).to eq 0
254
256
  end
255
257
 
256
258
  it "allows specifying a reader's schema by subject and version" do
257
- data = avro.encode(message, subject: 'person', version: 1)
258
- expect(avro.decode_message(data, schema_name: 'person').message).to eq message
259
+ data = avro.encode(message, subject: "person", version: 1)
260
+ expect(avro.decode_message(data, schema_name: "person").message).to eq message
259
261
  end
260
262
 
261
- it 'raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry' do
262
- expect { avro.encode(message, subject: 'missing', version: 1) }.to raise_error(AvroTurf::SchemaNotFoundError)
263
+ it "raises AvroTurf::SchemaNotFoundError when the schema does not exist on registry" do
264
+ expect { avro.encode(message, subject: "missing", version: 1) }.to raise_error(AvroTurf::SchemaNotFoundError)
263
265
  end
264
266
 
265
- it 'caches parsed schemas for decoding' do
266
- data = avro.encode(message, subject: 'person', version: 1)
267
+ it "caches parsed schemas for decoding" do
268
+ data = avro.encode(message, subject: "person", version: 1)
267
269
  avro.decode_message(data)
268
270
  allow(Avro::Schema).to receive(:parse).and_call_original
269
271
  expect(avro.decode_message(data).message).to eq message
@@ -273,7 +275,7 @@ describe AvroTurf::Messaging do
273
275
 
274
276
  it_behaves_like "encoding and decoding with the schema from schema store"
275
277
 
276
- it_behaves_like 'encoding and decoding with the schema from registry'
278
+ it_behaves_like "encoding and decoding with the schema from registry"
277
279
 
278
280
  context "with a provided registry" do
279
281
  let(:registry) { AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger) }
@@ -288,18 +290,18 @@ describe AvroTurf::Messaging do
288
290
 
289
291
  it_behaves_like "encoding and decoding with the schema from schema store"
290
292
 
291
- it_behaves_like 'encoding and decoding with the schema from registry'
293
+ it_behaves_like "encoding and decoding with the schema from registry"
292
294
 
293
295
  it "uses the provided registry" do
294
296
  allow(registry).to receive(:register).and_call_original
295
- message = { "full_name" => "John Doe" }
297
+ message = {"full_name" => "John Doe"}
296
298
  avro.encode(message, schema_name: "person")
297
299
  expect(registry).to have_received(:register).with("person", anything)
298
300
  end
299
301
 
300
302
  it "allows specifying a schema registry subject" do
301
303
  allow(registry).to receive(:register).and_call_original
302
- message = { "full_name" => "John Doe" }
304
+ message = {"full_name" => "John Doe"}
303
305
  avro.encode(message, schema_name: "person", subject: "people")
304
306
  expect(registry).to have_received(:register).with("people", anything)
305
307
  end
@@ -327,26 +329,26 @@ describe AvroTurf::Messaging do
327
329
  end
328
330
 
329
331
  context "validating" do
330
- subject(:encode){ avro.encode(message, schema_name: "person", validate: true) }
332
+ subject(:encode) { avro.encode(message, schema_name: "person", validate: true) }
331
333
 
332
334
  context "for correct message" do
333
335
  it { expect { encode }.not_to raise_error }
334
336
  end
335
337
 
336
338
  context "when message has wrong type" do
337
- let(:message) { { "full_name" => 123 } }
339
+ let(:message) { {"full_name" => 123} }
338
340
 
339
341
  it { expect { encode }.to raise_error(Avro::SchemaValidator::ValidationError, /\.full_name expected type string, got int/) }
340
342
  end
341
343
 
342
344
  context "when message contains extra fields (typo in key)" do
343
- let(:message) { { "fulll_name" => "John Doe" } }
345
+ let(:message) { {"fulll_name" => "John Doe"} }
344
346
 
345
347
  it { expect { encode }.to raise_error(Avro::SchemaValidator::ValidationError, /extra field 'fulll_name'/) }
346
348
  end
347
349
  end
348
350
 
349
- context 'fetching and registering schema' do
351
+ context "fetching and registering schema" do
350
352
  let(:schema_store) { AvroTurf::SchemaStore.new(path: "spec/schemas") }
351
353
 
352
354
  let(:registry) { AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger) }
@@ -361,28 +363,39 @@ describe AvroTurf::Messaging do
361
363
 
362
364
  let(:schema_id) { 234 }
363
365
 
364
- context 'using fetch_schema' do
366
+ context "using fetch_schema" do
365
367
  subject { avro.fetch_schema(subject: subj, version: version) }
366
368
 
367
- let(:subj) { 'subject' }
369
+ let(:subj) { "subject" }
368
370
 
369
- let(:version) { 'version' }
371
+ let(:version) { "version" }
370
372
 
371
- let(:response) { {'id' => schema_id, 'schema' => schema_json} }
373
+ let(:response) { {"id" => schema_id, "schema" => schema_json} }
372
374
 
373
375
  before do
374
376
  allow(registry).to receive(:subject_version).with(subj, version).and_return(response)
375
377
  end
376
378
 
377
- it 'gets schema from registry' do
379
+ it "gets schema from registry" do
378
380
  expect(subject).to eq([schema, schema_id])
379
381
  end
380
382
 
383
+ it "memoizes parsed schema" do
384
+ expect(registry).to receive(:subject_version).with(subj, version).twice.and_return(response)
385
+ expect(Avro::Schema).to receive(:parse).with(schema_json).once.and_return(schema)
386
+
387
+ first_result = avro.fetch_schema(subject: subj, version: version)
388
+ second_result = avro.fetch_schema(subject: subj, version: version)
389
+
390
+ expect(first_result).to eq([schema, schema_id])
391
+ expect(second_result).to eq([schema, schema_id])
392
+ end
393
+
381
394
  context "with an incompatible schema type" do
382
- let(:response) { {'id' => schema_id, 'schema' => 'blah', 'schemaType' => schema_type } }
383
- let(:schema_type) { 'PROTOBUF' }
395
+ let(:response) { {"id" => schema_id, "schema" => "blah", "schemaType" => schema_type} }
396
+ let(:schema_type) { "PROTOBUF" }
384
397
 
385
- it 'raises IncompatibleSchemaError' do
398
+ it "raises IncompatibleSchemaError" do
386
399
  expect { subject }.to raise_error(
387
400
  AvroTurf::IncompatibleSchemaError,
388
401
  "The #{schema_type} schema for #{subj} is incompatible."
@@ -391,22 +404,32 @@ describe AvroTurf::Messaging do
391
404
  end
392
405
  end
393
406
 
394
- context 'using fetch_schema_by_id' do
407
+ context "using fetch_schema_by_id" do
395
408
  subject { avro.fetch_schema_by_id(schema_id) }
396
409
 
397
410
  before do
398
411
  allow(registry).to receive(:fetch).with(schema_id).and_return(schema_json)
399
412
  end
400
413
 
401
- it 'gets schema from registry' do
414
+ it "gets schema from registry" do
402
415
  expect(subject).to eq([schema, schema_id])
403
416
  end
417
+
418
+ it "memoizes schema in @schemas_by_id after first call" do
419
+ expect(registry).to receive(:fetch).with(schema_id).once.and_return(schema_json)
420
+
421
+ first_result = avro.fetch_schema_by_id(schema_id)
422
+ second_result = avro.fetch_schema_by_id(schema_id)
423
+
424
+ expect(first_result).to eq([schema, schema_id])
425
+ expect(second_result).to eq([schema, schema_id])
426
+ end
404
427
  end
405
428
 
406
- context 'using fetch_schema_by_body' do
407
- let(:subject_name) { 'city' }
408
- let(:schema_name) { 'city' }
409
- let(:namespace) { 'namespace' }
429
+ context "using fetch_schema_by_body" do
430
+ let(:subject_name) { "city" }
431
+ let(:schema_name) { "city" }
432
+ let(:namespace) { "namespace" }
410
433
  let(:city_schema_id) { 125 }
411
434
  let(:city_schema_data) do
412
435
  {
@@ -426,50 +449,50 @@ describe AvroTurf::Messaging do
426
449
  allow(registry).to receive(:check).with(subject_name, city_schema).and_return(city_schema_data)
427
450
  end
428
451
 
429
- it 'gets schema from registry' do
452
+ it "gets schema from registry" do
430
453
  expect(fetch_schema_by_body).to eq([city_schema, city_schema_id])
431
454
  end
432
455
  end
433
456
 
434
- context 'using register_schema' do
435
- let(:schema_name) { 'schema_name' }
457
+ context "using register_schema" do
458
+ let(:schema_name) { "schema_name" }
436
459
 
437
- let(:namespace) { 'namespace' }
460
+ let(:namespace) { "namespace" }
438
461
 
439
462
  before do
440
463
  allow(schema_store).to receive(:find).with(schema_name, namespace).and_return(schema)
441
464
  end
442
465
 
443
- context 'when subject is not set' do
466
+ context "when subject is not set" do
444
467
  subject { avro.register_schema(schema_name: schema_name, namespace: namespace) }
445
468
 
446
469
  before do
447
470
  allow(registry).to receive(:register).with(schema.fullname, schema).and_return(schema_id)
448
471
  end
449
472
 
450
- it 'registers schema in registry' do
473
+ it "registers schema in registry" do
451
474
  expect(subject).to eq([schema, schema_id])
452
475
  end
453
476
  end
454
477
 
455
- context 'when subject is set' do
478
+ context "when subject is set" do
456
479
  subject { avro.register_schema(schema_name: schema_name, namespace: namespace, subject: subj) }
457
480
 
458
- let(:subj) { 'subject' }
481
+ let(:subj) { "subject" }
459
482
 
460
483
  before do
461
484
  allow(registry).to receive(:register).with(subj, schema).and_return(schema_id)
462
485
  end
463
486
 
464
- it 'registers schema in registry' do
487
+ it "registers schema in registry" do
465
488
  expect(subject).to eq([schema, schema_id])
466
489
  end
467
490
  end
468
491
  end
469
492
  end
470
493
 
471
- context 'with a registry path prefix' do
472
- let(:path_prefix) { '/prefix' }
494
+ context "with a registry path prefix" do
495
+ let(:path_prefix) { "/prefix" }
473
496
 
474
497
  let(:avro) {
475
498
  AvroTurf::Messaging.new(
@@ -489,11 +512,11 @@ describe AvroTurf::Messaging do
489
512
  end
490
513
 
491
514
  it_behaves_like "encoding and decoding with the schema from schema store"
492
- it_behaves_like 'encoding and decoding with the schema from registry'
493
- it_behaves_like 'encoding and decoding with the schema_id from registry'
515
+ it_behaves_like "encoding and decoding with the schema from registry"
516
+ it_behaves_like "encoding and decoding with the schema_id from registry"
494
517
  end
495
518
 
496
- context 'with a connect timeout' do
519
+ context "with a connect timeout" do
497
520
  let(:avro) {
498
521
  AvroTurf::Messaging.new(
499
522
  registry_url: registry_url,
@@ -507,16 +530,16 @@ describe AvroTurf::Messaging do
507
530
  }
508
531
 
509
532
  it_behaves_like "encoding and decoding with the schema from schema store"
510
- it_behaves_like 'encoding and decoding with the schema from registry'
511
- it_behaves_like 'encoding and decoding with the schema_id from registry'
533
+ it_behaves_like "encoding and decoding with the schema from registry"
534
+ it_behaves_like "encoding and decoding with the schema_id from registry"
512
535
 
513
- it 'passes the connect timeout setting to Excon' do
536
+ it "passes the connect timeout setting to Excon" do
514
537
  expect(Excon).to receive(:new).with(anything, hash_including(connect_timeout: 10)).and_call_original
515
538
  avro
516
539
  end
517
540
  end
518
541
 
519
- context 'with a connect timeout' do
542
+ context "with a connect timeout" do
520
543
  let(:avro) {
521
544
  AvroTurf::Messaging.new(
522
545
  registry_url: registry_url,
@@ -530,17 +553,17 @@ describe AvroTurf::Messaging do
530
553
  }
531
554
 
532
555
  it_behaves_like "encoding and decoding with the schema from schema store"
533
- it_behaves_like 'encoding and decoding with the schema from registry'
534
- it_behaves_like 'encoding and decoding with the schema_id from registry'
556
+ it_behaves_like "encoding and decoding with the schema from registry"
557
+ it_behaves_like "encoding and decoding with the schema_id from registry"
535
558
 
536
- it 'passes the connect timeout setting to Excon' do
559
+ it "passes the connect timeout setting to Excon" do
537
560
  expect(Excon).to receive(:new).with(anything, hash_including(retry_limit: 5)).and_call_original
538
561
  avro
539
562
  end
540
563
  end
541
564
 
542
- context 'with a proxy' do
543
- let(:proxy_url) { 'http://proxy.example.com' }
565
+ context "with a proxy" do
566
+ let(:proxy_url) { "http://proxy.example.com" }
544
567
  let(:avro) {
545
568
  AvroTurf::Messaging.new(
546
569
  registry_url: registry_url,
@@ -554,18 +577,17 @@ describe AvroTurf::Messaging do
554
577
  }
555
578
 
556
579
  it_behaves_like "encoding and decoding with the schema from schema store"
557
- it_behaves_like 'encoding and decoding with the schema from registry'
558
- it_behaves_like 'encoding and decoding with the schema_id from registry'
580
+ it_behaves_like "encoding and decoding with the schema from registry"
581
+ it_behaves_like "encoding and decoding with the schema_id from registry"
559
582
 
560
- it 'passes the proxy setting to Excon' do
583
+ it "passes the proxy setting to Excon" do
561
584
  expect(Excon).to receive(:new).with(anything, hash_including(proxy: proxy_url)).and_call_original
562
585
  avro
563
586
  end
564
587
  end
565
588
 
566
-
567
- context 'with a custom domain name resolver' do
568
- let(:resolv_resolver) { Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ['127.0.0.1', '127.0.0.1'])]) }
589
+ context "with a custom domain name resolver" do
590
+ let(:resolv_resolver) { Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ["127.0.0.1", "127.0.0.1"])]) }
569
591
  let(:avro) {
570
592
  AvroTurf::Messaging.new(
571
593
  registry_url: registry_url,
@@ -579,12 +601,36 @@ describe AvroTurf::Messaging do
579
601
  }
580
602
 
581
603
  it_behaves_like "encoding and decoding with the schema from schema store"
582
- it_behaves_like 'encoding and decoding with the schema from registry'
583
- it_behaves_like 'encoding and decoding with the schema_id from registry'
604
+ it_behaves_like "encoding and decoding with the schema from registry"
605
+ it_behaves_like "encoding and decoding with the schema_id from registry"
584
606
 
585
- it 'passes the domain name resolver setting to Excon' do
607
+ it "passes the domain name resolver setting to Excon" do
586
608
  expect(Excon).to receive(:new).with(anything, hash_including(resolv_resolver: resolv_resolver)).and_call_original
587
609
  avro
588
610
  end
589
611
  end
612
+
613
+ context "with a cert chain" do
614
+ let(:client_chain) { "test client chain" }
615
+ let(:avro) {
616
+ AvroTurf::Messaging.new(
617
+ registry_url: registry_url,
618
+ schemas_path: "spec/schemas",
619
+ logger: logger,
620
+ client_cert: client_cert,
621
+ client_chain: client_chain,
622
+ client_key: client_key,
623
+ client_key_pass: client_key_pass
624
+ )
625
+ }
626
+
627
+ it_behaves_like "encoding and decoding with the schema from schema store"
628
+ it_behaves_like "encoding and decoding with the schema from registry"
629
+ it_behaves_like "encoding and decoding with the schema_id from registry"
630
+
631
+ it "passes the client chain to Excon" do
632
+ expect(Excon).to receive(:new).with(anything, hash_including(client_chain: client_chain)).and_call_original
633
+ avro
634
+ end
635
+ end
590
636
  end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "avro_turf/mutable_schema_store"
4
+
5
+ describe AvroTurf::MutableSchemaStore do
6
+ let(:store) { AvroTurf::MutableSchemaStore.new(path: "spec/schemas") }
7
+
8
+ describe "#add_schema" do
9
+ it "adds a schema to the store" do
10
+ schema_hash = {
11
+ "name" => "person",
12
+ "namespace" => "test.people",
13
+ "type" => "record",
14
+ "fields" => [
15
+ {
16
+ "type" => "string",
17
+ "name" => "name"
18
+ }
19
+ ]
20
+ }
21
+
22
+ schema = store.add_schema(schema_hash)
23
+ expect(schema.fullname).to eq "test.people.person"
24
+ expect(store.schemas["test.people.person"]).to eq schema
25
+ end
26
+
27
+ # This test would fail under avro_turf <= v0.19.0
28
+ it "does NOT cache *nested* schemas in memory" do
29
+ schema_hash = {
30
+ "name" => "person",
31
+ "namespace" => "test",
32
+ "type" => "record",
33
+ "fields" => [
34
+ {
35
+ "name" => "address",
36
+ "type" => {
37
+ "name" => "address",
38
+ "type" => "record",
39
+ "fields" => [
40
+ {"name" => "addr1", "type" => "string"},
41
+ {"name" => "addr2", "type" => "string"},
42
+ {"name" => "city", "type" => "string"},
43
+ {"name" => "zip", "type" => "string"}
44
+ ]
45
+ }
46
+ }
47
+ ]
48
+ }
49
+
50
+ schema = store.add_schema(schema_hash)
51
+ expect(schema.fullname).to eq "test.person"
52
+ expect(store.schemas["test.person"]).to eq schema
53
+
54
+ expect { store.find("address", "test") }
55
+ .to raise_error(AvroTurf::SchemaNotFoundError)
56
+ end
57
+
58
+ # This test would fail under avro_turf <= v1.19.0
59
+ it "allows two different schemas to define nested sub-schemas with the same fullname" do
60
+ person_schema = {
61
+ "name" => "person",
62
+ "namespace" => "test",
63
+ "type" => "record",
64
+ "fields" => [
65
+ {
66
+ "name" => "location",
67
+ "type" => {
68
+ "name" => "location",
69
+ "type" => "record",
70
+ "fields" => [
71
+ {"name" => "city", "type" => "string"},
72
+ {"name" => "zipcode", "type" => "string"}
73
+ ]
74
+ }
75
+ }
76
+ ]
77
+ }
78
+
79
+ company_schema = {
80
+ "name" => "company",
81
+ "namespace" => "test",
82
+ "type" => "record",
83
+ "fields" => [
84
+ {
85
+ "name" => "headquarters",
86
+ "type" => {
87
+ "name" => "location",
88
+ "type" => "record",
89
+ "fields" => [
90
+ {"name" => "city", "type" => "string"},
91
+ {"name" => "postcode", "type" => "string"}
92
+ ]
93
+ }
94
+ }
95
+ ]
96
+ }
97
+
98
+ person = store.add_schema(person_schema)
99
+
100
+ # This should *NOT* raise the error:
101
+ # #<Avro::SchemaParseError: The name "test.location" is already in use.>
102
+ expect { store.add_schema(company_schema) }.not_to raise_error
103
+
104
+ company = store.schemas["test.company"]
105
+
106
+ person_location_field = person.fields_hash["location"]
107
+ expect(person_location_field.type.name).to eq("location")
108
+ expect(person_location_field.type.fields_hash).to include("zipcode")
109
+ expect(person_location_field.type.fields_hash).not_to include("postcode")
110
+
111
+ company_headquarters_field = company.fields_hash["headquarters"]
112
+ expect(company_headquarters_field.type.name).to eq("location")
113
+ expect(company_headquarters_field.type.fields_hash).to include("postcode")
114
+ expect(company_headquarters_field.type.fields_hash).not_to include("zipcode")
115
+ end
116
+ end
117
+
118
+ describe "#schemas" do
119
+ it "provides access to the internal schemas hash" do
120
+ expect(store.schemas).to be_a(Hash)
121
+ expect(store.schemas).to be_empty
122
+
123
+ schema_hash = {
124
+ "name" => "test",
125
+ "type" => "record",
126
+ "fields" => []
127
+ }
128
+
129
+ store.add_schema(schema_hash)
130
+ expect(store.schemas.size).to eq 1
131
+ expect(store.schemas["test"]).to be_a(Avro::Schema::RecordSchema)
132
+ end
133
+ end
134
+ end