deimos-temp-fork 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +83 -0
  3. data/.gitignore +41 -0
  4. data/.gitmodules +0 -0
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +333 -0
  7. data/.ruby-gemset +1 -0
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +349 -0
  10. data/CODE_OF_CONDUCT.md +77 -0
  11. data/Dockerfile +23 -0
  12. data/Gemfile +6 -0
  13. data/Gemfile.lock +286 -0
  14. data/Guardfile +22 -0
  15. data/LICENSE.md +195 -0
  16. data/README.md +1099 -0
  17. data/Rakefile +13 -0
  18. data/bin/deimos +4 -0
  19. data/deimos-ruby.gemspec +44 -0
  20. data/docker-compose.yml +71 -0
  21. data/docs/ARCHITECTURE.md +140 -0
  22. data/docs/CONFIGURATION.md +236 -0
  23. data/docs/DATABASE_BACKEND.md +147 -0
  24. data/docs/INTEGRATION_TESTS.md +52 -0
  25. data/docs/PULL_REQUEST_TEMPLATE.md +35 -0
  26. data/docs/UPGRADING.md +128 -0
  27. data/lib/deimos-temp-fork.rb +95 -0
  28. data/lib/deimos/active_record_consume/batch_consumption.rb +164 -0
  29. data/lib/deimos/active_record_consume/batch_slicer.rb +27 -0
  30. data/lib/deimos/active_record_consume/message_consumption.rb +79 -0
  31. data/lib/deimos/active_record_consume/schema_model_converter.rb +52 -0
  32. data/lib/deimos/active_record_consumer.rb +67 -0
  33. data/lib/deimos/active_record_producer.rb +87 -0
  34. data/lib/deimos/backends/base.rb +32 -0
  35. data/lib/deimos/backends/db.rb +41 -0
  36. data/lib/deimos/backends/kafka.rb +33 -0
  37. data/lib/deimos/backends/kafka_async.rb +33 -0
  38. data/lib/deimos/backends/test.rb +20 -0
  39. data/lib/deimos/batch_consumer.rb +7 -0
  40. data/lib/deimos/config/configuration.rb +381 -0
  41. data/lib/deimos/config/phobos_config.rb +137 -0
  42. data/lib/deimos/consume/batch_consumption.rb +150 -0
  43. data/lib/deimos/consume/message_consumption.rb +94 -0
  44. data/lib/deimos/consumer.rb +104 -0
  45. data/lib/deimos/instrumentation.rb +76 -0
  46. data/lib/deimos/kafka_message.rb +60 -0
  47. data/lib/deimos/kafka_source.rb +128 -0
  48. data/lib/deimos/kafka_topic_info.rb +102 -0
  49. data/lib/deimos/message.rb +79 -0
  50. data/lib/deimos/metrics/datadog.rb +47 -0
  51. data/lib/deimos/metrics/mock.rb +39 -0
  52. data/lib/deimos/metrics/provider.rb +36 -0
  53. data/lib/deimos/monkey_patches/phobos_cli.rb +35 -0
  54. data/lib/deimos/monkey_patches/phobos_producer.rb +51 -0
  55. data/lib/deimos/poll_info.rb +9 -0
  56. data/lib/deimos/producer.rb +224 -0
  57. data/lib/deimos/railtie.rb +8 -0
  58. data/lib/deimos/schema_backends/avro_base.rb +140 -0
  59. data/lib/deimos/schema_backends/avro_local.rb +30 -0
  60. data/lib/deimos/schema_backends/avro_schema_coercer.rb +119 -0
  61. data/lib/deimos/schema_backends/avro_schema_registry.rb +34 -0
  62. data/lib/deimos/schema_backends/avro_validation.rb +21 -0
  63. data/lib/deimos/schema_backends/base.rb +150 -0
  64. data/lib/deimos/schema_backends/mock.rb +42 -0
  65. data/lib/deimos/shared_config.rb +63 -0
  66. data/lib/deimos/test_helpers.rb +360 -0
  67. data/lib/deimos/tracing/datadog.rb +35 -0
  68. data/lib/deimos/tracing/mock.rb +40 -0
  69. data/lib/deimos/tracing/provider.rb +29 -0
  70. data/lib/deimos/utils/db_poller.rb +150 -0
  71. data/lib/deimos/utils/db_producer.rb +243 -0
  72. data/lib/deimos/utils/deadlock_retry.rb +68 -0
  73. data/lib/deimos/utils/inline_consumer.rb +150 -0
  74. data/lib/deimos/utils/lag_reporter.rb +175 -0
  75. data/lib/deimos/utils/schema_controller_mixin.rb +115 -0
  76. data/lib/deimos/version.rb +5 -0
  77. data/lib/generators/deimos/active_record/templates/migration.rb.tt +28 -0
  78. data/lib/generators/deimos/active_record/templates/model.rb.tt +5 -0
  79. data/lib/generators/deimos/active_record_generator.rb +79 -0
  80. data/lib/generators/deimos/db_backend/templates/migration +25 -0
  81. data/lib/generators/deimos/db_backend/templates/rails3_migration +31 -0
  82. data/lib/generators/deimos/db_backend_generator.rb +48 -0
  83. data/lib/generators/deimos/db_poller/templates/migration +11 -0
  84. data/lib/generators/deimos/db_poller/templates/rails3_migration +16 -0
  85. data/lib/generators/deimos/db_poller_generator.rb +48 -0
  86. data/lib/tasks/deimos.rake +34 -0
  87. data/spec/active_record_batch_consumer_spec.rb +481 -0
  88. data/spec/active_record_consume/batch_slicer_spec.rb +42 -0
  89. data/spec/active_record_consume/schema_model_converter_spec.rb +105 -0
  90. data/spec/active_record_consumer_spec.rb +154 -0
  91. data/spec/active_record_producer_spec.rb +85 -0
  92. data/spec/backends/base_spec.rb +10 -0
  93. data/spec/backends/db_spec.rb +54 -0
  94. data/spec/backends/kafka_async_spec.rb +11 -0
  95. data/spec/backends/kafka_spec.rb +11 -0
  96. data/spec/batch_consumer_spec.rb +256 -0
  97. data/spec/config/configuration_spec.rb +248 -0
  98. data/spec/consumer_spec.rb +209 -0
  99. data/spec/deimos_spec.rb +169 -0
  100. data/spec/generators/active_record_generator_spec.rb +56 -0
  101. data/spec/handlers/my_batch_consumer.rb +10 -0
  102. data/spec/handlers/my_consumer.rb +10 -0
  103. data/spec/kafka_listener_spec.rb +55 -0
  104. data/spec/kafka_source_spec.rb +381 -0
  105. data/spec/kafka_topic_info_spec.rb +111 -0
  106. data/spec/message_spec.rb +19 -0
  107. data/spec/phobos.bad_db.yml +73 -0
  108. data/spec/phobos.yml +77 -0
  109. data/spec/producer_spec.rb +498 -0
  110. data/spec/rake_spec.rb +19 -0
  111. data/spec/schema_backends/avro_base_shared.rb +199 -0
  112. data/spec/schema_backends/avro_local_spec.rb +32 -0
  113. data/spec/schema_backends/avro_schema_registry_spec.rb +32 -0
  114. data/spec/schema_backends/avro_validation_spec.rb +24 -0
  115. data/spec/schema_backends/base_spec.rb +33 -0
  116. data/spec/schemas/com/my-namespace/Generated.avsc +71 -0
  117. data/spec/schemas/com/my-namespace/MyNestedSchema.avsc +62 -0
  118. data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
  119. data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
  120. data/spec/schemas/com/my-namespace/MySchemaCompound-key.avsc +18 -0
  121. data/spec/schemas/com/my-namespace/MySchemaWithBooleans.avsc +18 -0
  122. data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
  123. data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
  124. data/spec/schemas/com/my-namespace/MySchemaWithUniqueId.avsc +32 -0
  125. data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
  126. data/spec/schemas/com/my-namespace/Widget.avsc +27 -0
  127. data/spec/schemas/com/my-namespace/WidgetTheSecond.avsc +27 -0
  128. data/spec/schemas/com/my-namespace/request/CreateTopic.avsc +11 -0
  129. data/spec/schemas/com/my-namespace/request/Index.avsc +11 -0
  130. data/spec/schemas/com/my-namespace/request/UpdateRequest.avsc +11 -0
  131. data/spec/schemas/com/my-namespace/response/CreateTopic.avsc +11 -0
  132. data/spec/schemas/com/my-namespace/response/Index.avsc +11 -0
  133. data/spec/schemas/com/my-namespace/response/UpdateResponse.avsc +11 -0
  134. data/spec/spec_helper.rb +267 -0
  135. data/spec/utils/db_poller_spec.rb +320 -0
  136. data/spec/utils/db_producer_spec.rb +514 -0
  137. data/spec/utils/deadlock_retry_spec.rb +74 -0
  138. data/spec/utils/inline_consumer_spec.rb +31 -0
  139. data/spec/utils/lag_reporter_spec.rb +76 -0
  140. data/spec/utils/platform_schema_validation_spec.rb +0 -0
  141. data/spec/utils/schema_controller_mixin_spec.rb +84 -0
  142. data/support/deimos-solo.png +0 -0
  143. data/support/deimos-with-name-next.png +0 -0
  144. data/support/deimos-with-name.png +0 -0
  145. data/support/flipp-logo.png +0 -0
  146. metadata +551 -0
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :nodoc:
4
+ module ConsumerTest
5
+ describe Deimos::Consumer, 'Message Consumer' do
6
+
7
+ prepend_before(:each) do
8
+ # :nodoc:
9
+ consumer_class = Class.new(described_class) do
10
+ schema 'MySchema'
11
+ namespace 'com.my-namespace'
12
+ key_config field: 'test_id'
13
+
14
+ # :nodoc:
15
+ def fatal_error?(_exception, payload, _metadata)
16
+ payload == 'fatal'
17
+ end
18
+
19
+ # :nodoc:
20
+ def consume(_payload, _metadata)
21
+ raise 'This should not be called unless call_original is set'
22
+ end
23
+ end
24
+ stub_const('ConsumerTest::MyConsumer', consumer_class)
25
+ end
26
+
27
+ it 'should consume a message' do
28
+ test_consume_message(MyConsumer,
29
+ 'test_id' => 'foo',
30
+ 'some_int' => 123) do |payload, _metadata|
31
+ expect(payload['test_id']).to eq('foo')
32
+ end
33
+ end
34
+
35
+ it 'should consume a nil message' do
36
+ test_consume_message(MyConsumer, nil) do |payload, _metadata|
37
+ expect(payload).to be_nil
38
+ end
39
+ end
40
+
41
+ it 'should consume a message idempotently' do
42
+ # testing for a crash and re-consuming the same message/metadata
43
+ key = { 'test_id' => 'foo' }
44
+ test_metadata = { key: key }
45
+ allow_any_instance_of(MyConsumer).to(receive(:decode_key)) do |_instance, k|
46
+ k['test_id']
47
+ end
48
+ MyConsumer.new.around_consume({ 'test_id' => 'foo',
49
+ 'some_int' => 123 }, test_metadata) do |_payload, metadata|
50
+ expect(metadata[:key]).to eq('foo')
51
+ end
52
+ MyConsumer.new.around_consume({ 'test_id' => 'foo',
53
+ 'some_int' => 123 }, test_metadata) do |_payload, metadata|
54
+ expect(metadata[:key]).to eq('foo')
55
+ end
56
+ end
57
+
58
+ it 'should consume a message on a topic' do
59
+ test_consume_message('my_consume_topic',
60
+ 'test_id' => 'foo',
61
+ 'some_int' => 123) do |payload, _metadata|
62
+ expect(payload['test_id']).to eq('foo')
63
+ end
64
+ end
65
+
66
+ it 'should fail on invalid message' do
67
+ test_consume_invalid_message(MyConsumer, 'invalid' => 'key')
68
+ end
69
+
70
+ it 'should fail if reraise is false but fatal_error is true' do
71
+ Deimos.configure { |config| config.consumers.reraise_errors = false }
72
+ test_consume_invalid_message(MyConsumer, 'fatal')
73
+ end
74
+
75
+ it 'should fail if fatal_error is true globally' do
76
+ Deimos.configure do |config|
77
+ config.consumers.fatal_error = proc { true }
78
+ config.consumers.reraise_errors = false
79
+ end
80
+ test_consume_invalid_message(MyConsumer, 'invalid' => 'key')
81
+ end
82
+
83
+ it 'should fail on message with extra fields' do
84
+ test_consume_invalid_message(MyConsumer,
85
+ 'test_id' => 'foo',
86
+ 'some_int' => 123,
87
+ 'extra_field' => 'field name')
88
+ end
89
+
90
+ it 'should not fail when before_consume fails without reraising errors' do
91
+ Deimos.configure { |config| config.consumers.reraise_errors = false }
92
+ expect {
93
+ test_consume_message(
94
+ MyConsumer,
95
+ { 'test_id' => 'foo',
96
+ 'some_int' => 123 },
97
+ { skip_expectation: true }
98
+ ) { raise 'OH NOES' }
99
+ }.not_to raise_error
100
+ end
101
+
102
+ it 'should not fail when consume fails without reraising errors' do
103
+ Deimos.configure { |config| config.consumers.reraise_errors = false }
104
+ expect {
105
+ test_consume_message(
106
+ MyConsumer,
107
+ { 'invalid' => 'key' },
108
+ { skip_expectation: true }
109
+ )
110
+ }.not_to raise_error
111
+ end
112
+
113
+ it 'should call original' do
114
+ expect {
115
+ test_consume_message(MyConsumer,
116
+ { 'test_id' => 'foo', 'some_int' => 123 },
117
+ { call_original: true })
118
+ }.to raise_error('This should not be called unless call_original is set')
119
+ end
120
+
121
+ describe 'decode_key' do
122
+
123
+ it 'should use the key field in the value if set' do
124
+ # actual decoding is disabled in test
125
+ expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
126
+ expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
127
+ end
128
+
129
+ it 'should use the key schema if set' do
130
+ consumer_class = Class.new(described_class) do
131
+ schema 'MySchema'
132
+ namespace 'com.my-namespace'
133
+ key_config schema: 'MySchema_key'
134
+ end
135
+ stub_const('ConsumerTest::MySchemaConsumer', consumer_class)
136
+ expect(MyConsumer.new.decode_key('test_id' => '123')).to eq('123')
137
+ expect { MyConsumer.new.decode_key(123) }.to raise_error(NoMethodError)
138
+ end
139
+
140
+ it 'should not decode if plain is set' do
141
+ consumer_class = Class.new(described_class) do
142
+ schema 'MySchema'
143
+ namespace 'com.my-namespace'
144
+ key_config plain: true
145
+ end
146
+ stub_const('ConsumerTest::MyNonEncodedConsumer', consumer_class)
147
+ expect(MyNonEncodedConsumer.new.decode_key('123')).to eq('123')
148
+ end
149
+
150
+ it 'should error with nothing set' do
151
+ consumer_class = Class.new(described_class) do
152
+ schema 'MySchema'
153
+ namespace 'com.my-namespace'
154
+ end
155
+ stub_const('ConsumerTest::MyErrorConsumer', consumer_class)
156
+ expect { MyErrorConsumer.new.decode_key('123') }.
157
+ to raise_error('No key config given - if you are not decoding keys, please use `key_config plain: true`')
158
+ end
159
+
160
+ end
161
+
162
+ describe 'timestamps' do
163
+ before(:each) do
164
+ # :nodoc:
165
+ consumer_class = Class.new(described_class) do
166
+ schema 'MySchemaWithDateTimes'
167
+ namespace 'com.my-namespace'
168
+ key_config plain: true
169
+
170
+ # :nodoc:
171
+ def consume(_payload, _metadata)
172
+ raise 'This should not be called unless call_original is set'
173
+ end
174
+ end
175
+ stub_const('ConsumerTest::MyConsumer', consumer_class)
176
+ end
177
+
178
+ it 'should consume a message' do
179
+ expect(Deimos.config.metrics).to receive(:histogram).twice
180
+ test_consume_message('my_consume_topic',
181
+ 'test_id' => 'foo',
182
+ 'some_int' => 123,
183
+ 'updated_at' => Time.now.to_i,
184
+ 'timestamp' => 2.minutes.ago.to_s) do |payload, _metadata|
185
+ expect(payload['test_id']).to eq('foo')
186
+ end
187
+ end
188
+
189
+ it 'should fail nicely when timestamp wrong format' do
190
+ expect(Deimos.config.metrics).to receive(:histogram).twice
191
+ test_consume_message('my_consume_topic',
192
+ 'test_id' => 'foo',
193
+ 'some_int' => 123,
194
+ 'updated_at' => Time.now.to_i,
195
+ 'timestamp' => 'dffdf') do |payload, _metadata|
196
+ expect(payload['test_id']).to eq('foo')
197
+ end
198
+ test_consume_message('my_consume_topic',
199
+ 'test_id' => 'foo',
200
+ 'some_int' => 123,
201
+ 'updated_at' => Time.now.to_i,
202
+ 'timestamp' => '') do |payload, _metadata|
203
+ expect(payload['test_id']).to eq('foo')
204
+ end
205
+ end
206
+
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Deimos do
4
+
5
+ let(:phobos_configuration) do
6
+ { 'logger' =>
7
+ { 'file' => 'log/phobos.log',
8
+ 'stdout_json' => false,
9
+ 'level' => 'debug',
10
+ 'ruby_kafka' =>
11
+ { 'level' => 'debug' } },
12
+ 'kafka' =>
13
+ { 'client_id' => 'phobos',
14
+ 'connect_timeout' => 15,
15
+ 'socket_timeout' => 15,
16
+ 'seed_brokers' => 'my_seed_broker.com',
17
+ 'ssl_ca_cert' => 'my_ssl_ca_cert',
18
+ 'ssl_client_cert' => 'my_ssl_client_cert',
19
+ 'ssl_client_cert_key' => 'my_ssl_client_cert_key' },
20
+ 'producer' =>
21
+ { 'ack_timeout' => 5,
22
+ 'required_acks' => :all,
23
+ 'max_retries' => 2,
24
+ 'retry_backoff' => 1,
25
+ 'max_buffer_size' => 10_000,
26
+ 'max_buffer_bytesize' => 10_000_000,
27
+ 'compression_codec' => nil,
28
+ 'compression_threshold' => 1,
29
+ 'max_queue_size' => 10_000,
30
+ 'delivery_threshold' => 0,
31
+ 'delivery_interval' => 0 },
32
+ 'consumer' =>
33
+ { 'session_timeout' => 300,
34
+ 'offset_commit_interval' => 10,
35
+ 'offset_commit_threshold' => 0,
36
+ 'heartbeat_interval' => 10 },
37
+ 'backoff' =>
38
+ { 'min_ms' => 1000,
39
+ 'max_ms' => 60_000 },
40
+ 'listeners' => [
41
+ { 'handler' => 'ConsumerTest::MyConsumer',
42
+ 'topic' => 'my_consume_topic',
43
+ 'group_id' => 'my_group_id',
44
+ 'max_bytes_per_partition' => 524_288 },
45
+ { 'handler' => 'ConsumerTest::MyBatchConsumer',
46
+ 'topic' => 'my_batch_consume_topic',
47
+ 'group_id' => 'my_batch_group_id',
48
+ 'delivery' => 'inline_batch' }
49
+ ],
50
+ 'custom_logger' => nil,
51
+ 'custom_kafka_logger' => nil }
52
+ end
53
+
54
+ let(:config_path) { File.join(File.dirname(__FILE__), 'phobos.yml') }
55
+
56
+ it 'should have a version number' do
57
+ expect(Deimos::VERSION).not_to be_nil
58
+ end
59
+
60
+ it 'should error if required_acks is not all' do
61
+ expect {
62
+ described_class.configure do |config|
63
+ config.producers.backend = :db
64
+ config.phobos_config_file = File.join(File.dirname(__FILE__), 'phobos.bad_db.yml')
65
+ end
66
+ }.to raise_error('Cannot set producers.backend to :db unless producers.required_acks is set to ":all"!')
67
+ end
68
+
69
+ describe '#start_db_backend!' do
70
+ it 'should start if backend is db and thread_count is > 0' do
71
+ signal_handler = instance_double(Sigurd::SignalHandler)
72
+ allow(signal_handler).to receive(:run!)
73
+ expect(Sigurd::Executor).to receive(:new).
74
+ with(anything, sleep_seconds: 5, logger: anything).and_call_original
75
+ expect(Sigurd::SignalHandler).to receive(:new) do |executor|
76
+ expect(executor.runners.size).to eq(2)
77
+ signal_handler
78
+ end
79
+ described_class.configure do |config|
80
+ config.producers.backend = :db
81
+ end
82
+ described_class.start_db_backend!(thread_count: 2)
83
+ end
84
+
85
+ it 'should not start if backend is not db' do
86
+ expect(Sigurd::SignalHandler).not_to receive(:new)
87
+ described_class.configure do |config|
88
+ config.producers.backend = :kafka
89
+ end
90
+ expect { described_class.start_db_backend!(thread_count: 2) }.
91
+ to raise_error('Publish backend is not set to :db, exiting')
92
+ end
93
+
94
+ it 'should not start if thread_count is nil' do
95
+ expect(Sigurd::SignalHandler).not_to receive(:new)
96
+ described_class.configure do |config|
97
+ config.producers.backend = :db
98
+ end
99
+ expect { described_class.start_db_backend!(thread_count: nil) }.
100
+ to raise_error('Thread count is not given or set to zero, exiting')
101
+ end
102
+
103
+ it 'should not start if thread_count is 0' do
104
+ expect(Sigurd::SignalHandler).not_to receive(:new)
105
+ described_class.configure do |config|
106
+ config.producers.backend = :db
107
+ end
108
+ expect { described_class.start_db_backend!(thread_count: 0) }.
109
+ to raise_error('Thread count is not given or set to zero, exiting')
110
+ end
111
+ end
112
+
113
+ describe 'delivery configuration' do
114
+ before(:each) do
115
+ allow(YAML).to receive(:load).and_return(phobos_configuration)
116
+ end
117
+
118
+ it 'should not raise an error with properly configured handlers' do
119
+ expect {
120
+ described_class.configure do
121
+ consumer do
122
+ class_name 'ConsumerTest::MyConsumer'
123
+ delivery :message
124
+ end
125
+ consumer do
126
+ class_name 'ConsumerTest::MyConsumer'
127
+ delivery :batch
128
+ end
129
+ consumer do
130
+ class_name 'ConsumerTest::MyBatchConsumer'
131
+ delivery :inline_batch
132
+ end
133
+ end
134
+ }.not_to raise_error
135
+ end
136
+
137
+ it 'should raise an error if inline_batch listeners do not implement consume_batch' do
138
+ expect {
139
+ described_class.configure do
140
+ consumer do
141
+ class_name 'ConsumerTest::MyConsumer'
142
+ delivery :inline_batch
143
+ end
144
+ end
145
+ }.to raise_error('BatchConsumer ConsumerTest::MyConsumer does not implement `consume_batch`')
146
+ end
147
+
148
+ it 'should raise an error if Consumers do not have message or batch delivery' do
149
+ expect {
150
+ described_class.configure do
151
+ consumer do
152
+ class_name 'ConsumerTest::MyBatchConsumer'
153
+ delivery :message
154
+ end
155
+ end
156
+ }.to raise_error('Non-batch Consumer ConsumerTest::MyBatchConsumer does not implement `consume`')
157
+ end
158
+
159
+ it 'should treat nil as `batch`' do
160
+ expect {
161
+ described_class.configure do
162
+ consumer do
163
+ class_name 'ConsumerTest::MyConsumer'
164
+ end
165
+ end
166
+ }.not_to raise_error
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'generators/deimos/active_record_generator'
4
+
5
+ RSpec.describe Deimos::Generators::ActiveRecordGenerator do
6
+
7
+ after(:each) do
8
+ FileUtils.rm_rf('db') if File.exist?('db')
9
+ FileUtils.rm_rf('app') if File.exist?('app')
10
+ end
11
+
12
+ it 'should generate a migration' do
13
+ expect(Dir['db/migrate/*.rb']).to be_empty
14
+ expect(Dir['app/models/*.rb']).to be_empty
15
+ described_class.start(['generated_table', 'com.my-namespace.Generated'])
16
+ files = Dir['db/migrate/*.rb']
17
+ expect(files.length).to eq(1)
18
+ results = <<~MIGRATION
19
+ class CreateGeneratedTable < ActiveRecord::Migration[6.1]
20
+ def up
21
+ if table_exists?(:generated_table)
22
+ warn "generated_table already exists, exiting"
23
+ return
24
+ end
25
+ create_table :generated_table do |t|
26
+ t.string :a_string
27
+ t.integer :a_int
28
+ t.bigint :a_long
29
+ t.float :a_float
30
+ t.float :a_double
31
+ t.string :an_enum
32
+ t.json :an_array
33
+ t.json :a_map
34
+ t.json :a_record
35
+ end
36
+
37
+ # TODO add indexes as necessary
38
+ end
39
+
40
+ def down
41
+ return unless table_exists?(:generated_table)
42
+ drop_table :generated_table
43
+ end
44
+
45
+ end
46
+ MIGRATION
47
+ expect(File.read(files[0])).to eq(results)
48
+ model = <<~MODEL
49
+ class GeneratedTable < ApplicationRecord
50
+ enum an_enum: {sym1: 'sym1', sym2: 'sym2'}
51
+ end
52
+ MODEL
53
+ expect(File.read('app/models/generated_table.rb')).to eq(model)
54
+ end
55
+
56
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConsumerTest
4
+ # Mock consumer
5
+ class MyBatchConsumer < Deimos::Consumer
6
+ # :no-doc:
7
+ def consume_batch
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ConsumerTest
4
+ # Mock consumer
5
+ class MyConsumer < Deimos::Consumer
6
+ # :no-doc:
7
+ def consume
8
+ end
9
+ end
10
+ end