avro_turf 1.5.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e110697cb451e5315414f8086d32aa6e6c43444a462fcdaa678d1311302fcab8
4
- data.tar.gz: a54afac8d7e8cb4a599695825ccb3d666d08ad800ccfe63229f14b6b42b26f11
3
+ metadata.gz: 67ff8ee9b578227cd54a33d76a95fed8bd2c9a396aa360ad9df9f52d01e5c25a
4
+ data.tar.gz: 8bca24236ce42f19f6db457ad13d76d33e89b18703dc0eb74a8adca53b2c7b6e
5
5
  SHA512:
6
- metadata.gz: 78ee7cc3c12975d15bc621d9b3a96ed014cc8265536650f365ed80a861a06d53f3e9db9f7d698f71c02485df6f9b371944102404e76cc05e13816e12d312d97c
7
- data.tar.gz: ac02799c0f25b88f8c9bfbbd0de48a2b3c39a7744ee1b90c6c87439b5a547db9456a2b3f89a9730303c76ea302159fdce9189f417e6424ecbac45da14682dd0d
6
+ metadata.gz: 859e8fa6938679007704d35b1b4a54616da7637c83f41c58cbd10828216e0af198846e755334f465613ceb9086ec0c63a823dc2cbf3ddbdc191a97423d2e3147
7
+ data.tar.gz: 7900a85abaf9dd55ac3b89bba2d04935ddbafc850a92fb1941ff8984df864cfaa4bb5527ca4d48a74ef3715915d598044b7c486363909f2705ece83b0ffca50f
data/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## v1.8.0
6
+
7
+ - add support for `Date` via appropriate logicalType defintion. This is a backwards incompatible change (#177)
8
+ - Fixed schema file cache truncation on multiple running instances and parallel access to the cache files.
9
+
10
+ ## v1.7.0
11
+
12
+ - Added extra params for the validation message schema before encode (#169)
13
+ - Fix infinite retry when loading schema with nested primary type in separate file (#165)
14
+
15
+ ## v1.6.0
16
+
17
+ - Schema registry path prefix (#162)
18
+
5
19
  ## v1.5.0
6
20
 
7
21
  - Add CA cert file option (#157)
@@ -51,7 +65,7 @@
51
65
  ## v0.9.0
52
66
 
53
67
  - Compatibility with Avro v1.9.0 (#94)
54
- - Disable the auto registeration of schema (#95)
68
+ - Disable the auto registration of schema (#95)
55
69
  - abstracted caching from CachedConfluentSchemaRegistry (#74)
56
70
  - Load avro-patches if installed to silence deprecation errors (#85)
57
71
  - Make schema store to be thread safe (#92)
@@ -13,7 +13,7 @@ class AvroTurf::CachedConfluentSchemaRegistry
13
13
  # cache - Optional user provided Cache object that responds to all methods in the AvroTurf::InMemoryCache interface.
14
14
  def initialize(upstream, cache: nil)
15
15
  @upstream = upstream
16
- @cache = cache || AvroTurf::InMemoryCache.new()
16
+ @cache = cache || AvroTurf::InMemoryCache.new
17
17
  end
18
18
 
19
19
  # Delegate the following methods to the upstream
@@ -34,7 +34,7 @@ class AvroTurf::CachedConfluentSchemaRegistry
34
34
 
35
35
  def subject_version(subject, version = 'latest')
36
36
  return @upstream.subject_version(subject, version) if version == 'latest'
37
-
37
+
38
38
  @cache.lookup_by_version(subject, version) ||
39
39
  @cache.store_by_version(subject, version, @upstream.subject_version(subject, version))
40
40
  end
@@ -14,8 +14,10 @@ class AvroTurf::ConfluentSchemaRegistry
14
14
  client_key: nil,
15
15
  client_key_pass: nil,
16
16
  client_cert_data: nil,
17
- client_key_data: nil
17
+ client_key_data: nil,
18
+ path_prefix: nil
18
19
  )
20
+ @path_prefix = path_prefix
19
21
  @logger = logger
20
22
  headers = {
21
23
  "Content-Type" => CONTENT_TYPE
@@ -122,6 +124,7 @@ class AvroTurf::ConfluentSchemaRegistry
122
124
 
123
125
  def request(path, **options)
124
126
  options = { expects: 200 }.merge!(options)
127
+ path = File.join(@path_prefix, path) unless @path_prefix.nil?
125
128
  response = @connection.request(path: path, **options)
126
129
  JSON.parse(response.body)
127
130
  end
@@ -1,5 +1,5 @@
1
1
  class Date
2
2
  def as_avro
3
- iso8601
3
+ self
4
4
  end
5
5
  end
@@ -1,20 +1,18 @@
1
1
  # A cache for the CachedConfluentSchemaRegistry.
2
2
  # Extends the InMemoryCache to provide a write-thru to disk for persistent cache.
3
- class AvroTurf::DiskCache < AvroTurf::InMemoryCache
3
+ class AvroTurf::DiskCache
4
4
 
5
5
  def initialize(disk_path, logger: Logger.new($stdout))
6
- super()
7
-
8
6
  @logger = logger
9
7
 
10
8
  # load the write-thru cache on startup, if it exists
11
9
  @schemas_by_id_path = File.join(disk_path, 'schemas_by_id.json')
12
10
  hash = read_from_disk_cache(@schemas_by_id_path)
13
- @schemas_by_id = hash if hash
11
+ @schemas_by_id = hash || {}
14
12
 
15
13
  @ids_by_schema_path = File.join(disk_path, 'ids_by_schema.json')
16
14
  hash = read_from_disk_cache(@ids_by_schema_path)
17
- @ids_by_schema = hash if hash
15
+ @ids_by_schema = hash || {}
18
16
 
19
17
  @schemas_by_subject_version_path = File.join(disk_path, 'schemas_by_subject_version.json')
20
18
  @schemas_by_subject_version = {}
@@ -24,15 +22,16 @@ class AvroTurf::DiskCache < AvroTurf::InMemoryCache
24
22
  # the write-thru cache (json) does not store keys in numeric format
25
23
  # so, convert id to a string for caching purposes
26
24
  def lookup_by_id(id)
27
- super(id.to_s)
25
+ @schemas_by_id[id.to_s]
28
26
  end
29
27
 
30
28
  # override to include write-thru cache after storing result from upstream
31
29
  def store_by_id(id, schema)
32
30
  # must return the value from storing the result (i.e. do not return result from file write)
33
- value = super(id.to_s, schema)
34
- File.write(@schemas_by_id_path, JSON.pretty_generate(@schemas_by_id))
35
- return value
31
+ @schemas_by_id[id.to_s] = schema
32
+ write_to_disk_cache(@schemas_by_id_path, @schemas_by_id)
33
+
34
+ schema
36
35
  end
37
36
 
38
37
  # override to use a json serializable cache key
@@ -45,7 +44,8 @@ class AvroTurf::DiskCache < AvroTurf::InMemoryCache
45
44
  def store_by_schema(subject, schema, id)
46
45
  key = "#{subject}#{schema}"
47
46
  @ids_by_schema[key] = id
48
- File.write(@ids_by_schema_path, JSON.pretty_generate(@ids_by_schema))
47
+
48
+ write_to_disk_cache(@ids_by_schema_path, @ids_by_schema)
49
49
  id
50
50
  end
51
51
 
@@ -78,7 +78,7 @@ class AvroTurf::DiskCache < AvroTurf::InMemoryCache
78
78
  hash[key] = schema
79
79
  hash
80
80
  else
81
- {key => schema}
81
+ { key => schema }
82
82
  end
83
83
 
84
84
  write_to_disk_cache(@schemas_by_subject_version_path, hash)
@@ -90,17 +90,27 @@ class AvroTurf::DiskCache < AvroTurf::InMemoryCache
90
90
  # Parse the file from disk, if it exists and is not zero length
91
91
  private def read_from_disk_cache(path)
92
92
  if File.exist?(path)
93
- if File.size(path)!=0
94
- return JSON.parse(File.read(path))
93
+ if File.size(path) != 0
94
+ json_data = File.open(path, 'r') do |file|
95
+ file.flock(File::LOCK_SH)
96
+ file.read
97
+ end
98
+
99
+ return JSON.parse(json_data)
95
100
  else
96
101
  # just log a message if skipping zero length file
97
102
  @logger.warn "skipping JSON.parse of zero length file at #{path}"
98
103
  end
99
104
  end
100
- return nil
105
+
106
+ nil
101
107
  end
102
108
 
103
109
  private def write_to_disk_cache(path, hash)
104
- File.write(path, JSON.pretty_generate(hash))
110
+ # don't use "w" because it truncates the file before lock
111
+ File.open(path, File::RDWR | File::CREAT, 0644) do |file|
112
+ file.flock(File::LOCK_EX)
113
+ file.write(JSON.pretty_generate(hash))
114
+ end
105
115
  end
106
116
  end
@@ -21,33 +21,47 @@ class AvroTurf
21
21
  # 1: https://github.com/confluentinc/schema-registry
22
22
  class Messaging
23
23
  MAGIC_BYTE = [0].pack("C").freeze
24
- DecodedMessage = Struct.new(:schema_id, :writer_schema, :reader_schema, :message)
25
- private_constant(:DecodedMessage)
24
+
25
+ class DecodedMessage
26
+ attr_reader :schema_id
27
+ attr_reader :writer_schema
28
+ attr_reader :reader_schema
29
+ attr_reader :message
30
+
31
+ def initialize(schema_id, writer_schema, reader_schema, message)
32
+ @schema_id = schema_id
33
+ @writer_schema = writer_schema
34
+ @reader_schema = reader_schema
35
+ @message = message
36
+ end
37
+ end
26
38
 
27
39
  # Instantiate a new Messaging instance with the given configuration.
28
40
  #
29
- # registry - A schema registry object that responds to all methods in the
30
- # AvroTurf::ConfluentSchemaRegistry interface.
31
- # registry_url - The String URL of the schema registry that should be used.
32
- # schema_store - A schema store object that responds to #find(schema_name, namespace).
33
- # schemas_path - The String file system path where local schemas are stored.
34
- # namespace - The String default schema namespace.
35
- # logger - The Logger that should be used to log information (optional).
36
- # proxy - Forward the request via proxy (optional).
37
- # user - User for basic auth (optional).
38
- # password - Password for basic auth (optional).
39
- # ssl_ca_file - Name of file containing CA certificate (optional).
40
- # client_cert - Name of file containing client certificate (optional).
41
- # client_key - Name of file containing client private key to go with client_cert (optional).
42
- # client_key_pass - Password to go with client_key (optional).
43
- # client_cert_data - In-memory client certificate (optional).
44
- # client_key_data - In-memory client private key to go with client_cert_data (optional).
41
+ # registry - A schema registry object that responds to all methods in the
42
+ # AvroTurf::ConfluentSchemaRegistry interface.
43
+ # registry_url - The String URL of the schema registry that should be used.
44
+ # schema_store - A schema store object that responds to #find(schema_name, namespace).
45
+ # schemas_path - The String file system path where local schemas are stored.
46
+ # namespace - The String default schema namespace.
47
+ # registry_path_prefix - The String URL path prefix used to namespace schema registry requests (optional).
48
+ # logger - The Logger that should be used to log information (optional).
49
+ # proxy - Forward the request via proxy (optional).
50
+ # user - User for basic auth (optional).
51
+ # password - Password for basic auth (optional).
52
+ # ssl_ca_file - Name of file containing CA certificate (optional).
53
+ # client_cert - Name of file containing client certificate (optional).
54
+ # client_key - Name of file containing client private key to go with client_cert (optional).
55
+ # client_key_pass - Password to go with client_key (optional).
56
+ # client_cert_data - In-memory client certificate (optional).
57
+ # client_key_data - In-memory client private key to go with client_cert_data (optional).
45
58
  def initialize(
46
59
  registry: nil,
47
60
  registry_url: nil,
48
61
  schema_store: nil,
49
62
  schemas_path: nil,
50
63
  namespace: nil,
64
+ registry_path_prefix: nil,
51
65
  logger: nil,
52
66
  proxy: nil,
53
67
  user: nil,
@@ -74,7 +88,8 @@ class AvroTurf
74
88
  client_key: client_key,
75
89
  client_key_pass: client_key_pass,
76
90
  client_cert_data: client_cert_data,
77
- client_key_data: client_key_data
91
+ client_key_data: client_key_data,
92
+ path_prefix: registry_path_prefix
78
93
  )
79
94
  )
80
95
  @schemas_by_id = {}
@@ -127,7 +142,7 @@ class AvroTurf
127
142
  writer.write(message, encoder)
128
143
 
129
144
  stream.string
130
- rescue Excon::Errors::NotFound
145
+ rescue Excon::Error::NotFound
131
146
  if schema_id
132
147
  raise SchemaNotFoundError.new("Schema with id: #{schema_id} is not found on registry")
133
148
  else
@@ -88,7 +88,7 @@ class AvroTurf::SchemaStore
88
88
  local_schemas_cache.each do |schema_name, schema|
89
89
  local_schemas_cache.delete(schema_name) unless File.exist?(build_schema_path(schema_name))
90
90
  end
91
- load_schema!(fullname, local_schemas_cache)
91
+ load_schema!(fullname, @schemas.dup)
92
92
  else
93
93
  raise
94
94
  end
@@ -0,0 +1,102 @@
1
+ require 'sinatra/base'
2
+
3
+ class FakePrefixedConfluentSchemaRegistryServer < FakeConfluentSchemaRegistryServer
4
+ post "/prefix/subjects/:subject/versions" do
5
+ schema = parse_schema
6
+ ids_for_subject = SUBJECTS[params[:subject]]
7
+
8
+ schemas_for_subject =
9
+ SCHEMAS.select
10
+ .with_index { |_, i| ids_for_subject.include?(i) }
11
+
12
+ if schemas_for_subject.include?(schema)
13
+ schema_id = SCHEMAS.index(schema)
14
+ else
15
+ SCHEMAS << schema
16
+ schema_id = SCHEMAS.size - 1
17
+ SUBJECTS[params[:subject]] = SUBJECTS[params[:subject]] << schema_id
18
+ end
19
+
20
+ { id: schema_id }.to_json
21
+ end
22
+
23
+ get "/prefix/schemas/ids/:schema_id" do
24
+ schema = SCHEMAS.at(params[:schema_id].to_i)
25
+ halt(404, SCHEMA_NOT_FOUND) unless schema
26
+ { schema: schema }.to_json
27
+ end
28
+
29
+ get "/prefix/subjects" do
30
+ SUBJECTS.keys.to_json
31
+ end
32
+
33
+ get "/prefix/subjects/:subject/versions" do
34
+ schema_ids = SUBJECTS[params[:subject]]
35
+ halt(404, SUBJECT_NOT_FOUND) if schema_ids.empty?
36
+ (1..schema_ids.size).to_a.to_json
37
+ end
38
+
39
+ get "/prefix/subjects/:subject/versions/:version" do
40
+ schema_ids = SUBJECTS[params[:subject]]
41
+ halt(404, SUBJECT_NOT_FOUND) if schema_ids.empty?
42
+
43
+ schema_id = if params[:version] == 'latest'
44
+ schema_ids.last
45
+ else
46
+ schema_ids.at(Integer(params[:version]) - 1)
47
+ end
48
+ halt(404, VERSION_NOT_FOUND) unless schema_id
49
+
50
+ schema = SCHEMAS.at(schema_id)
51
+
52
+ {
53
+ name: params[:subject],
54
+ version: schema_ids.index(schema_id) + 1,
55
+ id: schema_id,
56
+ schema: schema
57
+ }.to_json
58
+ end
59
+
60
+ post "/prefix/subjects/:subject" do
61
+ schema = parse_schema
62
+
63
+ # Note: this does not actually handle the same schema registered under
64
+ # multiple subjects
65
+ schema_id = SCHEMAS.index(schema)
66
+
67
+ halt(404, SCHEMA_NOT_FOUND) unless schema_id
68
+
69
+ {
70
+ subject: params[:subject],
71
+ id: schema_id,
72
+ version: SUBJECTS[params[:subject]].index(schema_id) + 1,
73
+ schema: schema
74
+ }.to_json
75
+ end
76
+
77
+ post "/prefix/compatibility/subjects/:subject/versions/:version" do
78
+ # The ruby avro gem does not yet include a compatibility check between schemas.
79
+ # See https://github.com/apache/avro/pull/170
80
+ raise NotImplementedError
81
+ end
82
+
83
+ get "/prefix/config" do
84
+ global_config.to_json
85
+ end
86
+
87
+ put "/prefix/config" do
88
+ global_config.merge!(parse_config).to_json
89
+ end
90
+
91
+ get "/prefix/config/:subject" do
92
+ CONFIGS.fetch(params[:subject], global_config).to_json
93
+ end
94
+
95
+ put "/prefix/config/:subject" do
96
+ config = parse_config
97
+ subject = params[:subject]
98
+ CONFIGS.fetch(subject) do
99
+ CONFIGS[subject] = {}
100
+ end.merge!(config).to_json
101
+ end
102
+ end
@@ -1,3 +1,3 @@
1
1
  class AvroTurf
2
- VERSION = "1.5.0"
2
+ VERSION = "1.8.0"
3
3
  end
data/lib/avro_turf.rb CHANGED
@@ -16,7 +16,9 @@ end
16
16
 
17
17
  class AvroTurf
18
18
  class Error < StandardError; end
19
+
19
20
  class SchemaError < Error; end
21
+
20
22
  class SchemaNotFoundError < Error; end
21
23
 
22
24
  DEFAULT_SCHEMAS_PATH = "./schemas"
@@ -31,7 +33,7 @@ class AvroTurf
31
33
  # Currently, the only valid codec name is `deflate`.
32
34
  def initialize(schemas_path: nil, schema_store: nil, namespace: nil, codec: nil)
33
35
  @namespace = namespace
34
- @schema_store = schema_store ||
36
+ @schema_store = schema_store ||
35
37
  SchemaStore.new(path: schemas_path || DEFAULT_SCHEMAS_PATH)
36
38
  @codec = codec
37
39
  end
@@ -62,14 +64,20 @@ class AvroTurf
62
64
  # validate - The boolean for performing complete data validation before
63
65
  # encoding it, Avro::SchemaValidator::ValidationError with
64
66
  # a descriptive message will be raised in case of invalid message.
67
+ # validate_options - Hash for the Avro::SchemaValidator, default
68
+ # {recursive: true, encoded: false, fail_on_extra_fields: true}
65
69
  #
66
70
  # Returns nothing.
67
- def encode_to_stream(data, schema_name: nil, stream: nil, namespace: @namespace, validate: false)
71
+ def encode_to_stream(data, schema_name: nil, stream: nil, namespace: @namespace,
72
+ validate: false,
73
+ validate_options: { recursive: true,
74
+ encoded: false,
75
+ fail_on_extra_fields: true })
68
76
  schema = @schema_store.find(schema_name, namespace)
69
77
  writer = Avro::IO::DatumWriter.new(schema)
70
78
 
71
79
  if validate
72
- Avro::SchemaValidator.validate!(schema, data, recursive: true, encoded: false, fail_on_extra_fields: true)
80
+ Avro::SchemaValidator.validate!(schema, data, **validate_options)
73
81
  end
74
82
 
75
83
  dw = Avro::DataFile::Writer.new(stream, writer, schema, @codec)
@@ -16,6 +16,13 @@ describe AvroTurf do
16
16
  {
17
17
  "type": "string",
18
18
  "name": "full_name"
19
+ },
20
+ {
21
+ "name": "birth_date",
22
+ "type": {
23
+ "type": "int",
24
+ "logicalType": "date"
25
+ }
19
26
  }
20
27
  ]
21
28
  }
@@ -24,7 +31,8 @@ describe AvroTurf do
24
31
 
25
32
  it "encodes data with Avro" do
26
33
  data = {
27
- "full_name" => "John Doe"
34
+ "full_name" => "John Doe",
35
+ "birth_date" => Date.new(1934, 1, 2)
28
36
  }
29
37
 
30
38
  encoded_data = avro.encode(data, schema_name: "person")
@@ -36,7 +44,8 @@ describe AvroTurf do
36
44
  compressed_avro = AvroTurf.new(schemas_path: "spec/schemas/", codec: "deflate")
37
45
 
38
46
  data = {
39
- "full_name" => "John Doe" * 100
47
+ "full_name" => "John Doe" * 100,
48
+ "birth_date" => Date.new(1934, 1, 2)
40
49
  }
41
50
 
42
51
  uncompressed_data = avro.encode(data, schema_name: "person")
@@ -251,6 +260,31 @@ describe AvroTurf do
251
260
  expect { encode_to_stream }.to raise_error(Avro::SchemaValidator::ValidationError, /extra field 'fulll_name'/)
252
261
  end
253
262
  end
263
+
264
+ context "when the `fail_on_extra_fields` validation option is disabled" do
265
+ let(:message) { { "full_name" => "John Doe", "first_name" => "John", "last_name" => "Doe" } }
266
+ subject(:encode_to_stream) do
267
+ stream = StringIO.new
268
+ avro.encode_to_stream(message, stream: stream, schema_name: "message",
269
+ validate: true,
270
+ validate_options: { recursive: true, encoded: false, fail_on_extra_fields: false }
271
+ )
272
+ end
273
+
274
+ it "should not raise Avro::SchemaValidator::ValidationError with a message about extra field" do
275
+ define_schema "message.avsc", <<-AVSC
276
+ {
277
+ "name": "message",
278
+ "type": "record",
279
+ "fields": [
280
+ { "name": "full_name", "type": "string" }
281
+ ]
282
+ }
283
+ AVSC
284
+
285
+ expect { encode_to_stream }.not_to raise_error
286
+ end
287
+ end
254
288
  end
255
289
  end
256
290
 
@@ -304,5 +338,33 @@ describe AvroTurf do
304
338
  datum = { message: "hello" }
305
339
  expect(avro.valid?(datum, schema_name: "postcard")).to eq true
306
340
  end
341
+
342
+ it "handles logicalType of date in schema" do
343
+ define_schema "postcard.avsc", <<-AVSC
344
+ {
345
+ "name": "postcard",
346
+ "type": "record",
347
+ "fields": [
348
+ {
349
+ "name": "message",
350
+ "type": "string"
351
+ },
352
+ {
353
+ "name": "sent_date",
354
+ "type": {
355
+ "type": "int",
356
+ "logicalType": "date"
357
+ }
358
+ }
359
+ ]
360
+ }
361
+ AVSC
362
+
363
+ datum = {
364
+ message: "hello",
365
+ sent_date: Date.new(2022, 9, 11)
366
+ }
367
+ expect(avro.valid?(datum, schema_name: "postcard")).to eq true
368
+ end
307
369
  end
308
370
  end
@@ -1,6 +1,6 @@
1
1
  describe Date, "#as_avro" do
2
- it "returns an ISO8601 string describing the time" do
2
+ it "returns Date object describing the time" do
3
3
  date = Date.today
4
- expect(date.as_avro).to eq(date.iso8601)
4
+ expect(date.as_avro).to eq(date)
5
5
  end
6
6
  end
@@ -1,6 +1,7 @@
1
1
  require 'webmock/rspec'
2
2
  require 'avro_turf/messaging'
3
3
  require 'avro_turf/test/fake_confluent_schema_registry_server'
4
+ require 'avro_turf/test/fake_prefixed_confluent_schema_registry_server'
4
5
 
5
6
  describe AvroTurf::Messaging do
6
7
  let(:registry_url) { "http://registry.example.com" }
@@ -8,7 +9,7 @@ describe AvroTurf::Messaging do
8
9
  let(:client_key) { "test client key" }
9
10
  let(:client_key_pass) { "test client key password" }
10
11
  let(:logger) { Logger.new(StringIO.new) }
11
-
12
+ let(:path_prefix) { nil }
12
13
  let(:avro) {
13
14
  AvroTurf::Messaging.new(
14
15
  registry_url: registry_url,
@@ -72,7 +73,7 @@ describe AvroTurf::Messaging do
72
73
 
73
74
  shared_examples_for 'encoding and decoding with the schema from registry' do
74
75
  before do
75
- registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger)
76
+ registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger, path_prefix: path_prefix)
76
77
  registry.register('person', schema)
77
78
  registry.register('people', schema)
78
79
  end
@@ -102,7 +103,7 @@ describe AvroTurf::Messaging do
102
103
 
103
104
  shared_examples_for 'encoding and decoding with the schema_id from registry' do
104
105
  before do
105
- registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger)
106
+ registry = AvroTurf::ConfluentSchemaRegistry.new(registry_url, logger: logger, path_prefix: path_prefix)
106
107
  registry.register('person', schema)
107
108
  registry.register('people', schema)
108
109
  end
@@ -399,4 +400,29 @@ describe AvroTurf::Messaging do
399
400
  end
400
401
  end
401
402
  end
402
- end
403
+
404
+ context 'with a registry path prefix' do
405
+ let(:path_prefix) { '/prefix' }
406
+
407
+ let(:avro) {
408
+ AvroTurf::Messaging.new(
409
+ registry_path_prefix: path_prefix,
410
+ registry_url: registry_url,
411
+ schemas_path: "spec/schemas",
412
+ logger: logger,
413
+ client_cert: client_cert,
414
+ client_key: client_key,
415
+ client_key_pass: client_key_pass
416
+ )
417
+ }
418
+
419
+ before do
420
+ stub_request(:any, /^#{registry_url}/).to_rack(FakePrefixedConfluentSchemaRegistryServer)
421
+ FakePrefixedConfluentSchemaRegistryServer.clear
422
+ end
423
+
424
+ it_behaves_like "encoding and decoding with the schema from schema store"
425
+ it_behaves_like 'encoding and decoding with the schema from registry'
426
+ it_behaves_like 'encoding and decoding with the schema_id from registry'
427
+ end
428
+ end
@@ -26,6 +26,33 @@ describe AvroTurf::SchemaStore do
26
26
  expect(schema.fullname).to eq "message"
27
27
  end
28
28
 
29
+ it "resolves missing references when nested schema is not a named type" do
30
+ define_schema "root.avsc", <<-AVSC
31
+ {
32
+ "type": "record",
33
+ "name": "root",
34
+ "fields": [
35
+ {
36
+ "type": "nested",
37
+ "name": "nested_value"
38
+ }
39
+ ]
40
+ }
41
+ AVSC
42
+
43
+ define_schema "nested.avsc", <<-AVSC
44
+ {
45
+ "name": "nested",
46
+ "type": "string",
47
+ "logicalType": "uuid"
48
+ }
49
+ AVSC
50
+
51
+ schema = store.find("root")
52
+
53
+ expect(schema.fullname).to eq "root"
54
+ end
55
+
29
56
  it "resolves missing references" do
30
57
  define_schema "person.avsc", <<-AVSC
31
58
  {
data/spec/spec_helper.rb CHANGED
@@ -22,6 +22,16 @@ module Helpers
22
22
  end
23
23
  end
24
24
 
25
+ # gem `fakefs` does not support flock for the file, and require patch
26
+ # https://github.com/fakefs/fakefs/issues/433
27
+ module FakeFS
28
+ class File < StringIO
29
+ def flock(*)
30
+ true
31
+ end
32
+ end
33
+ end
34
+
25
35
  RSpec.configure do |config|
26
36
  config.include FakeFS::SpecHelpers
27
37
  config.include Helpers
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: avro_turf
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Schierbeck
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-14 00:00:00.000000000 Z
11
+ date: 2022-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: avro
@@ -156,7 +156,7 @@ dependencies:
156
156
  - - ">="
157
157
  - !ruby/object:Gem::Version
158
158
  version: '0'
159
- description:
159
+ description:
160
160
  email:
161
161
  - dasch@zendesk.com
162
162
  executables: []
@@ -196,6 +196,7 @@ files:
196
196
  - lib/avro_turf/schema_store.rb
197
197
  - lib/avro_turf/schema_to_avro_patch.rb
198
198
  - lib/avro_turf/test/fake_confluent_schema_registry_server.rb
199
+ - lib/avro_turf/test/fake_prefixed_confluent_schema_registry_server.rb
199
200
  - lib/avro_turf/test/fake_schema_registry_server.rb
200
201
  - lib/avro_turf/version.rb
201
202
  - perf/address.avsc
@@ -250,8 +251,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
250
251
  - !ruby/object:Gem::Version
251
252
  version: '0'
252
253
  requirements: []
253
- rubygems_version: 3.1.2
254
- signing_key:
254
+ rubygems_version: 3.3.3
255
+ signing_key:
255
256
  specification_version: 4
256
257
  summary: A library that makes it easier to use the Avro serialization format from
257
258
  Ruby