deimos-ruby 1.24.3 → 2.0.0.pre.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +0 -17
  3. data/.tool-versions +1 -0
  4. data/CHANGELOG.md +1 -1
  5. data/README.md +287 -498
  6. data/deimos-ruby.gemspec +4 -4
  7. data/docs/CONFIGURATION.md +133 -227
  8. data/docs/UPGRADING.md +237 -0
  9. data/lib/deimos/active_record_consume/batch_consumption.rb +28 -29
  10. data/lib/deimos/active_record_consume/message_consumption.rb +15 -21
  11. data/lib/deimos/active_record_consumer.rb +36 -26
  12. data/lib/deimos/active_record_producer.rb +28 -9
  13. data/lib/deimos/backends/base.rb +4 -35
  14. data/lib/deimos/backends/kafka.rb +6 -22
  15. data/lib/deimos/backends/kafka_async.rb +6 -22
  16. data/lib/deimos/backends/{db.rb → outbox.rb} +13 -9
  17. data/lib/deimos/config/configuration.rb +116 -385
  18. data/lib/deimos/consume/batch_consumption.rb +24 -124
  19. data/lib/deimos/consume/message_consumption.rb +36 -63
  20. data/lib/deimos/consumer.rb +16 -75
  21. data/lib/deimos/ext/consumer_route.rb +35 -0
  22. data/lib/deimos/ext/producer_middleware.rb +94 -0
  23. data/lib/deimos/ext/producer_route.rb +22 -0
  24. data/lib/deimos/ext/redraw.rb +29 -0
  25. data/lib/deimos/ext/routing_defaults.rb +72 -0
  26. data/lib/deimos/ext/schema_route.rb +70 -0
  27. data/lib/deimos/kafka_message.rb +2 -2
  28. data/lib/deimos/kafka_source.rb +2 -7
  29. data/lib/deimos/kafka_topic_info.rb +1 -1
  30. data/lib/deimos/logging.rb +71 -0
  31. data/lib/deimos/message.rb +2 -11
  32. data/lib/deimos/metrics/datadog.rb +40 -1
  33. data/lib/deimos/metrics/provider.rb +4 -4
  34. data/lib/deimos/producer.rb +39 -116
  35. data/lib/deimos/railtie.rb +6 -0
  36. data/lib/deimos/schema_backends/avro_base.rb +21 -21
  37. data/lib/deimos/schema_backends/avro_schema_registry.rb +1 -2
  38. data/lib/deimos/schema_backends/avro_validation.rb +2 -2
  39. data/lib/deimos/schema_backends/base.rb +19 -12
  40. data/lib/deimos/schema_backends/mock.rb +6 -1
  41. data/lib/deimos/schema_backends/plain.rb +47 -0
  42. data/lib/deimos/schema_class/base.rb +2 -2
  43. data/lib/deimos/schema_class/enum.rb +1 -1
  44. data/lib/deimos/schema_class/record.rb +2 -2
  45. data/lib/deimos/test_helpers.rb +95 -320
  46. data/lib/deimos/tracing/provider.rb +6 -6
  47. data/lib/deimos/transcoder.rb +88 -0
  48. data/lib/deimos/utils/db_poller/base.rb +16 -14
  49. data/lib/deimos/utils/db_poller/state_based.rb +3 -3
  50. data/lib/deimos/utils/db_poller/time_based.rb +4 -4
  51. data/lib/deimos/utils/db_poller.rb +1 -1
  52. data/lib/deimos/utils/deadlock_retry.rb +1 -1
  53. data/lib/deimos/utils/{db_producer.rb → outbox_producer.rb} +16 -47
  54. data/lib/deimos/utils/schema_class.rb +0 -7
  55. data/lib/deimos/version.rb +1 -1
  56. data/lib/deimos.rb +79 -26
  57. data/lib/generators/deimos/{db_backend_generator.rb → outbox_backend_generator.rb} +4 -4
  58. data/lib/generators/deimos/schema_class_generator.rb +0 -1
  59. data/lib/generators/deimos/v2/templates/karafka.rb.tt +149 -0
  60. data/lib/generators/deimos/v2_generator.rb +193 -0
  61. data/lib/tasks/deimos.rake +5 -7
  62. data/spec/active_record_batch_consumer_association_spec.rb +22 -13
  63. data/spec/active_record_batch_consumer_spec.rb +84 -65
  64. data/spec/active_record_consume/batch_consumption_spec.rb +10 -10
  65. data/spec/active_record_consume/batch_slicer_spec.rb +12 -12
  66. data/spec/active_record_consumer_spec.rb +29 -13
  67. data/spec/active_record_producer_spec.rb +36 -26
  68. data/spec/backends/base_spec.rb +0 -23
  69. data/spec/backends/kafka_async_spec.rb +1 -3
  70. data/spec/backends/kafka_spec.rb +1 -3
  71. data/spec/backends/{db_spec.rb → outbox_spec.rb} +14 -20
  72. data/spec/batch_consumer_spec.rb +66 -116
  73. data/spec/consumer_spec.rb +53 -147
  74. data/spec/deimos_spec.rb +10 -126
  75. data/spec/kafka_source_spec.rb +19 -52
  76. data/spec/karafka/karafka.rb +69 -0
  77. data/spec/karafka_config/karafka_spec.rb +97 -0
  78. data/spec/logging_spec.rb +25 -0
  79. data/spec/message_spec.rb +9 -9
  80. data/spec/producer_spec.rb +112 -254
  81. data/spec/rake_spec.rb +1 -3
  82. data/spec/schema_backends/avro_validation_spec.rb +1 -1
  83. data/spec/schemas/com/my-namespace/MySchemaWithTitle.avsc +22 -0
  84. data/spec/snapshots/consumers-no-nest.snap +49 -0
  85. data/spec/snapshots/consumers.snap +49 -0
  86. data/spec/snapshots/consumers_and_producers-no-nest.snap +49 -0
  87. data/spec/snapshots/consumers_and_producers.snap +49 -0
  88. data/spec/snapshots/consumers_circular-no-nest.snap +49 -0
  89. data/spec/snapshots/consumers_circular.snap +49 -0
  90. data/spec/snapshots/consumers_complex_types-no-nest.snap +49 -0
  91. data/spec/snapshots/consumers_complex_types.snap +49 -0
  92. data/spec/snapshots/consumers_nested-no-nest.snap +49 -0
  93. data/spec/snapshots/consumers_nested.snap +49 -0
  94. data/spec/snapshots/namespace_folders.snap +49 -0
  95. data/spec/snapshots/namespace_map.snap +49 -0
  96. data/spec/snapshots/producers_with_key-no-nest.snap +49 -0
  97. data/spec/snapshots/producers_with_key.snap +49 -0
  98. data/spec/spec_helper.rb +61 -29
  99. data/spec/utils/db_poller_spec.rb +49 -39
  100. data/spec/utils/{db_producer_spec.rb → outbox_producer_spec.rb} +17 -184
  101. metadata +58 -67
  102. data/lib/deimos/batch_consumer.rb +0 -7
  103. data/lib/deimos/config/phobos_config.rb +0 -164
  104. data/lib/deimos/instrumentation.rb +0 -95
  105. data/lib/deimos/monkey_patches/phobos_cli.rb +0 -35
  106. data/lib/deimos/utils/inline_consumer.rb +0 -158
  107. data/lib/deimos/utils/lag_reporter.rb +0 -186
  108. data/lib/deimos/utils/schema_controller_mixin.rb +0 -129
  109. data/spec/config/configuration_spec.rb +0 -329
  110. data/spec/kafka_listener_spec.rb +0 -55
  111. data/spec/phobos.bad_db.yml +0 -73
  112. data/spec/phobos.yml +0 -77
  113. data/spec/utils/inline_consumer_spec.rb +0 -31
  114. data/spec/utils/lag_reporter_spec.rb +0 -76
  115. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  116. data/spec/utils/schema_controller_mixin_spec.rb +0 -84
  117. /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/migration +0 -0
  118. /data/lib/generators/deimos/{db_backend → outbox_backend}/templates/rails3_migration +0 -0
@@ -4,6 +4,7 @@ require 'active_support/concern'
4
4
  require 'active_support/core_ext'
5
5
  require 'deimos/tracing/mock'
6
6
  require 'deimos/metrics/mock'
7
+ require 'karafka/testing/rspec/helpers'
7
8
 
8
9
  module Deimos
9
10
  # Include this module in your RSpec spec_helper
@@ -11,122 +12,79 @@ module Deimos
11
12
  # and add methods to use to test encoding/decoding.
12
13
  module TestHelpers
13
14
  extend ActiveSupport::Concern
15
+ def self.included(base)
16
+ super
17
+ base.include Karafka::Testing::RSpec::Helpers
18
+ end
19
+
20
+ # @return [Array<Hash>]
21
+ def sent_messages
22
+ self.class.sent_messages
23
+ end
14
24
 
15
25
  class << self
16
- # for backwards compatibility
17
26
  # @return [Array<Hash>]
18
27
  def sent_messages
19
- Deimos::Backends::Test.sent_messages
28
+ Karafka.producer.client.messages.map do |m|
29
+ produced_message = m.except(:label).deep_dup
30
+ Deimos.decode_message(produced_message)
31
+ produced_message[:payload] = Deimos::TestHelpers.normalize_message(produced_message[:payload])
32
+ produced_message[:key] = Deimos::TestHelpers.normalize_message(produced_message[:key])
33
+ produced_message
34
+ end
20
35
  end
21
36
 
22
37
  # Set the config to the right settings for a unit test
23
38
  # @return [void]
24
39
  def unit_test!
25
- Deimos.configure do |deimos_config|
26
- deimos_config.logger = Logger.new(STDOUT)
27
- deimos_config.consumers.reraise_errors = true
28
- deimos_config.kafka.seed_brokers ||= ['test_broker']
29
- deimos_config.schema.backend = Deimos.schema_backend_class.mock_backend
30
- deimos_config.producers.backend = :test
31
- deimos_config.tracer = Deimos::Tracing::Mock.new
32
- end
33
- end
34
-
35
- # Kafka test config with avro schema registry
36
- # @return [void]
37
- def full_integration_test!
38
- Deimos.configure do |deimos_config|
39
- deimos_config.producers.backend = :kafka
40
- deimos_config.schema.backend = :avro_schema_registry
41
- end
42
- end
43
-
44
- # Set the config to the right settings for a kafka test
45
- # @return [void]
46
- def kafka_test!
47
- Deimos.configure do |deimos_config|
48
- deimos_config.producers.backend = :kafka
49
- deimos_config.schema.backend = :avro_validation
50
- end
40
+ Deimos.config.schema.backend = :avro_validation
41
+ warn "unit_test! is deprecated and can be replaced by setting Deimos's schema backend to `:avro_validation`. All other test behavior is provided by Karafka."
51
42
  end
52
43
  end
53
44
 
54
- included do
55
-
56
- RSpec.configure do |config|
57
- config.prepend_before(:each) do
58
- client = double('client').as_null_object
59
- allow(client).to receive(:time) do |*_args, &block|
60
- block.call
61
- end
62
- Deimos::Backends::Test.sent_messages.clear
63
- end
64
- end
65
-
66
- end
67
-
68
- # @deprecated
69
- # @!visibility private
70
- def stub_producers_and_consumers!
71
- warn('stub_producers_and_consumers! is no longer necessary and this method will be removed in 3.0')
72
- end
73
-
74
- # @deprecated
75
- # @!visibility private
76
- def stub_producer(_klass)
77
- warn('Stubbing producers is no longer necessary and this method will be removed in 3.0')
78
- end
79
-
80
- # @deprecated
81
- # @!visibility private
82
- def stub_consumer(_klass)
83
- warn('Stubbing consumers is no longer necessary and this method will be removed in 3.0')
84
- end
85
-
86
- # @deprecated
87
- # @!visibility private
88
- def stub_batch_consumer(_klass)
89
- warn('Stubbing batch consumers is no longer necessary and this method will be removed in 3.0')
90
- end
91
-
92
45
  # get the difference of 2 hashes.
93
- # @param hash1 [Hash]
94
- # @param hash2 [Hash]
46
+ # @param hash1 [Hash, nil]
47
+ # @param hash2 [Hash, nil]
95
48
  # @!visibility private
96
49
  def _hash_diff(hash1, hash2)
97
- if hash1.nil? || !hash1.is_a?(Hash)
98
- hash2
99
- elsif hash2.nil? || !hash2.is_a?(Hash)
100
- hash1
50
+ h1 = Deimos::TestHelpers.normalize_message(hash1)
51
+ h2 = Deimos::TestHelpers.normalize_message(hash2)
52
+ if h1.nil? || !h1.is_a?(Hash)
53
+ h2
54
+ elsif h2.nil? || !h2.is_a?(Hash)
55
+ h1
101
56
  else
102
- hash1.dup.
103
- delete_if { |k, v| hash2[k] == v }.
104
- merge!(hash2.dup.delete_if { |k, _v| hash1.key?(k) })
57
+ h1.dup.
58
+ delete_if { |k, v| h2[k] == v }.
59
+ merge!(h2.dup.delete_if { |k, _v| h1.key?(k) })
60
+ end
61
+ end
62
+
63
+ def self.normalize_message(m)
64
+ return nil if m.nil?
65
+
66
+ if m.respond_to?(:to_h)
67
+ m = m.to_h
105
68
  end
69
+ if m.respond_to?(:with_indifferent_access)
70
+ m = m.with_indifferent_access
71
+ end
72
+ m
106
73
  end
107
74
 
108
75
  # @!visibility private
109
76
  def _frk_failure_message(topic, message, key=nil, partition_key=nil, was_negated=false)
110
- messages = Deimos::Backends::Test.sent_messages.
111
- select { |m| m[:topic] == topic }.
112
- map { |m| m.except(:topic) }
77
+ messages = Deimos::TestHelpers.sent_messages.select { |m| m[:topic] == topic }
113
78
  message_string = ''
114
79
  diff = nil
115
80
  min_hash_diff = nil
81
+ message = Deimos::TestHelpers.normalize_message(message)
116
82
  if messages.any?
117
- message_string = messages.map(&:inspect).join("\n")
118
- min_hash_diff = messages.min_by { |m| _hash_diff(m, message).keys.size }
119
- diff = RSpec::Expectations.differ.
120
- diff_as_object(message, min_hash_diff[:payload])
83
+ message_string = messages.map { |m| m[:payload].inspect}.join("\n")
84
+ min_hash_diff = messages.min_by { |m| _hash_diff(m, message)&.keys&.size }
85
+ diff = RSpec::Expectations.differ.diff_as_object(message, min_hash_diff[:payload])
121
86
  end
122
- description = if message.respond_to?(:description)
123
- message.description
124
- elsif message.nil?
125
- 'nil'
126
- else
127
- message
128
- end
129
- str = "Expected #{topic} #{'not ' if was_negated}to have sent #{description}"
87
+ str = "Expected #{topic} #{'not ' if was_negated}to have sent #{message.try(:to_h) || message}"
130
88
  str += " with key #{key}" if key
131
89
  str += " with partition key #{partition_key}" if partition_key
132
90
  str += "\nClosest message received: #{min_hash_diff}" if min_hash_diff
@@ -135,23 +93,18 @@ module Deimos
135
93
  end
136
94
 
137
95
  RSpec::Matchers.define :have_sent do |msg, key=nil, partition_key=nil, headers=nil|
138
- message = if msg.respond_to?(:with_indifferent_access)
139
- msg.with_indifferent_access
140
- else
141
- msg
142
- end
96
+ message = Deimos::TestHelpers.normalize_message(msg)
143
97
  match do |topic|
144
- Deimos::Backends::Test.sent_messages.any? do |m|
145
- hash_matcher = RSpec::Matchers::BuiltIn::Match.new(message)
146
- hash_matcher.send(:match,
147
- message&.respond_to?(:to_h) ? message.to_h : message,
148
- m[:payload]&.with_indifferent_access) &&
98
+ message_key = Deimos::TestHelpers.normalize_message(key)
99
+ hash_matcher = RSpec::Matchers::BuiltIn::Match.new(message)
100
+ Deimos::TestHelpers.sent_messages.any? do |m|
101
+ hash_matcher.send(:match, message, m[:payload]) &&
149
102
  topic == m[:topic] &&
150
- (key.present? ? key == m[:key] : true) &&
103
+ (key.present? ? message_key == m[:key] : true) &&
151
104
  (partition_key.present? ? partition_key == m[:partition_key] : true) &&
152
105
  if headers.present?
153
106
  hash_matcher.send(:match,
154
- headers&.with_indifferent_access,
107
+ headers.with_indifferent_access,
155
108
  m[:headers]&.with_indifferent_access)
156
109
  else
157
110
  true
@@ -159,20 +112,11 @@ module Deimos
159
112
  end
160
113
  end
161
114
 
162
- if respond_to?(:failure_message)
163
- failure_message do |topic|
164
- _frk_failure_message(topic, message, key, partition_key)
165
- end
166
- failure_message_when_negated do |topic|
167
- _frk_failure_message(topic, message, key, partition_key, true)
168
- end
169
- else
170
- failure_message_for_should do |topic|
171
- _frk_failure_message(topic, message, key, partition_key)
172
- end
173
- failure_message_for_should_not do |topic|
174
- _frk_failure_message(topic, message, key, partition_key, true)
175
- end
115
+ failure_message do |topic|
116
+ _frk_failure_message(topic, message, key, partition_key)
117
+ end
118
+ failure_message_when_negated do |topic|
119
+ _frk_failure_message(topic, message, key, partition_key, true)
176
120
  end
177
121
  end
178
122
 
@@ -180,7 +124,8 @@ module Deimos
180
124
  # particular messages were sent or not sent after a point in time.
181
125
  # @return [void]
182
126
  def clear_kafka_messages!
183
- Deimos::Backends::Test.sent_messages.clear
127
+ puts "[Deprecated] clear_kafka_messages! can be replaced with `karafka.produced_messages.clear`"
128
+ karafka.produced_messages.clear
184
129
  end
185
130
 
186
131
  # Test that a given handler will consume a given payload correctly, i.e.
@@ -190,65 +135,19 @@ module Deimos
190
135
  # @param handler_class_or_topic [Class, String] Class which inherits from
191
136
  # Deimos::Consumer or the topic as a string
192
137
  # @param payload [Hash] the payload to consume
193
- # @param call_original [Boolean] if true, allow the consume handler
194
- # to continue as normal. Not compatible with a block.
195
- # @param skip_expectation [Boolean] Set to true to not place any
196
- # expectations on the consumer. Primarily used internally to Deimos.
197
138
  # @param key [Object] the key to use.
139
+ # @param call_original [Symbol] legacy parameter.
198
140
  # @param partition_key [Object] the partition key to use.
199
141
  # @return [void]
200
142
  def test_consume_message(handler_class_or_topic,
201
143
  payload,
202
- call_original: false,
203
144
  key: nil,
204
- partition_key: nil,
205
- skip_expectation: false,
206
- &block)
207
- raise 'Cannot have both call_original and be given a block!' if call_original && block_given?
208
-
209
- payload.stringify_keys! if payload.respond_to?(:stringify_keys!)
210
- handler_class = if handler_class_or_topic.is_a?(String)
211
- _get_handler_class_from_topic(handler_class_or_topic)
212
- else
213
- handler_class_or_topic
214
- end
215
- handler = handler_class.new
216
- allow(handler_class).to receive(:new).and_return(handler)
217
- listener = double('listener',
218
- handler_class: handler_class,
219
- encoding: nil)
220
- key ||= _key_from_consumer(handler_class)
221
- message = double('message',
222
- 'key' => key,
223
- 'partition_key' => partition_key,
224
- 'partition' => 1,
225
- 'offset' => 1,
226
- 'headers' => {},
227
- 'value' => payload)
228
-
229
- unless skip_expectation
230
- _handler_expectation(:consume,
231
- payload,
232
- handler,
233
- call_original,
234
- &block)
145
+ call_original: nil,
146
+ partition_key: nil)
147
+ unless call_original.nil?
148
+ puts "test_consume_message(call_original: true) is deprecated and will be removed in the future. You can remove the call_original parameter."
235
149
  end
236
- Phobos::Actions::ProcessMessage.new(
237
- listener: listener,
238
- message: message,
239
- listener_metadata: { topic: 'my-topic' }
240
- ).send(:process_message, payload)
241
- end
242
-
243
- # Check to see that a given message will fail due to validation errors.
244
- # @param handler_class [Class]
245
- # @param payload [Hash]
246
- # @return [void]
247
- def test_consume_invalid_message(handler_class, payload)
248
- expect {
249
- handler_class.decoder.validate(payload,
250
- schema: handler_class.decoder.schema)
251
- }.to raise_error(Avro::SchemaValidator::ValidationError)
150
+ test_consume_batch(handler_class_or_topic, [payload], keys: [key], partition_keys: [partition_key], single: true)
252
151
  end
253
152
 
254
153
  # Test that a given handler will consume a given batch payload correctly,
@@ -258,165 +157,41 @@ module Deimos
258
157
  # @param handler_class_or_topic [Class, String] Class which inherits from
259
158
  # Deimos::Consumer or the topic as a string
260
159
  # @param payloads [Array<Hash>] the payload to consume
261
- # @param keys [Array<Hash,String>]
262
- # @param partition_keys [Array<Integer>]
263
- # @param call_original [Boolean]
264
- # @param skip_expectation [Boolean]
160
+ # @param call_original [Boolean,nil] legacy parameter.
161
+ # @param keys [Array<Object>]
162
+ # @param partition_keys [Array<Object>]
163
+ # @param single [Boolean] used internally.
265
164
  # @return [void]
266
165
  def test_consume_batch(handler_class_or_topic,
267
166
  payloads,
268
167
  keys: [],
269
- partition_keys: [],
270
- call_original: false,
271
- skip_expectation: false,
272
- &block)
273
- if call_original && block_given?
274
- raise 'Cannot have both call_original and be given a block!'
275
- end
276
-
277
- topic_name = 'my-topic'
278
- handler_class = if handler_class_or_topic.is_a?(String)
279
- _get_handler_class_from_topic(handler_class_or_topic)
280
- else
281
- handler_class_or_topic
282
- end
283
- handler = handler_class.new
284
- allow(handler_class).to receive(:new).and_return(handler)
285
- listener = double('listener',
286
- handler_class: handler_class,
287
- encoding: nil)
288
- batch_messages = payloads.zip(keys, partition_keys).map do |payload, key, partition_key|
289
- key ||= _key_from_consumer(handler_class)
290
-
291
- double('message',
292
- 'key' => key,
293
- 'partition_key' => partition_key,
294
- 'partition' => 1,
295
- 'offset' => 1,
296
- 'headers' => {},
297
- 'value' => payload)
298
- end
299
- batch = double('fetched_batch',
300
- 'messages' => batch_messages,
301
- 'topic' => topic_name,
302
- 'partition' => 1,
303
- 'offset_lag' => 0)
304
- unless skip_expectation
305
- _handler_expectation(:consume_batch,
306
- payloads,
307
- handler,
308
- call_original,
309
- &block)
310
- end
311
- action = Phobos::Actions::ProcessBatchInline.new(
312
- listener: listener,
313
- batch: batch,
314
- metadata: { topic: topic_name }
315
- )
316
- allow(action).to receive(:backoff_interval).and_return(0)
317
- allow(action).to receive(:handle_error) { |e| raise e }
318
- action.send(:execute)
319
- end
320
-
321
- # Check to see that a given message will fail due to validation errors.
322
- # @param handler_class [Class]
323
- # @param payloads [Array<Hash>]
324
- # @return [void]
325
- def test_consume_batch_invalid_message(handler_class, payloads)
326
- topic_name = 'my-topic'
327
- handler = handler_class.new
328
- allow(handler_class).to receive(:new).and_return(handler)
329
- listener = double('listener',
330
- handler_class: handler_class,
331
- encoding: nil)
332
- batch_messages = payloads.map do |payload|
333
- key ||= _key_from_consumer(handler_class)
334
-
335
- double('message',
336
- 'key' => key,
337
- 'partition' => 1,
338
- 'offset' => 1,
339
- 'value' => payload)
340
- end
341
- batch = double('fetched_batch',
342
- 'messages' => batch_messages,
343
- 'topic' => topic_name,
344
- 'partition' => 1,
345
- 'offset_lag' => 0)
346
-
347
- action = Phobos::Actions::ProcessBatchInline.new(
348
- listener: listener,
349
- batch: batch,
350
- metadata: { topic: topic_name }
351
- )
352
- allow(action).to receive(:backoff_interval).and_return(0)
353
- allow(action).to receive(:handle_error) { |e| raise e }
354
-
355
- expect { action.send(:execute) }.
356
- to raise_error
357
- end
358
-
359
- private
360
-
361
- def _key_from_consumer(consumer)
362
- if consumer.config[:key_field]
363
- { consumer.config[:key_field] => 1 }
364
- elsif consumer.config[:key_schema]
365
- backend = consumer.decoder
366
- old_schema = backend.schema
367
- backend.schema = consumer.config[:key_schema]
368
- key = backend.schema_fields.map { |field| [field.name, 1] }.to_h
369
- backend.schema = old_schema
370
- key
371
- elsif consumer.config[:no_keys]
372
- nil
168
+ call_original: nil,
169
+ single: false,
170
+ partition_keys: [])
171
+ unless call_original.nil?
172
+ puts "test_consume_batch(call_original: true) is deprecated and will be removed in the future. You can remove the call_original parameter."
173
+ end
174
+ consumer = nil
175
+ topic_name = nil
176
+ if handler_class_or_topic.is_a?(String)
177
+ topic_name = handler_class_or_topic
178
+ consumer = karafka.consumer_for(topic_name)
373
179
  else
374
- 1
180
+ topic_name = Deimos.topic_for_consumer(handler_class_or_topic)
181
+ consumer = karafka.consumer_for(topic_name)
375
182
  end
376
- end
377
-
378
- # @param topic [String]
379
- # @return [Class]
380
- def _get_handler_class_from_topic(topic)
381
- listeners = Phobos.config['listeners']
382
- handler = listeners.find { |l| l.topic == topic }
383
- raise "No consumer found in Phobos configuration for topic #{topic}!" if handler.nil?
384
-
385
- handler.handler.constantize
386
- end
387
-
388
- # Test that a given handler will execute a `method` on an `input` correctly,
389
- # If a block is given, that block will be executed when `method` is called.
390
- # Otherwise it will just confirm that `method` is called at all.
391
- # @param method [Symbol]
392
- # @param input [Object]
393
- # @param handler [Deimos::Consumer]
394
- # @param call_original [Boolean]
395
- def _handler_expectation(method,
396
- input,
397
- handler,
398
- call_original,
399
- &block)
400
- schema_class = handler.class.config[:schema]
401
- namespace = handler.class.config[:namespace]
402
- expected = input.dup
403
183
 
404
- config = handler.class.config
405
- use_schema_classes = config[:use_schema_classes]
406
- use_schema_classes = use_schema_classes.present? ? use_schema_classes : Deimos.config.schema.use_schema_classes
184
+ Deimos.karafka_config_for(topic: topic_name).each_message(single)
407
185
 
408
- if use_schema_classes && schema_class.present?
409
- expected = if input.is_a?(Array)
410
- input.map do |payload|
411
- Utils::SchemaClass.instance(payload, schema_class, namespace)
412
- end
413
- else
414
- Utils::SchemaClass.instance(input, schema_class, namespace)
415
- end
186
+ payloads.each_with_index do |payload, i|
187
+ karafka.produce(payload, {key: keys[i], partition_key: partition_keys[i], topic: consumer.topic.name})
188
+ end
189
+ if block_given?
190
+ allow_any_instance_of(consumer_class).to receive(:consume_batch) do
191
+ yield
192
+ end
193
+ end
194
+ consumer.consume
416
195
  end
417
-
418
- expectation = expect(handler).to receive(method).with(expected, anything, &block)
419
- expectation.and_call_original if call_original
420
- end
421
196
  end
422
197
  end
@@ -9,14 +9,14 @@ module Deimos
9
9
  # @param options [Hash] Options for the span
10
10
  # @return [Object] The span object
11
11
  def start(span_name, options={})
12
- raise NotImplementedError
12
+ raise MissingImplementationError
13
13
  end
14
14
 
15
15
  # Finishes the trace on the span object.
16
16
  # @param span [Object] The span to finish trace on
17
17
  # @return [void]
18
18
  def finish(span)
19
- raise NotImplementedError
19
+ raise MissingImplementationError
20
20
  end
21
21
 
22
22
  # Set an error on the span.
@@ -24,13 +24,13 @@ module Deimos
24
24
  # @param exception [Exception] The exception that occurred
25
25
  # @return [void]
26
26
  def set_error(span, exception)
27
- raise NotImplementedError
27
+ raise MissingImplementationError
28
28
  end
29
29
 
30
30
  # Get the currently activated span.
31
31
  # @return [Object]
32
32
  def active_span
33
- raise NotImplementedError
33
+ raise MissingImplementationError
34
34
  end
35
35
 
36
36
  # Set a tag to a span. Use the currently active span if not given.
@@ -39,13 +39,13 @@ module Deimos
39
39
  # @param span [Object]
40
40
  # @return [void]
41
41
  def set_tag(tag, value, span=nil)
42
- raise NotImplementedError
42
+ raise MissingImplementationError
43
43
  end
44
44
 
45
45
  # Get a tag from a span with the specified tag.
46
46
  # @param tag [String]
47
47
  def get_tag(tag)
48
- raise NotImplementedError
48
+ raise MissingImplementationError
49
49
  end
50
50
 
51
51
  end
@@ -0,0 +1,88 @@
1
+ module Deimos
2
+ class Transcoder
3
+
4
+ attr_accessor :key_field, :backend
5
+
6
+ # @param schema [String]
7
+ # @param namespace [String]
8
+ # @param key_field [Symbol]
9
+ # @param use_schema_classes [Boolean]
10
+ # @param topic [String]
11
+ def initialize(schema:, namespace:, key_field: nil, use_schema_classes: nil, topic: nil)
12
+ @schema = schema
13
+ @namespace = namespace
14
+ self.key_field = key_field
15
+ @use_schema_classes = use_schema_classes
16
+ @topic = topic
17
+ end
18
+
19
+ # @return [Class < Deimos::SchemaBackends::Base]
20
+ def backend
21
+ @backend ||= Deimos.schema_backend(schema: @schema, namespace: @namespace)
22
+ end
23
+
24
+ # for use in test helpers
25
+ # @param key [Object]
26
+ # @return [String]
27
+ def encode_key(key)
28
+ if self.key_field
29
+ self.backend.encode_key(self.key_field, key, topic: @topic)
30
+ else
31
+ self.backend.encode(key, topic: @topic)
32
+ end
33
+ end
34
+
35
+ # @param key [String]
36
+ # @return [Object]
37
+ def decode_key(key)
38
+ return nil if key.nil? || self.key_field.nil?
39
+
40
+ decoded_key = self.backend.decode_key(key, self.key_field)
41
+ return decoded_key unless @use_schema_classes
42
+
43
+ Utils::SchemaClass.instance(decoded_key,
44
+ "#{@schema}_key",
45
+ @namespace)
46
+ end
47
+
48
+ # @param payload [String]
49
+ # @return [Object]
50
+ def decode_message(payload)
51
+ return nil if payload.nil?
52
+
53
+ decoded_payload = self.backend.decode(payload)
54
+ return decoded_payload unless @use_schema_classes
55
+
56
+ Utils::SchemaClass.instance(decoded_payload,
57
+ @schema,
58
+ @namespace)
59
+ end
60
+
61
+ # @param payload [Object]
62
+ # @return [String]
63
+ def encode(payload)
64
+ return nil if payload.nil?
65
+
66
+ self.backend.encode(payload)
67
+ end
68
+
69
+ # @param message [Karafka::Messages::Message]
70
+ # @return [Object]
71
+ def call(message)
72
+ if self.key_field
73
+ decode_key(message.raw_key)
74
+ elsif message.respond_to?(:raw_payload)
75
+ decode_message(message.raw_payload)
76
+ else
77
+ decode_message(message.raw_key)
78
+ end
79
+ end
80
+
81
+ # @param payload [String]
82
+ # @return [Object]
83
+ def decode_message_hash(payload)
84
+ self.key_field ? decode_key(payload) : decode_message(payload)
85
+ end
86
+
87
+ end
88
+ end