avro_turf 1.18.0 → 1.20.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +20 -11
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile +6 -1
  5. data/README.md +1 -1
  6. data/Rakefile +2 -1
  7. data/avro_turf.gemspec +17 -17
  8. data/lib/avro_turf/cached_confluent_schema_registry.rb +9 -8
  9. data/lib/avro_turf/cached_schema_registry.rb +3 -1
  10. data/lib/avro_turf/confluent_schema_registry.rb +35 -22
  11. data/lib/avro_turf/core_ext/date.rb +2 -0
  12. data/lib/avro_turf/core_ext/enumerable.rb +2 -0
  13. data/lib/avro_turf/core_ext/false_class.rb +2 -0
  14. data/lib/avro_turf/core_ext/hash.rb +4 -2
  15. data/lib/avro_turf/core_ext/nil_class.rb +2 -0
  16. data/lib/avro_turf/core_ext/numeric.rb +2 -0
  17. data/lib/avro_turf/core_ext/string.rb +2 -0
  18. data/lib/avro_turf/core_ext/symbol.rb +2 -0
  19. data/lib/avro_turf/core_ext/time.rb +2 -0
  20. data/lib/avro_turf/core_ext/true_class.rb +2 -0
  21. data/lib/avro_turf/core_ext.rb +12 -10
  22. data/lib/avro_turf/disk_cache.rb +13 -12
  23. data/lib/avro_turf/in_memory_cache.rb +2 -0
  24. data/lib/avro_turf/messaging.rb +31 -16
  25. data/lib/avro_turf/mutable_schema_store.rb +25 -4
  26. data/lib/avro_turf/schema_registry.rb +3 -1
  27. data/lib/avro_turf/schema_store.rb +3 -2
  28. data/lib/avro_turf/schema_to_avro_patch.rb +14 -12
  29. data/lib/avro_turf/test/fake_confluent_schema_registry_server.rb +24 -23
  30. data/lib/avro_turf/test/fake_prefixed_confluent_schema_registry_server.rb +12 -10
  31. data/lib/avro_turf/test/fake_schema_registry_server.rb +3 -1
  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 +171 -86
  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_spec.rb +97 -94
  59. metadata +15 -33
@@ -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,40 +363,52 @@ 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
382
+
383
+ context "with an incompatible schema type" do
384
+ let(:response) { {"id" => schema_id, "schema" => "blah", "schemaType" => schema_type} }
385
+ let(:schema_type) { "PROTOBUF" }
386
+
387
+ it "raises IncompatibleSchemaError" do
388
+ expect { subject }.to raise_error(
389
+ AvroTurf::IncompatibleSchemaError,
390
+ "The #{schema_type} schema for #{subj} is incompatible."
391
+ )
392
+ end
393
+ end
380
394
  end
381
395
 
382
- context 'using fetch_schema_by_id' do
396
+ context "using fetch_schema_by_id" do
383
397
  subject { avro.fetch_schema_by_id(schema_id) }
384
398
 
385
399
  before do
386
400
  allow(registry).to receive(:fetch).with(schema_id).and_return(schema_json)
387
401
  end
388
402
 
389
- it 'gets schema from registry' do
403
+ it "gets schema from registry" do
390
404
  expect(subject).to eq([schema, schema_id])
391
405
  end
392
406
  end
393
407
 
394
- context 'using fetch_schema_by_body' do
395
- let(:subject_name) { 'city' }
396
- let(:schema_name) { 'city' }
397
- let(:namespace) { 'namespace' }
408
+ context "using fetch_schema_by_body" do
409
+ let(:subject_name) { "city" }
410
+ let(:schema_name) { "city" }
411
+ let(:namespace) { "namespace" }
398
412
  let(:city_schema_id) { 125 }
399
413
  let(:city_schema_data) do
400
414
  {
@@ -414,50 +428,50 @@ describe AvroTurf::Messaging do
414
428
  allow(registry).to receive(:check).with(subject_name, city_schema).and_return(city_schema_data)
415
429
  end
416
430
 
417
- it 'gets schema from registry' do
431
+ it "gets schema from registry" do
418
432
  expect(fetch_schema_by_body).to eq([city_schema, city_schema_id])
419
433
  end
420
434
  end
421
435
 
422
- context 'using register_schema' do
423
- let(:schema_name) { 'schema_name' }
436
+ context "using register_schema" do
437
+ let(:schema_name) { "schema_name" }
424
438
 
425
- let(:namespace) { 'namespace' }
439
+ let(:namespace) { "namespace" }
426
440
 
427
441
  before do
428
442
  allow(schema_store).to receive(:find).with(schema_name, namespace).and_return(schema)
429
443
  end
430
444
 
431
- context 'when subject is not set' do
445
+ context "when subject is not set" do
432
446
  subject { avro.register_schema(schema_name: schema_name, namespace: namespace) }
433
447
 
434
448
  before do
435
449
  allow(registry).to receive(:register).with(schema.fullname, schema).and_return(schema_id)
436
450
  end
437
451
 
438
- it 'registers schema in registry' do
452
+ it "registers schema in registry" do
439
453
  expect(subject).to eq([schema, schema_id])
440
454
  end
441
455
  end
442
456
 
443
- context 'when subject is set' do
457
+ context "when subject is set" do
444
458
  subject { avro.register_schema(schema_name: schema_name, namespace: namespace, subject: subj) }
445
459
 
446
- let(:subj) { 'subject' }
460
+ let(:subj) { "subject" }
447
461
 
448
462
  before do
449
463
  allow(registry).to receive(:register).with(subj, schema).and_return(schema_id)
450
464
  end
451
465
 
452
- it 'registers schema in registry' do
466
+ it "registers schema in registry" do
453
467
  expect(subject).to eq([schema, schema_id])
454
468
  end
455
469
  end
456
470
  end
457
471
  end
458
472
 
459
- context 'with a registry path prefix' do
460
- let(:path_prefix) { '/prefix' }
473
+ context "with a registry path prefix" do
474
+ let(:path_prefix) { "/prefix" }
461
475
 
462
476
  let(:avro) {
463
477
  AvroTurf::Messaging.new(
@@ -477,11 +491,11 @@ describe AvroTurf::Messaging do
477
491
  end
478
492
 
479
493
  it_behaves_like "encoding and decoding with the schema from schema store"
480
- it_behaves_like 'encoding and decoding with the schema from registry'
481
- it_behaves_like 'encoding and decoding with the schema_id from registry'
494
+ it_behaves_like "encoding and decoding with the schema from registry"
495
+ it_behaves_like "encoding and decoding with the schema_id from registry"
482
496
  end
483
497
 
484
- context 'with a connect timeout' do
498
+ context "with a connect timeout" do
485
499
  let(:avro) {
486
500
  AvroTurf::Messaging.new(
487
501
  registry_url: registry_url,
@@ -495,17 +509,64 @@ describe AvroTurf::Messaging do
495
509
  }
496
510
 
497
511
  it_behaves_like "encoding and decoding with the schema from schema store"
498
- it_behaves_like 'encoding and decoding with the schema from registry'
499
- it_behaves_like 'encoding and decoding with the schema_id from registry'
512
+ it_behaves_like "encoding and decoding with the schema from registry"
513
+ it_behaves_like "encoding and decoding with the schema_id from registry"
500
514
 
501
- it 'passes the connect timeout setting to Excon' do
515
+ it "passes the connect timeout setting to Excon" do
502
516
  expect(Excon).to receive(:new).with(anything, hash_including(connect_timeout: 10)).and_call_original
503
517
  avro
504
518
  end
505
519
  end
506
520
 
507
- context 'with a custom domain name resolver' do
508
- let(:resolv_resolver) { Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ['127.0.0.1', '127.0.0.1'])]) }
521
+ context "with a connect timeout" do
522
+ let(:avro) {
523
+ AvroTurf::Messaging.new(
524
+ registry_url: registry_url,
525
+ schemas_path: "spec/schemas",
526
+ logger: logger,
527
+ client_cert: client_cert,
528
+ client_key: client_key,
529
+ client_key_pass: client_key_pass,
530
+ retry_limit: 5
531
+ )
532
+ }
533
+
534
+ it_behaves_like "encoding and decoding with the schema from schema store"
535
+ it_behaves_like "encoding and decoding with the schema from registry"
536
+ it_behaves_like "encoding and decoding with the schema_id from registry"
537
+
538
+ it "passes the connect timeout setting to Excon" do
539
+ expect(Excon).to receive(:new).with(anything, hash_including(retry_limit: 5)).and_call_original
540
+ avro
541
+ end
542
+ end
543
+
544
+ context "with a proxy" do
545
+ let(:proxy_url) { "http://proxy.example.com" }
546
+ let(:avro) {
547
+ AvroTurf::Messaging.new(
548
+ registry_url: registry_url,
549
+ schemas_path: "spec/schemas",
550
+ logger: logger,
551
+ client_cert: client_cert,
552
+ client_key: client_key,
553
+ client_key_pass: client_key_pass,
554
+ proxy: proxy_url
555
+ )
556
+ }
557
+
558
+ it_behaves_like "encoding and decoding with the schema from schema store"
559
+ it_behaves_like "encoding and decoding with the schema from registry"
560
+ it_behaves_like "encoding and decoding with the schema_id from registry"
561
+
562
+ it "passes the proxy setting to Excon" do
563
+ expect(Excon).to receive(:new).with(anything, hash_including(proxy: proxy_url)).and_call_original
564
+ avro
565
+ end
566
+ end
567
+
568
+ context "with a custom domain name resolver" do
569
+ let(:resolv_resolver) { Resolv.new([Resolv::Hosts.new, Resolv::DNS.new(nameserver: ["127.0.0.1", "127.0.0.1"])]) }
509
570
  let(:avro) {
510
571
  AvroTurf::Messaging.new(
511
572
  registry_url: registry_url,
@@ -519,12 +580,36 @@ describe AvroTurf::Messaging do
519
580
  }
520
581
 
521
582
  it_behaves_like "encoding and decoding with the schema from schema store"
522
- it_behaves_like 'encoding and decoding with the schema from registry'
523
- it_behaves_like 'encoding and decoding with the schema_id from registry'
583
+ it_behaves_like "encoding and decoding with the schema from registry"
584
+ it_behaves_like "encoding and decoding with the schema_id from registry"
524
585
 
525
- it 'passes the domain name resolver setting to Excon' do
586
+ it "passes the domain name resolver setting to Excon" do
526
587
  expect(Excon).to receive(:new).with(anything, hash_including(resolv_resolver: resolv_resolver)).and_call_original
527
588
  avro
528
589
  end
529
590
  end
591
+
592
+ context "with a cert chain" do
593
+ let(:client_chain) { "test client chain" }
594
+ let(:avro) {
595
+ AvroTurf::Messaging.new(
596
+ registry_url: registry_url,
597
+ schemas_path: "spec/schemas",
598
+ logger: logger,
599
+ client_cert: client_cert,
600
+ client_chain: client_chain,
601
+ client_key: client_key,
602
+ client_key_pass: client_key_pass
603
+ )
604
+ }
605
+
606
+ it_behaves_like "encoding and decoding with the schema from schema store"
607
+ it_behaves_like "encoding and decoding with the schema from registry"
608
+ it_behaves_like "encoding and decoding with the schema_id from registry"
609
+
610
+ it "passes the client chain to Excon" do
611
+ expect(Excon).to receive(:new).with(anything, hash_including(client_chain: client_chain)).and_call_original
612
+ avro
613
+ end
614
+ end
530
615
  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