nulogy_message_bus_consumer 2.0.0 → 3.0.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.
@@ -4,7 +4,8 @@ RSpec.describe "Auditing pipeline" do # rubocop:disable RSpec/DescribeClass
4
4
  NulogyMessageBusConsumer::Config.new(
5
5
  consumer_group_id: random_consumer_group,
6
6
  bootstrap_servers: test_bootstrap_servers,
7
- topic_name: topic.topic_name
7
+ topic_name: topic.topic_name,
8
+ security_protocol: "plaintext"
8
9
  )
9
10
  end
10
11
  let(:logger) { spy }
@@ -33,7 +34,7 @@ RSpec.describe "Auditing pipeline" do # rubocop:disable RSpec/DescribeClass
33
34
 
34
35
  run_audit_pipeline
35
36
 
36
- expect(logger).to have_not_received(:warn)
37
+ expect(logger).not_to receive(:warn)
37
38
  end
38
39
  end
39
40
 
@@ -0,0 +1,54 @@
1
+ RSpec.describe "End to end" do
2
+ let(:logger) { NulogyMessageBusConsumer::NullLogger.new }
3
+ let(:topic) { TestTopic.new }
4
+ let(:tap) { MiddlewareTap.new }
5
+ let(:message_handler_spy) { double }
6
+ subject(:pipeline) do
7
+ pipeline = NulogyMessageBusConsumer.recommended_consumer_pipeline(config: topic.config)
8
+ pipeline.insert(tap, after: NulogyMessageBusConsumer::Steps::ConnectToMessageBus)
9
+ pipeline.append(message_handler_spy)
10
+ pipeline
11
+ end
12
+
13
+ after { topic.close }
14
+
15
+ it "receives messages using the full pipeline" do
16
+ create_topic(topic.topic_name)
17
+
18
+ called = false
19
+ expect(message_handler_spy).to receive(:call) do |message:, **_kargs|
20
+ expect(message).to have_attributes(event_data: {data: "Some Payload"})
21
+ called = true
22
+ :success
23
+ end
24
+
25
+ pipeline_thread = start(pipeline, tap)
26
+
27
+ topic.produce_one_message(
28
+ key: "Some Key",
29
+ payload: message_payload(data: "Some Payload")
30
+ )
31
+
32
+ NulogyMessageBusConsumer::KafkaUtils.wait_for { called }
33
+ Thread.kill(pipeline_thread)
34
+ end
35
+
36
+ def start(pipeline, tap)
37
+ thr = Thread.new { pipeline.invoke }
38
+ wait_for_partition_assignment(tap)
39
+ thr
40
+ end
41
+
42
+ def wait_for_partition_assignment(tap)
43
+ NulogyMessageBusConsumer::KafkaUtils.wait_for { tap.arguments.fetch(:kafka_consumer, nil) }
44
+ NulogyMessageBusConsumer::KafkaUtils.wait_for_assignment(tap.arguments[:kafka_consumer])
45
+ end
46
+
47
+ def message_payload(**payload)
48
+ JSON.dump(
49
+ id: SecureRandom.uuid,
50
+ created_at: 1_000,
51
+ event_json: JSON.dump(payload)
52
+ )
53
+ end
54
+ end
@@ -31,7 +31,7 @@ RSpec.describe NulogyMessageBusConsumer::KafkaUtils do
31
31
  it "does not keep the connection open when there are no messages" do
32
32
  topic.produce_one_message(payload: "The Only Message")
33
33
 
34
- enum = utils.every_message_until_none_are_left(topic.consumer)
34
+ enum = utils.every_message_until_none_are_left(topic.consumer, Kafka::CONSUMER_POLL_TIMEOUT)
35
35
 
36
36
  expect(enum).to match([
37
37
  have_attributes(payload: "The Only Message")
@@ -3,22 +3,22 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
3
3
  let(:consumer) { test_topic.consumer }
4
4
  let(:logger) { NulogyMessageBusConsumer::NullLogger.new }
5
5
  let(:handler) { spy }
6
+ let(:subscribe_to_partition) { NulogyMessageBusConsumer::Steps::SubscribeToPartition.new }
6
7
  let(:pipeline) do
7
8
  NulogyMessageBusConsumer::Pipeline.new([
8
9
  NulogyMessageBusConsumer::Steps::ConnectToMessageBus.new(test_topic.config, logger, kafka_consumer: consumer),
9
- NulogyMessageBusConsumer::Steps::SeekBeginningOfTopic.new,
10
- NulogyMessageBusConsumer::Steps::StreamMessagesUntilNoneAreLeft.new(logger),
11
- NulogyMessageBusConsumer::Steps::CommitOnSuccess.new,
10
+ NulogyMessageBusConsumer::Steps::StreamMessagesUntilNoneAreLeft.new(logger, Kafka::CONSUMER_POLL_TIMEOUT),
11
+ NulogyMessageBusConsumer::Steps::CommitOnSuccess.new(logger),
12
12
  handler
13
13
  ])
14
14
  end
15
15
  let(:deduped_pipeline) do
16
16
  NulogyMessageBusConsumer::Pipeline.new([
17
17
  NulogyMessageBusConsumer::Steps::ConnectToMessageBus.new(test_topic.config, logger, kafka_consumer: consumer),
18
- NulogyMessageBusConsumer::Steps::SeekBeginningOfTopic.new,
19
- NulogyMessageBusConsumer::Steps::StreamMessagesUntilNoneAreLeft.new(logger),
18
+ subscribe_to_partition,
19
+ NulogyMessageBusConsumer::Steps::StreamMessagesUntilNoneAreLeft.new(logger, Kafka::CONSUMER_POLL_TIMEOUT),
20
+ NulogyMessageBusConsumer::Steps::CommitOnSuccess.new(logger),
20
21
  NulogyMessageBusConsumer::Steps::DeduplicateMessages.new(logger),
21
- NulogyMessageBusConsumer::Steps::CommitOnSuccess.new,
22
22
  handler
23
23
  ])
24
24
  end
@@ -27,6 +27,8 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
27
27
 
28
28
  context "when successful" do
29
29
  it "commits and processes the next message" do
30
+ create_topic(test_topic.topic_name)
31
+
30
32
  expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_return(:success)
31
33
  expect(handler).to receive(:call).with(a_message_with(key: "test 2")).and_return(:success)
32
34
  expect(consumer).to receive(:commit).twice
@@ -40,10 +42,11 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
40
42
 
41
43
  context "when failing by :failure" do
42
44
  it "reprocesses the message" do
43
- expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_return(:failure)
44
- expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_return(:success)
45
+ create_topic(test_topic.topic_name)
46
+
47
+ expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_return(:failure, :success)
45
48
  expect(handler).to receive(:call).with(a_message_with(key: "test 2")).and_return(:success)
46
- expect(consumer).to receive(:commit).twice
49
+ expect(consumer).to receive(:commit).twice.and_call_original
47
50
 
48
51
  test_topic.produce_one_message(key: "test 1")
49
52
  test_topic.produce_one_message(key: "test 2")
@@ -55,36 +58,20 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
55
58
  # This test is more illustrative of how we expect it to work.
56
59
  # Specifically, testing the "auto.offset.store" setting for the consumer.
57
60
  context "when a partition has a failing message" do
58
- let(:handler) { ->(message:, **_) { message.event_data[:type] == "good" ? :success : :failure } }
61
+ let(:handler) { ->(message:, **_) { message.event_data[:type].start_with?("good") ? :success : :failure } }
59
62
 
60
- it "processes messages from other partitions without committing offsets for partitions with failing messages" do
61
- Kafka.create_topic(test_topic.topic_name)
63
+ it "it blocks subsequent messages from being processed" do
64
+ create_topic(test_topic.topic_name)
62
65
 
63
66
  # Produce message to a single partition. This partition will be blocked by the second message.
64
- test_topic.produce_one_message(partition: 1, event_json: {type: "good"}) # success
67
+ success_id = test_topic.produce_one_message(partition: 1, event_json: {type: "good 1"}) # success
65
68
  test_topic.produce_one_message(partition: 1, event_json: {type: "bad"}) # failure
66
- blocked_id = test_topic.produce_one_message(partition: 1, event_json: {type: "good"}) # blocked
67
-
68
- consume_from_partition(1) do
69
- deduped_pipeline.invoke
70
- end
71
-
72
- # produce to another partition
73
- success_id = test_topic.produce_one_message(partition: 2, event_json: {type: "good"}) # success
74
-
75
- consume_from_partition(2) do
76
- deduped_pipeline.invoke
77
- end
69
+ blocked_id = test_topic.produce_one_message(partition: 1, event_json: {type: "good 2"}) # blocked
78
70
 
79
- # try consuming from all partitions again -- it will fail on the blocked one again
80
71
  deduped_pipeline.invoke
81
72
 
82
- # Wait for assignment after a reconnect
83
- NulogyMessageBusConsumer::KafkaUtils.wait_for_assignment(consumer)
84
-
85
73
  lag = consumer.lag(consumer.committed)
86
- expect(lag.dig(test_topic.topic_name, 1)).to be >= 1
87
- expect(lag.dig(test_topic.topic_name, 2)).to be(0)
74
+ expect(lag.dig(test_topic.topic_name, 1)).to be 2
88
75
  expect(NulogyMessageBusConsumer::ProcessedMessage.exists?(success_id)).to be(true)
89
76
  expect(NulogyMessageBusConsumer::ProcessedMessage.exists?(blocked_id)).to be(false)
90
77
  end
@@ -93,10 +80,12 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
93
80
 
94
81
  context "when failing by exception" do
95
82
  it "reprocesses the message" do
83
+ create_topic(test_topic.topic_name)
84
+
96
85
  expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_raise("intentional error")
97
86
  expect(handler).to receive(:call).with(a_message_with(key: "test 1")).and_return(:success)
98
87
  expect(handler).to receive(:call).with(a_message_with(key: "test 2")).and_return(:success)
99
- expect(consumer).to receive(:commit).twice
88
+ expect(consumer).to receive(:commit).twice.and_call_original
100
89
 
101
90
  test_topic.produce_one_message(key: "test 1")
102
91
  test_topic.produce_one_message(key: "test 2")
@@ -114,18 +103,36 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
114
103
  message: have_attributes(matcher)
115
104
  )
116
105
  end
106
+ end
117
107
 
118
- def consume_from_partition(partition_number)
119
- original_assignment = consumer.assignment
120
- topic_partitions = original_assignment
121
- .to_h
122
- .transform_values { |values| values.select { |t| t.partition == partition_number } }
123
- new_assignment = Rdkafka::Consumer::TopicPartitionList.new(topic_partitions)
124
-
125
- consumer.assign(new_assignment)
108
+ module NulogyMessageBusConsumer
109
+ module Steps
110
+ class SubscribeToPartition
111
+ attr_writer :partition_number
112
+
113
+ def call(kafka_consumer:, **_)
114
+ original_assignment = kafka_consumer.assignment
115
+ if @partition_number
116
+ topic_partitions = original_assignment
117
+ .to_h
118
+ .transform_values { |values| values.select { |t| t.partition == @partition_number } }
119
+ new_assignment = Rdkafka::Consumer::TopicPartitionList.new(topic_partitions)
120
+
121
+ kafka_consumer.assign(new_assignment)
122
+ NulogyMessageBusConsumer::KafkaUtils.wait_for do
123
+ kafka_consumer.assignment == new_assignment
124
+ end
125
+ end
126
126
 
127
- yield
128
- ensure
129
- consumer.assign(original_assignment)
127
+ yield
128
+ ensure
129
+ if @partition_number
130
+ kafka_consumer.assign(original_assignment)
131
+ NulogyMessageBusConsumer::KafkaUtils.wait_for do
132
+ kafka_consumer.assignment == original_assignment
133
+ end
134
+ end
135
+ end
136
+ end
130
137
  end
131
138
  end
@@ -1,46 +1,32 @@
1
1
  RSpec.describe NulogyMessageBusConsumer::Steps::ConnectToMessageBus do
2
- subject(:pipeline) do
3
- pipeline = NulogyMessageBusConsumer.recommended_consumer_pipeline(config: config)
4
- pipeline.insert(tap, after: NulogyMessageBusConsumer::Steps::ConnectToMessageBus)
5
- pipeline.append(message_handler_spy)
6
- pipeline
7
- end
8
-
2
+ let(:logger) { NulogyMessageBusConsumer::NullLogger.new }
9
3
  let(:topic) { TestTopic.new }
10
- let(:config) { topic.config }
11
4
  let(:tap) { MiddlewareTap.new }
12
5
  let(:message_handler_spy) { double }
6
+ let(:pipeline) do
7
+ NulogyMessageBusConsumer::Pipeline.new([
8
+ NulogyMessageBusConsumer::Steps::ConnectToMessageBus.new(topic.config, logger, kafka_consumer: topic.consumer),
9
+ NulogyMessageBusConsumer::Steps::StreamMessagesUntilNoneAreLeft.new(logger, Kafka::CONSUMER_POLL_TIMEOUT),
10
+ message_handler_spy
11
+ ])
12
+ end
13
13
 
14
14
  after { topic.close }
15
15
 
16
- it "receives messages", skip: flakey_in_ci do
17
- called = false
16
+ it "receives messages" do
17
+ create_topic(topic.topic_name)
18
+
18
19
  expect(message_handler_spy).to receive(:call) do |message:, **_kargs|
19
20
  expect(message).to have_attributes(event_data: {data: "Some Payload"})
20
- called = true
21
21
  :success
22
22
  end
23
23
 
24
- pipeline_thread = start(pipeline, tap)
25
-
26
24
  topic.produce_one_message(
27
25
  key: "Some Key",
28
26
  payload: message_payload(data: "Some Payload")
29
27
  )
30
28
 
31
- NulogyMessageBusConsumer::KafkaUtils.wait_for { called }
32
- Thread.kill(pipeline_thread)
33
- end
34
-
35
- def start(pipeline, tap)
36
- thr = Thread.new { pipeline.invoke }
37
- wait_for_partition_assignment(tap)
38
- thr
39
- end
40
-
41
- def wait_for_partition_assignment(tap)
42
- NulogyMessageBusConsumer::KafkaUtils.wait_for { tap.arguments[:kafka_consumer] }
43
- NulogyMessageBusConsumer::KafkaUtils.wait_for_assignment(tap.arguments[:kafka_consumer])
29
+ pipeline.invoke
44
30
  end
45
31
 
46
32
  def message_payload(**payload)
@@ -5,6 +5,8 @@ RSpec.describe TestTopic do
5
5
 
6
6
  context "smoke test for specs" do
7
7
  it "publishes and receives messages" do
8
+ create_topic(topic.topic_name)
9
+
8
10
  topic.produce_one_message(
9
11
  key: "Some Key",
10
12
  payload: "Some Payload"
@@ -18,6 +20,8 @@ RSpec.describe TestTopic do
18
20
  end
19
21
 
20
22
  it "receives returns nil when no messages are received" do
23
+ create_topic(topic.topic_name)
24
+
21
25
  consumer = topic.consumer
22
26
  message = consumer.poll(1)
23
27
  expect(message).to be(nil)
@@ -3,16 +3,7 @@ require "open3"
3
3
  module Kafka
4
4
  module_function
5
5
 
6
- def kafka_config
7
- config = {
8
- "auto.offset.reset": "beginning",
9
- "bootstrap.servers": test_bootstrap_servers,
10
- "enable.auto.commit": false,
11
- "group.id": random_consumer_group
12
- }
13
-
14
- Rdkafka::Config.new(config)
15
- end
6
+ CONSUMER_POLL_TIMEOUT = 1000
16
7
 
17
8
  def random_topic_name
18
9
  "test-topic-#{SecureRandom.uuid}"
@@ -27,16 +18,36 @@ module Kafka
27
18
  end
28
19
 
29
20
  def setup_kafka_producer
30
- kafka_config.producer
21
+ kafka_producer_config.producer
22
+ end
23
+
24
+ def kafka_producer_config
25
+ config = {"bootstrap.servers": test_bootstrap_servers}
26
+
27
+ Rdkafka::Config.new(config)
31
28
  end
32
29
 
33
30
  def setup_kafka_consumer(topic_name)
34
- consumer = kafka_config.consumer
31
+ consumer = kafka_consumer_config.consumer
35
32
  consumer.subscribe(topic_name)
36
33
  NulogyMessageBusConsumer::KafkaUtils.wait_for_assignment(consumer)
37
34
  consumer
38
35
  end
39
36
 
37
+ # TODO: Why is this duplicated from ConnectToMessageBus
38
+ def kafka_consumer_config
39
+ config = {
40
+ "auto.offset.reset": "beginning",
41
+ "bootstrap.servers": test_bootstrap_servers,
42
+ "enable.auto.commit": false,
43
+ "enable.auto.offset.store": false,
44
+ "group.id": random_consumer_group,
45
+ "security.protocol": "plaintext"
46
+ }
47
+
48
+ Rdkafka::Config.new(config)
49
+ end
50
+
40
51
  def create_topic(topic_name)
41
52
  run("kaf topic create #{topic_name} --brokers #{test_bootstrap_servers} --replicas 1 --partitions 3")
42
53
  end
@@ -68,7 +79,8 @@ module Kafka
68
79
  NulogyMessageBusConsumer::Config.new(
69
80
  consumer_group_id: random_consumer_group,
70
81
  bootstrap_servers: test_bootstrap_servers,
71
- topic_name: topic_name
82
+ topic_name: topic_name,
83
+ security_protocol: "plaintext"
72
84
  )
73
85
  end
74
86
  end
@@ -34,7 +34,7 @@ class TestTopic
34
34
  end
35
35
 
36
36
  def consume_one_message
37
- consumer.poll(250)
37
+ consumer.poll(Kafka::CONSUMER_POLL_TIMEOUT)
38
38
  end
39
39
 
40
40
  def config
@@ -1,5 +1,6 @@
1
1
  RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
2
- subject(:step) { NulogyMessageBusConsumer::Steps::CommitOnSuccess.new }
2
+ let(:logger) { NulogyMessageBusConsumer::NullLogger.new }
3
+ subject(:step) { NulogyMessageBusConsumer::Steps::CommitOnSuccess.new(logger) }
3
4
 
4
5
  let(:kafka_consumer) { spy }
5
6
  let(:message) { NulogyMessageBusConsumer::Message.new }
@@ -21,6 +22,9 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
21
22
 
22
23
  context "when result is :failure" do
23
24
  it "returns the result" do
25
+ topic_partition_list = {topic_name: %i[partition_1 partition_2]}
26
+ allow(kafka_consumer).to receive(:assignment).and_return(topic_partition_list)
27
+
24
28
  result = step.call(kafka_consumer: kafka_consumer, message: message) { :failure }
25
29
 
26
30
  expect(result).to be(:failure)
@@ -33,6 +37,8 @@ RSpec.describe NulogyMessageBusConsumer::Steps::CommitOnSuccess do
33
37
 
34
38
  expect(kafka_consumer).to receive(:unsubscribe)
35
39
  expect(kafka_consumer).to receive(:subscribe).with(:topic_name)
40
+ expect(kafka_consumer).to receive(:assignment).and_return({})
41
+ expect(kafka_consumer).to receive(:assignment).and_return(topic_partition_list)
36
42
 
37
43
  step.call(kafka_consumer: kafka_consumer, message: message) { :failure }
38
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nulogy_message_bus_consumer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nulogy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-29 00:00:00.000000000 Z
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: bundler-audit
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '='
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.7.0.1
61
+ version: 0.9.2
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '='
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.7.0.1
68
+ version: 0.9.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: dotenv
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +84,16 @@ dependencies:
84
84
  name: pg
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '='
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.2.3
89
+ version: '1.2'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '='
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.2.3
96
+ version: '1.2'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: pry
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +128,28 @@ dependencies:
128
128
  requirements:
129
129
  - - '='
130
130
  - !ruby/object:Gem::Version
131
- version: 6.0.3.5
131
+ version: 6.0.4
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
136
  - - '='
137
137
  - !ruby/object:Gem::Version
138
- version: 6.0.3.5
138
+ version: 6.0.4
139
+ - !ruby/object:Gem::Dependency
140
+ name: psych
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "<"
144
+ - !ruby/object:Gem::Version
145
+ version: '4'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "<"
151
+ - !ruby/object:Gem::Version
152
+ version: '4'
139
153
  - !ruby/object:Gem::Dependency
140
154
  name: rspec
141
155
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +323,7 @@ files:
309
323
  - spec/dummy/public/favicon.ico
310
324
  - spec/dummy/tmp/development_secret.txt
311
325
  - spec/integration/nulogy_message_bus_consumer/auditor_spec.rb
326
+ - spec/integration/nulogy_message_bus_consumer/end_to_end_spec.rb
312
327
  - spec/integration/nulogy_message_bus_consumer/kafka_utils_spec.rb
313
328
  - spec/integration/nulogy_message_bus_consumer/steps/commit_on_success_spec.rb
314
329
  - spec/integration/nulogy_message_bus_consumer/steps/connect_to_message_bus_spec.rb
@@ -349,7 +364,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
349
364
  - !ruby/object:Gem::Version
350
365
  version: '0'
351
366
  requirements: []
352
- rubygems_version: 3.2.15
367
+ rubygems_version: 3.4.19
353
368
  signing_key:
354
369
  specification_version: 4
355
370
  summary: Code for accessing the Nulogy Message Bus
@@ -407,6 +422,7 @@ test_files:
407
422
  - spec/dummy/public/favicon.ico
408
423
  - spec/dummy/tmp/development_secret.txt
409
424
  - spec/integration/nulogy_message_bus_consumer/auditor_spec.rb
425
+ - spec/integration/nulogy_message_bus_consumer/end_to_end_spec.rb
410
426
  - spec/integration/nulogy_message_bus_consumer/kafka_utils_spec.rb
411
427
  - spec/integration/nulogy_message_bus_consumer/steps/commit_on_success_spec.rb
412
428
  - spec/integration/nulogy_message_bus_consumer/steps/connect_to_message_bus_spec.rb