deimos-ruby 2.3.0.pre.beta4 → 2.3.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +3 -1
- data/README.md +8 -0
- data/deimos-ruby.gemspec +2 -2
- data/lib/deimos/backends/kafka.rb +1 -1
- data/lib/deimos/backends/kafka_async.rb +2 -1
- data/lib/deimos/config/configuration.rb +1 -1
- data/lib/deimos/ext/producer_middleware.rb +2 -2
- data/lib/deimos/kafka_source.rb +1 -1
- data/lib/deimos/metrics/datadog.rb +3 -1
- data/lib/deimos/schema_backends/avro_base.rb +6 -4
- data/lib/deimos/schema_backends/avro_local.rb +12 -13
- data/lib/deimos/schema_backends/avro_schema_registry.rb +15 -14
- data/lib/deimos/schema_backends/avro_validation.rb +1 -1
- data/lib/deimos/schema_backends/base.rb +4 -5
- data/lib/deimos/schema_backends/mock.rb +1 -1
- data/lib/deimos/schema_backends/plain.rb +1 -1
- data/lib/deimos/schema_backends/proto_base.rb +11 -36
- data/lib/deimos/schema_backends/proto_local.rb +5 -5
- data/lib/deimos/schema_backends/proto_schema_registry.rb +7 -32
- data/lib/deimos/test_helpers.rb +8 -0
- data/lib/deimos/transcoder.rb +1 -1
- data/lib/deimos/utils/outbox_producer.rb +2 -2
- data/lib/deimos/version.rb +1 -1
- data/lib/deimos.rb +35 -15
- data/lib/generators/deimos/active_record_generator.rb +1 -1
- data/lib/generators/deimos/schema_class_generator.rb +3 -3
- data/lib/generators/deimos/v2_generator.rb +2 -2
- data/spec/deimos_spec.rb +32 -0
- data/spec/generators/schema_class_generator_spec.rb +4 -5
- data/spec/schema_backends/avro_base_shared.rb +1 -1
- data/spec/schema_backends/avro_local_spec.rb +8 -1
- data/spec/schema_backends/avro_schema_registry_spec.rb +7 -7
- data/spec/schema_backends/base_spec.rb +2 -2
- data/spec/schema_backends/proto_schema_registry_spec.rb +19 -222
- data/spec/snapshots/consumers-no-nest.snap +7 -7
- data/spec/snapshots/consumers.snap +7 -7
- data/spec/snapshots/consumers_and_producers-no-nest.snap +7 -7
- data/spec/snapshots/consumers_and_producers.snap +7 -7
- data/spec/snapshots/consumers_circular-no-nest.snap +7 -7
- data/spec/snapshots/consumers_circular.snap +7 -7
- data/spec/snapshots/consumers_complex_types-no-nest.snap +7 -7
- data/spec/snapshots/consumers_complex_types.snap +7 -7
- data/spec/snapshots/consumers_nested-no-nest.snap +7 -7
- data/spec/snapshots/consumers_nested.snap +7 -7
- data/spec/snapshots/namespace_folders.snap +7 -7
- data/spec/snapshots/namespace_map.snap +7 -7
- data/spec/snapshots/producers_with_key-no-nest.snap +7 -7
- data/spec/snapshots/producers_with_key.snap +7 -7
- data/spec/spec_helper.rb +1 -1
- metadata +35 -32
- data/CLAUDE.md +0 -270
- data/spec/gen/sample/v1/sample_key_pb.rb +0 -17
- data/spec/protos/sample/v1/sample_key.proto +0 -7
|
@@ -13,7 +13,7 @@ module Deimos
|
|
|
13
13
|
# @return [Array<Symbol>]
|
|
14
14
|
SPECIAL_TYPES = %i(record enum).freeze
|
|
15
15
|
# @return [String]
|
|
16
|
-
INITIALIZE_WHITESPACE = "\n#{' ' * 19}"
|
|
16
|
+
INITIALIZE_WHITESPACE = "\n#{' ' * 19}"
|
|
17
17
|
# @return [Array<String>]
|
|
18
18
|
IGNORE_DEFAULTS = %w(message_id timestamp).freeze
|
|
19
19
|
# @return [String]
|
|
@@ -192,7 +192,7 @@ module Deimos
|
|
|
192
192
|
|
|
193
193
|
def generate_from_schema_files(found_schemas)
|
|
194
194
|
path = Deimos.config.schema.path || Deimos.config.schema.paths[:avro].first
|
|
195
|
-
schema_store =
|
|
195
|
+
schema_store = AvroTurf::MutableSchemaStore.new(path: path)
|
|
196
196
|
schema_store.load_schemas!
|
|
197
197
|
schema_store.schemas.values.sort_by { |s| "#{s.namespace}#{s.name}" }.each do |schema|
|
|
198
198
|
name = "#{schema.namespace}.#{schema.name}"
|
|
@@ -265,7 +265,7 @@ module Deimos
|
|
|
265
265
|
end
|
|
266
266
|
|
|
267
267
|
result = "def initialize(_from_message: false, #{arguments.first}"
|
|
268
|
-
arguments[1
|
|
268
|
+
arguments[1..-1].each_with_index do |arg, _i|
|
|
269
269
|
result += ",#{INITIALIZE_WHITESPACE}#{arg}"
|
|
270
270
|
end
|
|
271
271
|
"#{result})"
|
|
@@ -119,7 +119,7 @@ module Deimos
|
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def consumer_configs
|
|
122
|
-
deimos_config.consumer_objects.group_by(&:group_id).
|
|
122
|
+
deimos_config.consumer_objects.group_by(&:group_id).map { |group_id, consumers|
|
|
123
123
|
[group_id, consumers.map do |consumer|
|
|
124
124
|
kafka_configs = {}
|
|
125
125
|
kafka_configs['auto.offset.reset'] = consumer.start_from_beginning ? 'earliest' : 'latest'
|
|
@@ -159,7 +159,7 @@ module Deimos
|
|
|
159
159
|
configs[:each_message] = true unless consumer.delivery.to_s == 'inline_batch'
|
|
160
160
|
configs
|
|
161
161
|
end]
|
|
162
|
-
|
|
162
|
+
}.to_h
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
def producer_configs
|
data/spec/deimos_spec.rb
CHANGED
|
@@ -50,4 +50,36 @@ describe Deimos do
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
specify '#producer_for' do
|
|
54
|
+
allow(described_class).to receive(:producer_for).and_call_original
|
|
55
|
+
Karafka::App.routes.redraw do
|
|
56
|
+
topic 'main-broker' do
|
|
57
|
+
active false
|
|
58
|
+
kafka({
|
|
59
|
+
'bootstrap.servers': 'broker1:9092'
|
|
60
|
+
})
|
|
61
|
+
end
|
|
62
|
+
topic 'main-broker2' do
|
|
63
|
+
active false
|
|
64
|
+
kafka({
|
|
65
|
+
'bootstrap.servers': 'broker1:9092'
|
|
66
|
+
})
|
|
67
|
+
end
|
|
68
|
+
topic 'other-broker' do
|
|
69
|
+
active false
|
|
70
|
+
kafka({
|
|
71
|
+
'bootstrap.servers': 'broker2:9092'
|
|
72
|
+
})
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
described_class.setup_producers
|
|
76
|
+
|
|
77
|
+
producer1 = described_class.producer_for('main-broker')
|
|
78
|
+
producer2 = described_class.producer_for('main-broker2')
|
|
79
|
+
producer3 = described_class.producer_for('other-broker')
|
|
80
|
+
expect(producer1).to eq(producer2)
|
|
81
|
+
expect(producer1.config.kafka[:'bootstrap.servers']).to eq('broker1:9092')
|
|
82
|
+
expect(producer3.config.kafka[:'bootstrap.servers']).to eq('broker2:9092')
|
|
83
|
+
end
|
|
84
|
+
|
|
53
85
|
end
|
|
@@ -20,7 +20,7 @@ end
|
|
|
20
20
|
|
|
21
21
|
RSpec.describe Deimos::Generators::SchemaClassGenerator do
|
|
22
22
|
let(:schema_class_path) { 'spec/app/lib/schema_classes' }
|
|
23
|
-
let(:files) { Dir["#{schema_class_path}/**/*.rb"].
|
|
23
|
+
let(:files) { Dir["#{schema_class_path}/**/*.rb"].map { |f| [f, File.read(f)]}.to_h }
|
|
24
24
|
|
|
25
25
|
before(:each) do
|
|
26
26
|
Deimos.config.reset!
|
|
@@ -37,10 +37,9 @@ RSpec.describe Deimos::Generators::SchemaClassGenerator do
|
|
|
37
37
|
|
|
38
38
|
context 'with a Consumers Schema' do
|
|
39
39
|
before(:each) do
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
topic 'MyTopic'
|
|
40
|
+
Karafka::App.routes.redraw do
|
|
41
|
+
topic 'MyTopic' do
|
|
42
|
+
consumer ConsumerTest::MyConsumer
|
|
44
43
|
schema 'Generated'
|
|
45
44
|
namespace 'com.my-namespace'
|
|
46
45
|
key_config field: :a_string
|
|
@@ -66,7 +66,7 @@ RSpec.shared_examples_for('an Avro backend') do
|
|
|
66
66
|
expect(backend.encode_key('test_id', 1, topic: 'topic')).to eq('itsme')
|
|
67
67
|
expect(backend).to have_received(:encode).
|
|
68
68
|
with({ 'test_id' => 1 }, { schema: 'MySchema_key', topic: 'topic' })
|
|
69
|
-
expect(backend.schema_store.find('com.my-namespace
|
|
69
|
+
expect(backend.schema_store.find('MySchema_key', 'com.my-namespace').to_avro).
|
|
70
70
|
to eq(
|
|
71
71
|
'doc' => 'Key for com.my-namespace.MySchema - autogenerated by Deimos',
|
|
72
72
|
'fields' => [
|
|
@@ -15,10 +15,17 @@ RSpec.describe Deimos::SchemaBackends::AvroLocal do
|
|
|
15
15
|
it_should_behave_like 'an Avro backend'
|
|
16
16
|
|
|
17
17
|
it 'should encode and decode correctly' do
|
|
18
|
+
avro_turf = instance_double(AvroTurf)
|
|
19
|
+
allow(avro_turf).to receive_messages(encode: 'encoded-payload', decode: payload)
|
|
20
|
+
allow(backend).to receive(:avro_turf).and_return(avro_turf)
|
|
18
21
|
results = backend.encode(payload)
|
|
19
|
-
expect(results).to
|
|
22
|
+
expect(results).to eq('encoded-payload')
|
|
20
23
|
results = backend.decode(results)
|
|
21
24
|
expect(results).to eq(payload)
|
|
25
|
+
expect(avro_turf).to have_received(:encode).
|
|
26
|
+
with(payload, schema_name: 'MySchema', namespace: 'com.my-namespace')
|
|
27
|
+
expect(avro_turf).to have_received(:decode).
|
|
28
|
+
with('encoded-payload', schema_name: 'MySchema', namespace: 'com.my-namespace')
|
|
22
29
|
end
|
|
23
30
|
|
|
24
31
|
end
|
|
@@ -15,17 +15,17 @@ RSpec.describe Deimos::SchemaBackends::AvroSchemaRegistry do
|
|
|
15
15
|
it_should_behave_like 'an Avro backend'
|
|
16
16
|
|
|
17
17
|
it 'should encode and decode correctly' do
|
|
18
|
-
|
|
19
|
-
allow(
|
|
20
|
-
allow(backend).to receive(:
|
|
18
|
+
avro_turf = instance_double(AvroTurf::Messaging)
|
|
19
|
+
allow(avro_turf).to receive_messages(encode: 'encoded-payload', decode: payload)
|
|
20
|
+
allow(backend).to receive(:avro_turf_messaging).and_return(avro_turf)
|
|
21
21
|
results = backend.encode(payload, topic: 'topic')
|
|
22
22
|
expect(results).to eq('encoded-payload')
|
|
23
23
|
results = backend.decode(results)
|
|
24
24
|
expect(results).to eq(payload)
|
|
25
|
-
expect(
|
|
26
|
-
with(payload, schema_name: '
|
|
27
|
-
expect(
|
|
28
|
-
with('encoded-payload')
|
|
25
|
+
expect(avro_turf).to have_received(:encode).
|
|
26
|
+
with(payload, schema_name: 'MySchema', subject: 'topic')
|
|
27
|
+
expect(avro_turf).to have_received(:decode).
|
|
28
|
+
with('encoded-payload', schema_name: 'MySchema')
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
end
|
|
@@ -6,13 +6,13 @@ describe Deimos::SchemaBackends::Base do
|
|
|
6
6
|
|
|
7
7
|
it 'should validate on encode' do
|
|
8
8
|
expect(backend).to receive(:validate).with(payload, schema: 'schema')
|
|
9
|
-
expect(backend).to receive(:encode_payload).with(payload, schema: 'schema',
|
|
9
|
+
expect(backend).to receive(:encode_payload).with(payload, schema: 'schema', topic: 'topic')
|
|
10
10
|
backend.encode(payload, topic: 'topic')
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
it 'should validate and encode a passed schema' do
|
|
14
14
|
expect(backend).to receive(:validate).with(payload, schema: 'schema2')
|
|
15
|
-
expect(backend).to receive(:encode_payload).with(payload, schema: 'schema2',
|
|
15
|
+
expect(backend).to receive(:encode_payload).with(payload, schema: 'schema2', topic: 'topic')
|
|
16
16
|
backend.encode(payload, schema: 'schema2', topic: 'topic')
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
require 'deimos/schema_backends/proto_schema_registry'
|
|
4
4
|
require_relative "#{__dir__}/../gen/sample/v1/sample_pb"
|
|
5
|
-
require_relative "#{__dir__}/../gen/sample/v1/sample_key_pb"
|
|
6
5
|
|
|
7
6
|
RSpec.describe Deimos::SchemaBackends::ProtoSchemaRegistry do
|
|
8
7
|
let(:payload) do
|
|
@@ -17,234 +16,32 @@ RSpec.describe Deimos::SchemaBackends::ProtoSchemaRegistry do
|
|
|
17
16
|
str_map: { 'foo' => 'bar' }
|
|
18
17
|
)
|
|
19
18
|
end
|
|
20
|
-
let(:schema_registry) { instance_double(SchemaRegistry::Client) }
|
|
21
|
-
let(:key_schema_registry) { instance_double(SchemaRegistry::Client) }
|
|
22
19
|
|
|
23
20
|
let(:backend) { described_class.new(schema: 'sample.v1.SampleMessage') }
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
specify('#encode_key') do
|
|
23
|
+
expect(backend.encode_key(nil, 789)).to eq('789')
|
|
24
|
+
expect(backend.encode_key(nil, 'string')).to eq('string')
|
|
25
|
+
expect(backend.encode_key(nil, { foo: 'bar' })).to eq('{"foo":"bar"}')
|
|
26
|
+
expect(backend.encode_key(:foo, 'bar')).to eq('bar')
|
|
28
27
|
end
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# Encode
|
|
35
|
-
encoded = backend.encode(payload, topic: 'topic')
|
|
36
|
-
expect(encoded).to eq('encoded-payload')
|
|
37
|
-
expect(schema_registry).to have_received(:encode).with(payload, subject: 'topic-value')
|
|
38
|
-
|
|
39
|
-
# Decode
|
|
40
|
-
decoded = backend.decode(encoded)
|
|
41
|
-
expect(decoded).to eq(payload)
|
|
42
|
-
expect(schema_registry).to have_received(:decode).with('encoded-payload')
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
it 'should encode hash payloads by converting to protobuf message' do
|
|
46
|
-
hash_payload = {
|
|
47
|
-
str: 'string',
|
|
48
|
-
num: 123,
|
|
49
|
-
flag: true
|
|
50
|
-
}
|
|
51
|
-
allow(schema_registry).to receive(:encode).and_return('encoded-payload')
|
|
52
|
-
|
|
53
|
-
backend.encode(hash_payload, topic: 'topic')
|
|
54
|
-
|
|
55
|
-
# Should have converted hash to protobuf message before encoding
|
|
56
|
-
expect(schema_registry).to have_received(:encode) do |arg, **kwargs|
|
|
57
|
-
expect(arg).to be_a(Sample::V1::SampleMessage)
|
|
58
|
-
expect(arg.str).to eq('string')
|
|
59
|
-
expect(arg.num).to eq(123)
|
|
60
|
-
expect(arg.flag).to be(true)
|
|
61
|
-
expect(kwargs).to eq(subject: 'topic-value')
|
|
62
|
-
end
|
|
63
|
-
end
|
|
29
|
+
specify('#decode_key') do
|
|
30
|
+
expect(backend.decode_key('789', nil)).to eq(789)
|
|
31
|
+
expect(backend.decode_key('{"foo":"bar"}', :foo)).to eq('bar')
|
|
32
|
+
expect(backend.decode_key('{"foo":"bar"}', nil)).to eq({ 'foo' => 'bar' })
|
|
64
33
|
end
|
|
65
34
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
key_hash,
|
|
77
|
-
subject: 'my-topic-key',
|
|
78
|
-
schema_text: anything
|
|
79
|
-
)
|
|
80
|
-
expect(encoded).to eq('encoded-key')
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
it 'should encode a hash key with field extraction using JSON schema' do
|
|
84
|
-
full_payload = { 'str' => 'test-key', 'num' => 123 }
|
|
85
|
-
key_hash = { 'str' => 'test-key' }
|
|
86
|
-
|
|
87
|
-
allow(key_schema_registry).to receive(:encode).and_return('encoded-key')
|
|
88
|
-
|
|
89
|
-
encoded = backend.encode_key('str', full_payload, topic: 'my-topic')
|
|
90
|
-
|
|
91
|
-
expect(key_schema_registry).to have_received(:encode).with(
|
|
92
|
-
key_hash,
|
|
93
|
-
subject: 'my-topic-key',
|
|
94
|
-
schema_text: anything
|
|
95
|
-
)
|
|
96
|
-
expect(encoded).to eq('encoded-key')
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
it 'should decode a JSON schema key' do
|
|
100
|
-
decoded_json = { 'str' => 'test-key' }
|
|
101
|
-
allow(key_schema_registry).to receive(:decode).and_return(decoded_json)
|
|
102
|
-
|
|
103
|
-
result = backend.decode_key('encoded-key', 'str')
|
|
104
|
-
|
|
105
|
-
expect(key_schema_registry).to have_received(:decode).with('encoded-key')
|
|
106
|
-
expect(result).to eq('test-key')
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it 'should decode a JSON schema key without field extraction' do
|
|
110
|
-
decoded_json = { 'str' => 'test-key', 'num' => 123 }
|
|
111
|
-
allow(key_schema_registry).to receive(:decode).and_return(decoded_json)
|
|
112
|
-
|
|
113
|
-
result = backend.decode_key('encoded-key', nil)
|
|
114
|
-
|
|
115
|
-
expect(key_schema_registry).to have_received(:decode).with('encoded-key')
|
|
116
|
-
expect(result).to eq(decoded_json)
|
|
117
|
-
end
|
|
35
|
+
it 'should encode and decode correctly' do
|
|
36
|
+
proto_turf = instance_double(ProtoTurf)
|
|
37
|
+
allow(proto_turf).to receive_messages(encode: 'encoded-payload', decode: payload)
|
|
38
|
+
allow(described_class).to receive(:proto_turf).and_return(proto_turf)
|
|
39
|
+
results = backend.encode(payload, topic: 'topic')
|
|
40
|
+
expect(results).to eq('encoded-payload')
|
|
41
|
+
results = backend.decode(results)
|
|
42
|
+
expect(results).to eq(payload)
|
|
43
|
+
expect(proto_turf).to have_received(:encode).with(payload, subject: 'topic')
|
|
44
|
+
expect(proto_turf).to have_received(:decode).with('encoded-payload')
|
|
118
45
|
end
|
|
119
46
|
|
|
120
|
-
describe 'key encoding with key_config schema (separate Protobuf schema)' do
|
|
121
|
-
let(:key_backend) { described_class.new(schema: 'sample.v1.SampleMessageKey') }
|
|
122
|
-
let(:key_schema_registry_for_test) { instance_double(SchemaRegistry::Client) }
|
|
123
|
-
let(:schema_registry_for_test) { instance_double(SchemaRegistry::Client) }
|
|
124
|
-
|
|
125
|
-
before(:each) do
|
|
126
|
-
# For key_backend tests, mock both schema_registry instances
|
|
127
|
-
allow(described_class).to receive_messages(schema_registry: schema_registry_for_test,
|
|
128
|
-
key_schema_registry: key_schema_registry_for_test)
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
it 'should encode a protobuf key message using the key schema' do
|
|
132
|
-
key_msg = Sample::V1::SampleMessageKey.new(str: 'test-key')
|
|
133
|
-
# Since subject ends with '-key', encode_payload uses key_schema_registry
|
|
134
|
-
allow(key_schema_registry_for_test).to receive(:encode).and_return('encoded-key')
|
|
135
|
-
|
|
136
|
-
encoded = key_backend.encode(key_msg, topic: 'my-topic', is_key: true)
|
|
137
|
-
|
|
138
|
-
expect(key_schema_registry_for_test).to have_received(:encode).with(key_msg, subject: 'my-topic-key')
|
|
139
|
-
expect(encoded).to eq('encoded-key')
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
it 'should encode a hash key using the key schema' do
|
|
143
|
-
key_hash = { str: 'test-key' }
|
|
144
|
-
allow(key_schema_registry_for_test).to receive(:encode).and_return('encoded-key')
|
|
145
|
-
|
|
146
|
-
encoded = key_backend.encode(key_hash, topic: 'my-topic', is_key: true)
|
|
147
|
-
|
|
148
|
-
expect(key_schema_registry_for_test).to have_received(:encode) do |arg, **kwargs|
|
|
149
|
-
expect(arg).to be_a(Sample::V1::SampleMessageKey)
|
|
150
|
-
expect(arg.str).to eq('test-key')
|
|
151
|
-
expect(kwargs).to eq(subject: 'my-topic-key')
|
|
152
|
-
end
|
|
153
|
-
expect(encoded).to eq('encoded-key')
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
it 'should decode a protobuf key' do
|
|
157
|
-
key_msg = Sample::V1::SampleMessageKey.new(str: 'test-key')
|
|
158
|
-
allow(schema_registry_for_test).to receive(:decode).and_return(key_msg)
|
|
159
|
-
|
|
160
|
-
decoded = key_backend.decode('encoded-key')
|
|
161
|
-
|
|
162
|
-
expect(schema_registry_for_test).to have_received(:decode).with('encoded-key')
|
|
163
|
-
expect(decoded).to eq(key_msg)
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
describe 'backward compatibility with plain string/JSON keys' do
|
|
168
|
-
it 'should encode plain string keys as strings' do
|
|
169
|
-
expect(backend.encode_key(nil, 'simple-string', topic: 'my-topic')).to eq('simple-string')
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
it 'should encode integer keys as strings' do
|
|
173
|
-
expect(backend.encode_key(nil, 789, topic: 'my-topic')).to eq('789')
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
it 'should encode hash keys using JSON schema when no field specified' do
|
|
177
|
-
key_hash = { foo: 'bar', baz: 'qux' }
|
|
178
|
-
allow(key_schema_registry).to receive(:encode).and_return('encoded-json')
|
|
179
|
-
|
|
180
|
-
backend.encode_key(nil, key_hash, topic: 'my-topic')
|
|
181
|
-
|
|
182
|
-
# Should use encode_proto_key which calls key_schema_registry.encode
|
|
183
|
-
expect(key_schema_registry).to have_received(:encode)
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
it 'should decode JSON string keys to hashes' do
|
|
187
|
-
decoded_hash = { 'foo' => 'bar' }
|
|
188
|
-
allow(key_schema_registry).to receive(:decode).and_return(decoded_hash)
|
|
189
|
-
|
|
190
|
-
result = backend.decode_key('{"foo":"bar"}', nil)
|
|
191
|
-
expect(result).to eq(decoded_hash)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
it 'should decode JSON keys with field extraction' do
|
|
195
|
-
decoded_hash = { 'foo' => 'bar', 'baz' => 'qux' }
|
|
196
|
-
allow(key_schema_registry).to receive(:decode).and_return(decoded_hash)
|
|
197
|
-
|
|
198
|
-
result = backend.decode_key('encoded-key', :foo)
|
|
199
|
-
expect(result).to eq('bar')
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
describe 'edge cases' do
|
|
204
|
-
it 'should handle nested field extraction for keys' do
|
|
205
|
-
# Use nested field from the actual schema: non_union_nested.nested_str
|
|
206
|
-
nested_payload = { 'non_union_nested' => { 'nested_str' => 'value', 'nested_num' => 123 }, 'str' => 'other' }
|
|
207
|
-
allow(key_schema_registry).to receive(:encode).and_return('encoded-key')
|
|
208
|
-
|
|
209
|
-
backend.encode_key('non_union_nested.nested_str', nested_payload, topic: 'my-topic')
|
|
210
|
-
|
|
211
|
-
# Should encode with just the nested_str field extracted from the nested message
|
|
212
|
-
expect(key_schema_registry).to have_received(:encode).with(
|
|
213
|
-
{ 'nested_str' => 'value' },
|
|
214
|
-
subject: 'my-topic-key',
|
|
215
|
-
schema_text: anything
|
|
216
|
-
)
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it 'should handle encoding payloads with subject suffix detection' do
|
|
220
|
-
allow(schema_registry).to receive(:encode).and_return('encoded-payload')
|
|
221
|
-
allow(key_schema_registry).to receive(:encode).and_return('encoded-payload')
|
|
222
|
-
|
|
223
|
-
# When subject ends with '-key', should use key_schema_registry
|
|
224
|
-
backend.encode_payload(payload, subject: 'my-topic-key')
|
|
225
|
-
expect(key_schema_registry).to have_received(:encode).with(payload, subject: 'my-topic-key')
|
|
226
|
-
|
|
227
|
-
# When subject doesn't end with '-key', should use schema_registry
|
|
228
|
-
backend.encode_payload(payload, subject: 'my-topic-value')
|
|
229
|
-
expect(schema_registry).to have_received(:encode).with(payload, subject: 'my-topic-value')
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
it 'should handle nil payloads gracefully' do
|
|
233
|
-
# encode with nil payload - schema_registry will handle the nil
|
|
234
|
-
allow(schema_registry).to receive(:encode).with(nil, subject: 'topic-value').and_return(nil)
|
|
235
|
-
expect(backend.encode(nil, topic: 'topic')).to be_nil
|
|
236
|
-
|
|
237
|
-
# decode returns nil for nil payload (base class checks this)
|
|
238
|
-
expect(backend.decode(nil)).to be_nil
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
describe 'schema field introspection' do
|
|
243
|
-
it 'should return schema fields from protobuf descriptor' do
|
|
244
|
-
fields = backend.schema_fields
|
|
245
|
-
|
|
246
|
-
expect(fields).to be_an(Array)
|
|
247
|
-
expect(fields.map(&:name)).to include('str', 'num', 'str_arr', 'flag', 'timestamp')
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
47
|
end
|
|
@@ -217,6 +217,13 @@ module Schemas
|
|
|
217
217
|
'com.my-namespace'
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
+
def self.tombstone(key)
|
|
221
|
+
record = self.allocate
|
|
222
|
+
record.tombstone_key = key
|
|
223
|
+
record.a_string = key
|
|
224
|
+
record
|
|
225
|
+
end
|
|
226
|
+
|
|
220
227
|
# @override
|
|
221
228
|
def as_json(_opts={})
|
|
222
229
|
{
|
|
@@ -437,13 +444,6 @@ module Schemas
|
|
|
437
444
|
'com.my-namespace'
|
|
438
445
|
end
|
|
439
446
|
|
|
440
|
-
def self.tombstone(key)
|
|
441
|
-
record = self.allocate
|
|
442
|
-
record.tombstone_key = key
|
|
443
|
-
record.test_id = key
|
|
444
|
-
record
|
|
445
|
-
end
|
|
446
|
-
|
|
447
447
|
# @override
|
|
448
448
|
def as_json(_opts={})
|
|
449
449
|
{
|
|
@@ -177,6 +177,13 @@ module Schemas
|
|
|
177
177
|
'com.my-namespace'
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def self.tombstone(key)
|
|
181
|
+
record = self.allocate
|
|
182
|
+
record.tombstone_key = key
|
|
183
|
+
record.a_string = key
|
|
184
|
+
record
|
|
185
|
+
end
|
|
186
|
+
|
|
180
187
|
# @override
|
|
181
188
|
def as_json(_opts={})
|
|
182
189
|
{
|
|
@@ -391,13 +398,6 @@ module Schemas
|
|
|
391
398
|
'com.my-namespace'
|
|
392
399
|
end
|
|
393
400
|
|
|
394
|
-
def self.tombstone(key)
|
|
395
|
-
record = self.allocate
|
|
396
|
-
record.tombstone_key = key
|
|
397
|
-
record.test_id = key
|
|
398
|
-
record
|
|
399
|
-
end
|
|
400
|
-
|
|
401
401
|
# @override
|
|
402
402
|
def as_json(_opts={})
|
|
403
403
|
{
|
|
@@ -217,6 +217,13 @@ module Schemas
|
|
|
217
217
|
'com.my-namespace'
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
+
def self.tombstone(key)
|
|
221
|
+
record = self.allocate
|
|
222
|
+
record.tombstone_key = key
|
|
223
|
+
record.a_string = key
|
|
224
|
+
record
|
|
225
|
+
end
|
|
226
|
+
|
|
220
227
|
# @override
|
|
221
228
|
def as_json(_opts={})
|
|
222
229
|
{
|
|
@@ -437,13 +444,6 @@ module Schemas
|
|
|
437
444
|
'com.my-namespace'
|
|
438
445
|
end
|
|
439
446
|
|
|
440
|
-
def self.tombstone(key)
|
|
441
|
-
record = self.allocate
|
|
442
|
-
record.tombstone_key = key
|
|
443
|
-
record.test_id = key
|
|
444
|
-
record
|
|
445
|
-
end
|
|
446
|
-
|
|
447
447
|
# @override
|
|
448
448
|
def as_json(_opts={})
|
|
449
449
|
{
|
|
@@ -177,6 +177,13 @@ module Schemas
|
|
|
177
177
|
'com.my-namespace'
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def self.tombstone(key)
|
|
181
|
+
record = self.allocate
|
|
182
|
+
record.tombstone_key = key
|
|
183
|
+
record.a_string = key
|
|
184
|
+
record
|
|
185
|
+
end
|
|
186
|
+
|
|
180
187
|
# @override
|
|
181
188
|
def as_json(_opts={})
|
|
182
189
|
{
|
|
@@ -391,13 +398,6 @@ module Schemas
|
|
|
391
398
|
'com.my-namespace'
|
|
392
399
|
end
|
|
393
400
|
|
|
394
|
-
def self.tombstone(key)
|
|
395
|
-
record = self.allocate
|
|
396
|
-
record.tombstone_key = key
|
|
397
|
-
record.test_id = key
|
|
398
|
-
record
|
|
399
|
-
end
|
|
400
|
-
|
|
401
401
|
# @override
|
|
402
402
|
def as_json(_opts={})
|
|
403
403
|
{
|
|
@@ -217,6 +217,13 @@ module Schemas
|
|
|
217
217
|
'com.my-namespace'
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
+
def self.tombstone(key)
|
|
221
|
+
record = self.allocate
|
|
222
|
+
record.tombstone_key = key
|
|
223
|
+
record.a_string = key
|
|
224
|
+
record
|
|
225
|
+
end
|
|
226
|
+
|
|
220
227
|
# @override
|
|
221
228
|
def as_json(_opts={})
|
|
222
229
|
{
|
|
@@ -437,13 +444,6 @@ module Schemas
|
|
|
437
444
|
'com.my-namespace'
|
|
438
445
|
end
|
|
439
446
|
|
|
440
|
-
def self.tombstone(key)
|
|
441
|
-
record = self.allocate
|
|
442
|
-
record.tombstone_key = key
|
|
443
|
-
record.test_id = key
|
|
444
|
-
record
|
|
445
|
-
end
|
|
446
|
-
|
|
447
447
|
# @override
|
|
448
448
|
def as_json(_opts={})
|
|
449
449
|
{
|
|
@@ -177,6 +177,13 @@ module Schemas
|
|
|
177
177
|
'com.my-namespace'
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def self.tombstone(key)
|
|
181
|
+
record = self.allocate
|
|
182
|
+
record.tombstone_key = key
|
|
183
|
+
record.a_string = key
|
|
184
|
+
record
|
|
185
|
+
end
|
|
186
|
+
|
|
180
187
|
# @override
|
|
181
188
|
def as_json(_opts={})
|
|
182
189
|
{
|
|
@@ -391,13 +398,6 @@ module Schemas
|
|
|
391
398
|
'com.my-namespace'
|
|
392
399
|
end
|
|
393
400
|
|
|
394
|
-
def self.tombstone(key)
|
|
395
|
-
record = self.allocate
|
|
396
|
-
record.tombstone_key = key
|
|
397
|
-
record.test_id = key
|
|
398
|
-
record
|
|
399
|
-
end
|
|
400
|
-
|
|
401
401
|
# @override
|
|
402
402
|
def as_json(_opts={})
|
|
403
403
|
{
|
|
@@ -217,6 +217,13 @@ module Schemas
|
|
|
217
217
|
'com.my-namespace'
|
|
218
218
|
end
|
|
219
219
|
|
|
220
|
+
def self.tombstone(key)
|
|
221
|
+
record = self.allocate
|
|
222
|
+
record.tombstone_key = key
|
|
223
|
+
record.a_string = key
|
|
224
|
+
record
|
|
225
|
+
end
|
|
226
|
+
|
|
220
227
|
# @override
|
|
221
228
|
def as_json(_opts={})
|
|
222
229
|
{
|
|
@@ -437,13 +444,6 @@ module Schemas
|
|
|
437
444
|
'com.my-namespace'
|
|
438
445
|
end
|
|
439
446
|
|
|
440
|
-
def self.tombstone(key)
|
|
441
|
-
record = self.allocate
|
|
442
|
-
record.tombstone_key = key
|
|
443
|
-
record.test_id = key
|
|
444
|
-
record
|
|
445
|
-
end
|
|
446
|
-
|
|
447
447
|
# @override
|
|
448
448
|
def as_json(_opts={})
|
|
449
449
|
{
|
|
@@ -177,6 +177,13 @@ module Schemas
|
|
|
177
177
|
'com.my-namespace'
|
|
178
178
|
end
|
|
179
179
|
|
|
180
|
+
def self.tombstone(key)
|
|
181
|
+
record = self.allocate
|
|
182
|
+
record.tombstone_key = key
|
|
183
|
+
record.a_string = key
|
|
184
|
+
record
|
|
185
|
+
end
|
|
186
|
+
|
|
180
187
|
# @override
|
|
181
188
|
def as_json(_opts={})
|
|
182
189
|
{
|
|
@@ -391,13 +398,6 @@ module Schemas
|
|
|
391
398
|
'com.my-namespace'
|
|
392
399
|
end
|
|
393
400
|
|
|
394
|
-
def self.tombstone(key)
|
|
395
|
-
record = self.allocate
|
|
396
|
-
record.tombstone_key = key
|
|
397
|
-
record.test_id = key
|
|
398
|
-
record
|
|
399
|
-
end
|
|
400
|
-
|
|
401
401
|
# @override
|
|
402
402
|
def as_json(_opts={})
|
|
403
403
|
{
|