deimos-kafka 1.0.0.pre.beta15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +74 -0
  3. data/.gitignore +41 -0
  4. data/.gitmodules +0 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +321 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +9 -0
  10. data/CODE_OF_CONDUCT.md +77 -0
  11. data/Dockerfile +23 -0
  12. data/Gemfile +6 -0
  13. data/Gemfile.lock +165 -0
  14. data/Guardfile +22 -0
  15. data/LICENSE.md +195 -0
  16. data/README.md +742 -0
  17. data/Rakefile +13 -0
  18. data/bin/deimos +4 -0
  19. data/deimos-kafka.gemspec +42 -0
  20. data/docker-compose.yml +71 -0
  21. data/docs/DATABASE_BACKEND.md +147 -0
  22. data/docs/PULL_REQUEST_TEMPLATE.md +34 -0
  23. data/lib/deimos.rb +134 -0
  24. data/lib/deimos/active_record_consumer.rb +81 -0
  25. data/lib/deimos/active_record_producer.rb +64 -0
  26. data/lib/deimos/avro_data_coder.rb +89 -0
  27. data/lib/deimos/avro_data_decoder.rb +36 -0
  28. data/lib/deimos/avro_data_encoder.rb +51 -0
  29. data/lib/deimos/backends/db.rb +27 -0
  30. data/lib/deimos/backends/kafka.rb +27 -0
  31. data/lib/deimos/backends/kafka_async.rb +27 -0
  32. data/lib/deimos/configuration.rb +88 -0
  33. data/lib/deimos/consumer.rb +164 -0
  34. data/lib/deimos/instrumentation.rb +71 -0
  35. data/lib/deimos/kafka_message.rb +27 -0
  36. data/lib/deimos/kafka_source.rb +126 -0
  37. data/lib/deimos/kafka_topic_info.rb +79 -0
  38. data/lib/deimos/message.rb +74 -0
  39. data/lib/deimos/metrics/datadog.rb +47 -0
  40. data/lib/deimos/metrics/mock.rb +39 -0
  41. data/lib/deimos/metrics/provider.rb +38 -0
  42. data/lib/deimos/monkey_patches/phobos_cli.rb +35 -0
  43. data/lib/deimos/monkey_patches/phobos_producer.rb +51 -0
  44. data/lib/deimos/monkey_patches/ruby_kafka_heartbeat.rb +85 -0
  45. data/lib/deimos/monkey_patches/schema_store.rb +19 -0
  46. data/lib/deimos/producer.rb +218 -0
  47. data/lib/deimos/publish_backend.rb +30 -0
  48. data/lib/deimos/railtie.rb +8 -0
  49. data/lib/deimos/schema_coercer.rb +108 -0
  50. data/lib/deimos/shared_config.rb +59 -0
  51. data/lib/deimos/test_helpers.rb +356 -0
  52. data/lib/deimos/tracing/datadog.rb +35 -0
  53. data/lib/deimos/tracing/mock.rb +40 -0
  54. data/lib/deimos/tracing/provider.rb +31 -0
  55. data/lib/deimos/utils/db_producer.rb +95 -0
  56. data/lib/deimos/utils/executor.rb +117 -0
  57. data/lib/deimos/utils/inline_consumer.rb +144 -0
  58. data/lib/deimos/utils/lag_reporter.rb +182 -0
  59. data/lib/deimos/utils/platform_schema_validation.rb +0 -0
  60. data/lib/deimos/utils/signal_handler.rb +68 -0
  61. data/lib/deimos/version.rb +5 -0
  62. data/lib/generators/deimos/db_backend/templates/migration +24 -0
  63. data/lib/generators/deimos/db_backend/templates/rails3_migration +30 -0
  64. data/lib/generators/deimos/db_backend_generator.rb +48 -0
  65. data/lib/tasks/deimos.rake +17 -0
  66. data/spec/active_record_consumer_spec.rb +81 -0
  67. data/spec/active_record_producer_spec.rb +107 -0
  68. data/spec/avro_data_decoder_spec.rb +18 -0
  69. data/spec/avro_data_encoder_spec.rb +37 -0
  70. data/spec/backends/db_spec.rb +35 -0
  71. data/spec/backends/kafka_async_spec.rb +11 -0
  72. data/spec/backends/kafka_spec.rb +11 -0
  73. data/spec/consumer_spec.rb +169 -0
  74. data/spec/deimos_spec.rb +117 -0
  75. data/spec/kafka_source_spec.rb +168 -0
  76. data/spec/kafka_topic_info_spec.rb +88 -0
  77. data/spec/phobos.bad_db.yml +73 -0
  78. data/spec/phobos.yml +73 -0
  79. data/spec/producer_spec.rb +397 -0
  80. data/spec/publish_backend_spec.rb +10 -0
  81. data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
  82. data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
  83. data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
  84. data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
  85. data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
  86. data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
  87. data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
  88. data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
  89. data/spec/spec_helper.rb +207 -0
  90. data/spec/updateable_schema_store_spec.rb +36 -0
  91. data/spec/utils/db_producer_spec.rb +208 -0
  92. data/spec/utils/executor_spec.rb +42 -0
  93. data/spec/utils/lag_reporter_spec.rb +69 -0
  94. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  95. data/spec/utils/signal_handler_spec.rb +16 -0
  96. data/support/deimos-solo.png +0 -0
  97. data/support/deimos-with-name-next.png +0 -0
  98. data/support/deimos-with-name.png +0 -0
  99. data/support/flipp-logo.png +0 -0
  100. metadata +452 -0
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module ActiveRecordProducerTest
5
+ describe Deimos::ActiveRecordProducer do
6
+
7
+ before(:all) do
8
+ ActiveRecord::Base.connection.create_table(:widgets) do |t|
9
+ t.string(:test_id)
10
+ t.integer(:some_int)
11
+ t.boolean(:some_bool)
12
+ t.timestamps
13
+ end
14
+
15
+ # :nodoc:
16
+ class Widget < ActiveRecord::Base
17
+ # @return [String]
18
+ def generated_id
19
+ 'generated_id'
20
+ end
21
+ end
22
+ end
23
+
24
+ after(:all) do
25
+ ActiveRecord::Base.connection.drop_table(:widgets)
26
+ end
27
+
28
+ prepend_before(:each) do
29
+
30
+ producer_class = Class.new(Deimos::ActiveRecordProducer) do
31
+ schema 'MySchema'
32
+ namespace 'com.my-namespace'
33
+ topic 'my-topic'
34
+ key_config none: true
35
+ end
36
+ stub_const('MyProducer', producer_class)
37
+
38
+ producer_class = Class.new(Deimos::ActiveRecordProducer) do
39
+ schema 'MySchemaWithBooleans'
40
+ namespace 'com.my-namespace'
41
+ topic 'my-topic-with-boolean'
42
+ key_config none: true
43
+ end
44
+ stub_const('MyBooleanProducer', producer_class)
45
+
46
+ producer_class = Class.new(Deimos::ActiveRecordProducer) do
47
+ schema 'MySchemaWithId'
48
+ namespace 'com.my-namespace'
49
+ topic 'my-topic-with-id'
50
+ key_config none: true
51
+ record_class Widget
52
+
53
+ # :nodoc:
54
+ def self.generate_payload(attrs, widget)
55
+ super.merge(message_id: widget.generated_id)
56
+ end
57
+
58
+ end
59
+ stub_const('MyProducerWithID', producer_class)
60
+
61
+ producer_class = Class.new(Deimos::ActiveRecordProducer) do
62
+ schema 'MySchemaWithUniqueId'
63
+ namespace 'com.my-namespace'
64
+ topic 'my-topic-with-unique-id'
65
+ key_config field: :id
66
+ record_class Widget
67
+ end
68
+ stub_const('MyProducerWithUniqueID', producer_class)
69
+ end
70
+
71
+ it 'should send events correctly' do
72
+ MyProducer.send_event(Widget.new(test_id: 'abc', some_int: 3))
73
+ expect('my-topic').to have_sent(test_id: 'abc', some_int: 3)
74
+ end
75
+
76
+ it 'should coerce values' do
77
+ MyProducer.send_event(Widget.new(test_id: 'abc', some_int: '3'))
78
+ MyProducer.send_event(Widget.new(test_id: 'abc', some_int: 4.5))
79
+ expect('my-topic').to have_sent(test_id: 'abc', some_int: 3)
80
+ expect('my-topic').to have_sent(test_id: 'abc', some_int: 4)
81
+ expect {
82
+ MyProducer.send_event(Widget.new(test_id: 'abc', some_int: nil))
83
+ }.to raise_error(Avro::SchemaValidator::ValidationError)
84
+
85
+ MyBooleanProducer.send_event(Widget.new(test_id: 'abc', some_bool: nil))
86
+ MyBooleanProducer.send_event(Widget.new(test_id: 'abc', some_bool: true))
87
+ expect('my-topic-with-boolean').to have_sent(test_id: 'abc', some_bool: false)
88
+ expect('my-topic-with-boolean').to have_sent(test_id: 'abc', some_bool: true)
89
+ end
90
+
91
+ it 'should be able to call the record' do
92
+ widget = Widget.create!(test_id: 'abc2', some_int: 3)
93
+ MyProducerWithID.send_event(id: widget.id, test_id: 'abc2', some_int: 3)
94
+ expect('my-topic-with-id').to have_sent(
95
+ test_id: 'abc2',
96
+ some_int: 3,
97
+ message_id: 'generated_id',
98
+ timestamp: anything
99
+ )
100
+ end
101
+
102
+ specify '#watched_attributes' do
103
+ expect(MyProducer.watched_attributes).to eq(%w(test_id some_int))
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Deimos::AvroDataDecoder do
4
+
5
+ let(:decoder) do
6
+ decoder = described_class.new(schema: 'MySchema',
7
+ namespace: 'com.my-namespace')
8
+ allow(decoder).to(receive(:decode)) { |payload| payload }
9
+ decoder
10
+ end
11
+
12
+ it 'should decode a key' do
13
+ # reset stub from TestHelpers
14
+ allow(described_class).to receive(:new).and_call_original
15
+ expect(decoder.decode_key({ 'test_id' => '123' }, 'test_id')).to eq('123')
16
+ end
17
+
18
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'avro_turf/messaging'
4
+
5
+ describe Deimos::AvroDataEncoder do
6
+
7
+ let(:encoder) do
8
+ encoder = described_class.new(schema: 'MySchema',
9
+ namespace: 'com.my-namespace')
10
+ allow(encoder).to(receive(:encode)) { |payload| payload }
11
+ encoder
12
+ end
13
+
14
+ specify 'generate_key_schema' do
15
+ expect_any_instance_of(AvroTurf::SchemaStore).
16
+ to receive(:add_schema).with(
17
+ 'type' => 'record',
18
+ 'name' => 'MySchema_key',
19
+ 'namespace' => 'com.my-namespace',
20
+ 'doc' => 'Key for com.my-namespace.MySchema',
21
+ 'fields' => [
22
+ {
23
+ 'name' => 'test_id',
24
+ 'type' => 'string'
25
+ }
26
+ ]
27
+ )
28
+ encoder.send(:_generate_key_schema, 'test_id')
29
+ end
30
+
31
+ it 'should encode a key' do
32
+ # reset stub from TestHelpers
33
+ allow(described_class).to receive(:new).and_call_original
34
+ expect(encoder.encode_key('test_id', '123')).to eq('test_id' => '123')
35
+ end
36
+
37
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ each_db_config(Deimos::Backends::Db) do
4
+ include_context 'with publish_backend'
5
+
6
+ it 'should save to the database' do
7
+ described_class.publish(producer_class: MyProducer, messages: messages)
8
+ records = Deimos::KafkaMessage.all
9
+ expect(records.size).to eq(3)
10
+ expect(records[0].attributes.to_h).to include(
11
+ 'message' => '{"foo"=>1}',
12
+ 'topic' => 'my-topic',
13
+ 'key' => 'foo1'
14
+ )
15
+ expect(records[1].attributes.to_h).to include(
16
+ 'message' => '{"foo"=>2}',
17
+ 'topic' => 'my-topic',
18
+ 'key' => 'foo2'
19
+ )
20
+ expect(records[2].attributes.to_h).to include(
21
+ 'message' => '{"foo"=>3}',
22
+ 'topic' => 'my-topic',
23
+ 'key' => 'foo3'
24
+ )
25
+ end
26
+ it 'should add to non-keyed messages' do
27
+ described_class.publish(producer_class: MyNoKeyProducer,
28
+ messages: messages)
29
+ expect(Deimos::KafkaMessage.count).to eq(3)
30
+ described_class.publish(producer_class: MyNoKeyProducer,
31
+ messages: [messages.first])
32
+ expect(Deimos::KafkaMessage.count).to eq(4)
33
+
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Deimos::Backends::KafkaAsync do
4
+ include_context 'with publish_backend'
5
+ it 'should publish to Kafka asynchronously' do
6
+ producer = instance_double(Phobos::Producer::ClassMethods::PublicAPI)
7
+ expect(producer).to receive(:async_publish_list).with(messages.map(&:encoded_hash))
8
+ expect(described_class).to receive(:producer).and_return(producer)
9
+ described_class.publish(producer_class: MyProducer, messages: messages)
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Deimos::Backends::Kafka do
4
+ include_context 'with publish_backend'
5
+ it 'should publish to Kafka synchronously' do
6
+ producer = instance_double(Phobos::Producer::ClassMethods::PublicAPI)
7
+ expect(producer).to receive(:publish_list).with(messages.map(&:encoded_hash))
8
+ expect(described_class).to receive(:producer).and_return(producer)
9
+ described_class.publish(producer_class: MyProducer, messages: messages)
10
+ end
11
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module ConsumerTest
5
+ describe Deimos::Consumer do
6
+
7
+ prepend_before(:each) do
8
+ # :nodoc:
9
+ consumer_class = Class.new(Deimos::Consumer) do
10
+ schema 'MySchema'
11
+ namespace 'com.my-namespace'
12
+ key_config field: 'test_id'
13
+
14
+ # :nodoc:
15
+ def consume(_payload, _metadata)
16
+ raise 'This should not be called unless call_original is set'
17
+ end
18
+ end
19
+ stub_const('ConsumerTest::MyConsumer', consumer_class)
20
+ end
21
+
22
+ it 'should consume a message' do
23
+ test_consume_message(MyConsumer,
24
+ 'test_id' => 'foo',
25
+ 'some_int' => 123) do |payload, _metadata|
26
+ expect(payload['test_id']).to eq('foo')
27
+ end
28
+ end
29
+
30
+ it 'should consume a message on a topic' do
31
+ test_consume_message('my_consume_topic',
32
+ 'test_id' => 'foo',
33
+ 'some_int' => 123) do |payload, _metadata|
34
+ expect(payload['test_id']).to eq('foo')
35
+ end
36
+ end
37
+
38
+ it 'should fail on invalid message' do
39
+ test_consume_invalid_message(MyConsumer, 'invalid' => 'key')
40
+ end
41
+
42
+ it 'should fail on message with extra fields' do
43
+ test_consume_invalid_message(MyConsumer,
44
+ 'test_id' => 'foo',
45
+ 'some_int' => 123,
46
+ 'extra_field' => 'field name')
47
+ end
48
+
49
+ it 'should not fail when before_consume fails without reraising errors' do
50
+ Deimos.configure { |config| config.reraise_consumer_errors = false }
51
+ expect {
52
+ test_consume_message(
53
+ MyConsumer,
54
+ { 'test_id' => 'foo',
55
+ 'some_int' => 123 },
56
+ { skip_expectation: true }
57
+ ) { raise 'OH NOES' }
58
+ } .not_to raise_error
59
+ end
60
+
61
+ it 'should not fail when consume fails without reraising errors' do
62
+ Deimos.configure { |config| config.reraise_consumer_errors = false }
63
+ expect {
64
+ test_consume_message(
65
+ MyConsumer,
66
+ { 'invalid' => 'key' },
67
+ { skip_expectation: true }
68
+ )
69
+ } .not_to raise_error
70
+ end
71
+
72
+ it 'should call original' do
73
+ expect {
74
+ test_consume_message(MyConsumer,
75
+ { 'test_id' => 'foo', 'some_int' => 123 },
76
+ { call_original: true })
77
+ }.to raise_error('This should not be called unless call_original is set')
78
+ end
79
+
80
+ describe 'decode_key' do
81
+
82
+ it 'should use the key field in the value if set' do
83
+ # actual decoding is disabled in test
84
+ expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
85
+ expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
86
+ end
87
+
88
+ it 'should use the key schema if set' do
89
+ consumer_class = Class.new(Deimos::Consumer) do
90
+ schema 'MySchema'
91
+ namespace 'com.my-namespace'
92
+ key_config schema: 'MySchema_key'
93
+ end
94
+ stub_const('ConsumerTest::MySchemaConsumer', consumer_class)
95
+ expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
96
+ expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
97
+ end
98
+
99
+ it 'should not encode if plain is set' do
100
+ consumer_class = Class.new(Deimos::Consumer) do
101
+ schema 'MySchema'
102
+ namespace 'com.my-namespace'
103
+ key_config plain: true
104
+ end
105
+ stub_const('ConsumerTest::MyNonEncodedConsumer', consumer_class)
106
+ expect(MyNonEncodedConsumer.new.decode_key('123')).to eq('123')
107
+ end
108
+
109
+ it 'should error with nothing set' do
110
+ consumer_class = Class.new(Deimos::Consumer) do
111
+ schema 'MySchema'
112
+ namespace 'com.my-namespace'
113
+ end
114
+ stub_const('ConsumerTest::MyErrorConsumer', consumer_class)
115
+ expect { MyErrorConsumer.new.decode_key('123') }.
116
+ to raise_error('No key config given - if you are not decoding keys, please use `key_config plain: true`')
117
+ end
118
+
119
+ end
120
+
121
+ describe 'timestamps' do
122
+ before(:each) do
123
+ # :nodoc:
124
+ consumer_class = Class.new(Deimos::Consumer) do
125
+ schema 'MySchemaWithDateTimes'
126
+ namespace 'com.my-namespace'
127
+ key_config plain: true
128
+
129
+ # :nodoc:
130
+ def consume(_payload, _metadata)
131
+ raise 'This should not be called unless call_original is set'
132
+ end
133
+ end
134
+ stub_const('ConsumerTest::MyConsumer', consumer_class)
135
+ stub_consumer(consumer_class)
136
+ end
137
+
138
+ it 'should consume a message' do
139
+ expect(Deimos.config.metrics).to receive(:histogram).twice
140
+ test_consume_message('my_consume_topic',
141
+ 'test_id' => 'foo',
142
+ 'some_int' => 123,
143
+ 'updated_at' => Time.now.to_i,
144
+ 'timestamp' => 2.minutes.ago.to_s) do |payload, _metadata|
145
+ expect(payload['test_id']).to eq('foo')
146
+ end
147
+ end
148
+
149
+ it 'should fail nicely when timestamp wrong format' do
150
+ expect(Deimos.config.metrics).to receive(:histogram).twice
151
+ test_consume_message('my_consume_topic',
152
+ 'test_id' => 'foo',
153
+ 'some_int' => 123,
154
+ 'updated_at' => Time.now.to_i,
155
+ 'timestamp' => 'dffdf') do |payload, _metadata|
156
+ expect(payload['test_id']).to eq('foo')
157
+ end
158
+ test_consume_message('my_consume_topic',
159
+ 'test_id' => 'foo',
160
+ 'some_int' => 123,
161
+ 'updated_at' => Time.now.to_i,
162
+ 'timestamp' => '') do |payload, _metadata|
163
+ expect(payload['test_id']).to eq('foo')
164
+ end
165
+ end
166
+
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Deimos do
4
+
5
+ it 'should have a version number' do
6
+ expect(Deimos::VERSION).not_to be_nil
7
+ end
8
+
9
+ specify 'configure' do
10
+ phobos_configuration = { 'logger' =>
11
+ { 'file' => 'log/phobos.log',
12
+ 'stdout_json' => false,
13
+ 'level' => 'debug',
14
+ 'ruby_kafka' =>
15
+ { 'level' => 'debug' } },
16
+ 'kafka' =>
17
+ { 'client_id' => 'phobos',
18
+ 'connect_timeout' => 15,
19
+ 'socket_timeout' => 15,
20
+ 'seed_brokers' => 'my_seed_broker.com',
21
+ 'ssl_ca_cert' => 'my_ssl_ca_cert',
22
+ 'ssl_client_cert' => 'my_ssl_client_cert',
23
+ 'ssl_client_cert_key' => 'my_ssl_client_cert_key' },
24
+ 'producer' =>
25
+ { 'ack_timeout' => 5,
26
+ 'required_acks' => :all,
27
+ 'max_retries' => 2,
28
+ 'retry_backoff' => 1,
29
+ 'max_buffer_size' => 10_000,
30
+ 'max_buffer_bytesize' => 10_000_000,
31
+ 'compression_codec' => nil,
32
+ 'compression_threshold' => 1,
33
+ 'max_queue_size' => 10_000,
34
+ 'delivery_threshold' => 0,
35
+ 'delivery_interval' => 0 },
36
+ 'consumer' =>
37
+ { 'session_timeout' => 300,
38
+ 'offset_commit_interval' => 10,
39
+ 'offset_commit_threshold' => 0,
40
+ 'heartbeat_interval' => 10 },
41
+ 'backoff' =>
42
+ { 'min_ms' => 1000,
43
+ 'max_ms' => 60_000 },
44
+ 'listeners' => [
45
+ { 'handler' => 'ConsumerTest::MyConsumer',
46
+ 'topic' => 'my_consume_topic',
47
+ 'group_id' => 'my_group_id',
48
+ 'max_bytes_per_partition' => 524_288 }
49
+ ],
50
+ 'custom_logger' => nil,
51
+ 'custom_kafka_logger' => nil }
52
+
53
+ expect(Phobos).to receive(:configure).with(phobos_configuration)
54
+ allow(described_class).to receive(:ssl_var_contents) { |key| key }
55
+ described_class.configure do |config|
56
+ config.phobos_config_file = File.join(File.dirname(__FILE__), 'phobos.yml')
57
+ config.seed_broker = 'my_seed_broker.com'
58
+ config.ssl_enabled = true
59
+ config.ssl_ca_cert = 'my_ssl_ca_cert'
60
+ config.ssl_client_cert = 'my_ssl_client_cert'
61
+ config.ssl_client_cert_key = 'my_ssl_client_cert_key'
62
+ end
63
+ end
64
+
65
+ it 'should error if required_acks is not all' do
66
+ expect {
67
+ described_class.configure do |config|
68
+ config.publish_backend = :db
69
+ config.phobos_config_file = File.join(File.dirname(__FILE__), 'phobos.bad_db.yml')
70
+ end
71
+ }.to raise_error('Cannot set publish_backend to :db unless required_acks is set to ":all" in phobos.yml!')
72
+ end
73
+
74
+ describe '#start_db_backend!' do
75
+ before(:each) do
76
+ allow(described_class).to receive(:run_db_backend_in_thread)
77
+ end
78
+
79
+ it 'should start if backend is db and num_producer_threads is > 0' do
80
+ signal_handler = instance_double(Deimos::Utils::SignalHandler)
81
+ allow(signal_handler).to receive(:run!)
82
+ expect(Deimos::Utils::SignalHandler).to receive(:new) do |executor|
83
+ expect(executor.runners.size).to eq(2)
84
+ signal_handler
85
+ end
86
+ described_class.configure do |config|
87
+ config.publish_backend = :db
88
+ end
89
+ described_class.start_db_backend!(thread_count: 2)
90
+ end
91
+
92
+ it 'should not start if backend is not db' do
93
+ expect(Deimos::Utils::SignalHandler).not_to receive(:new)
94
+ described_class.configure do |config|
95
+ config.publish_backend = :kafka
96
+ end
97
+ described_class.start_db_backend!(thread_count: 2)
98
+ end
99
+
100
+ it 'should not start if num_producer_threads is nil' do
101
+ expect(Deimos::Utils::SignalHandler).not_to receive(:new)
102
+ described_class.configure do |config|
103
+ config.publish_backend = :db
104
+ end
105
+ described_class.start_db_backend!(thread_count: nil)
106
+ end
107
+
108
+ it 'should not start if num_producer_threads is 0' do
109
+ expect(Deimos::Utils::SignalHandler).not_to receive(:new)
110
+ described_class.configure do |config|
111
+ config.publish_backend = :db
112
+ end
113
+ described_class.start_db_backend!(thread_count: 0)
114
+ end
115
+
116
+ end
117
+ end