deimos-ruby 1.6.1 → 1.8.0.pre.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +9 -0
- data/.rubocop.yml +15 -13
- data/.ruby-version +1 -1
- data/CHANGELOG.md +30 -0
- data/Gemfile.lock +87 -80
- data/README.md +139 -15
- data/Rakefile +1 -1
- data/deimos-ruby.gemspec +3 -2
- data/docs/ARCHITECTURE.md +144 -0
- data/docs/CONFIGURATION.md +27 -0
- data/lib/deimos.rb +7 -6
- data/lib/deimos/active_record_consume/batch_consumption.rb +159 -0
- data/lib/deimos/active_record_consume/batch_slicer.rb +27 -0
- data/lib/deimos/active_record_consume/message_consumption.rb +58 -0
- data/lib/deimos/active_record_consume/schema_model_converter.rb +52 -0
- data/lib/deimos/active_record_consumer.rb +33 -75
- data/lib/deimos/active_record_producer.rb +23 -0
- data/lib/deimos/batch_consumer.rb +2 -140
- data/lib/deimos/config/configuration.rb +28 -10
- data/lib/deimos/consume/batch_consumption.rb +148 -0
- data/lib/deimos/consume/message_consumption.rb +93 -0
- data/lib/deimos/consumer.rb +79 -69
- data/lib/deimos/kafka_message.rb +1 -1
- data/lib/deimos/kafka_source.rb +29 -23
- data/lib/deimos/kafka_topic_info.rb +1 -1
- data/lib/deimos/message.rb +6 -1
- data/lib/deimos/metrics/provider.rb +0 -2
- data/lib/deimos/poll_info.rb +9 -0
- data/lib/deimos/tracing/provider.rb +0 -2
- data/lib/deimos/utils/db_poller.rb +149 -0
- data/lib/deimos/utils/db_producer.rb +8 -3
- data/lib/deimos/utils/deadlock_retry.rb +68 -0
- data/lib/deimos/utils/lag_reporter.rb +19 -26
- data/lib/deimos/version.rb +1 -1
- data/lib/generators/deimos/db_poller/templates/migration +11 -0
- data/lib/generators/deimos/db_poller/templates/rails3_migration +16 -0
- data/lib/generators/deimos/db_poller_generator.rb +48 -0
- data/lib/tasks/deimos.rake +7 -0
- data/spec/active_record_batch_consumer_spec.rb +481 -0
- data/spec/active_record_consume/batch_slicer_spec.rb +42 -0
- data/spec/active_record_consume/schema_model_converter_spec.rb +105 -0
- data/spec/active_record_consumer_spec.rb +22 -11
- data/spec/active_record_producer_spec.rb +66 -88
- data/spec/batch_consumer_spec.rb +23 -7
- data/spec/config/configuration_spec.rb +4 -0
- data/spec/consumer_spec.rb +8 -8
- data/spec/deimos_spec.rb +57 -49
- data/spec/handlers/my_batch_consumer.rb +6 -1
- data/spec/handlers/my_consumer.rb +6 -1
- data/spec/kafka_source_spec.rb +53 -0
- data/spec/message_spec.rb +19 -0
- data/spec/producer_spec.rb +3 -3
- data/spec/rake_spec.rb +1 -1
- data/spec/schemas/com/my-namespace/MySchemaCompound-key.avsc +18 -0
- data/spec/schemas/com/my-namespace/Wibble.avsc +43 -0
- data/spec/spec_helper.rb +61 -6
- data/spec/utils/db_poller_spec.rb +320 -0
- data/spec/utils/deadlock_retry_spec.rb +74 -0
- data/spec/utils/lag_reporter_spec.rb +29 -22
- metadata +61 -20
- data/lib/deimos/base_consumer.rb +0 -104
- data/lib/deimos/utils/executor.rb +0 -124
- data/lib/deimos/utils/platform_schema_validation.rb +0 -0
- data/lib/deimos/utils/signal_handler.rb +0 -68
- data/spec/utils/executor_spec.rb +0 -53
- data/spec/utils/signal_handler_spec.rb +0 -16
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Deimos::ActiveRecordConsume::BatchSlicer do
|
4
|
+
describe '#slice' do
|
5
|
+
let(:batch) do
|
6
|
+
[
|
7
|
+
Deimos::Message.new({ v: 1 }, nil, key: 'C'),
|
8
|
+
Deimos::Message.new({ v: 123 }, nil, key: 'A'),
|
9
|
+
Deimos::Message.new({ v: 999 }, nil, key: 'B'),
|
10
|
+
Deimos::Message.new({ v: 456 }, nil, key: 'A'),
|
11
|
+
Deimos::Message.new({ v: 2 }, nil, key: 'C'),
|
12
|
+
Deimos::Message.new({ v: 3 }, nil, key: 'C')
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should slice a batch by key' do
|
17
|
+
slices = described_class.slice(batch)
|
18
|
+
|
19
|
+
expect(slices).
|
20
|
+
to match([
|
21
|
+
match_array([
|
22
|
+
Deimos::Message.new({ v: 1 }, nil, key: 'C'),
|
23
|
+
Deimos::Message.new({ v: 123 }, nil, key: 'A'),
|
24
|
+
Deimos::Message.new({ v: 999 }, nil, key: 'B')
|
25
|
+
]),
|
26
|
+
match_array([
|
27
|
+
Deimos::Message.new({ v: 456 }, nil, key: 'A'),
|
28
|
+
Deimos::Message.new({ v: 2 }, nil, key: 'C')
|
29
|
+
]),
|
30
|
+
match_array([
|
31
|
+
Deimos::Message.new({ v: 3 }, nil, key: 'C')
|
32
|
+
])
|
33
|
+
])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should handle empty batches' do
|
37
|
+
slices = described_class.slice([])
|
38
|
+
|
39
|
+
expect(slices).to be_empty
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos/active_record_consume/schema_model_converter'
|
4
|
+
require 'deimos/schema_backends/avro_local'
|
5
|
+
|
6
|
+
# Wrapped in a module to prevent class leakage
|
7
|
+
module SchemaModelConverterTest
|
8
|
+
describe Deimos::ActiveRecordConsume::SchemaModelConverter do
|
9
|
+
# Create ActiveRecord table and model
|
10
|
+
before(:all) do
|
11
|
+
ActiveRecord::Base.connection.create_table(:wibbles, force: true) do |t|
|
12
|
+
t.integer(:wibble_id)
|
13
|
+
t.string(:name)
|
14
|
+
t.integer(:bar)
|
15
|
+
t.datetime(:birthday_int)
|
16
|
+
t.datetime(:birthday_long)
|
17
|
+
t.datetime(:birthday_optional)
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
|
21
|
+
# :nodoc:
|
22
|
+
class Wibble < ActiveRecord::Base
|
23
|
+
end
|
24
|
+
Wibble.reset_column_information
|
25
|
+
end
|
26
|
+
|
27
|
+
after(:all) do
|
28
|
+
ActiveRecord::Base.connection.drop_table(:wibbles)
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:schema) { Deimos::SchemaBackends::AvroLocal.new(schema: 'Wibble', namespace: 'com.my-namespace') }
|
32
|
+
let(:inst) { described_class.new(schema, Wibble) }
|
33
|
+
|
34
|
+
describe '#convert' do
|
35
|
+
it 'should extract attributes from the payload' do
|
36
|
+
payload = { 'id' => 123, 'wibble_id' => 456, 'name' => 'wibble' }
|
37
|
+
|
38
|
+
expect(inst.convert(payload)).to include('id' => 123, 'wibble_id' => 456, 'name' => 'wibble')
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should ignore payload fields that don\'t exist' do
|
42
|
+
payload = { 'foo' => 'abc' }
|
43
|
+
|
44
|
+
expect(inst.convert(payload)).not_to include('foo')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should ignore fields in the schema but not in the model' do
|
48
|
+
payload = { 'floop' => 'def' }
|
49
|
+
|
50
|
+
expect(inst.convert(payload)).not_to include('floop')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should ignore model fields not in the schema' do
|
54
|
+
payload = { 'bar' => 'xyz' }
|
55
|
+
|
56
|
+
expect(inst.convert(payload)).not_to include('bar')
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should handle nils' do
|
60
|
+
payload = { 'name' => nil }
|
61
|
+
|
62
|
+
expect(inst.convert(payload)['name']).to be_nil
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'timestamps' do
|
66
|
+
it 'should ignore AR timestamp fields' do
|
67
|
+
payload = { 'updated_at' => '1234567890', 'created_at' => '2345678901' }
|
68
|
+
|
69
|
+
expect(inst.convert(payload)).not_to include('updated_at', 'created_at')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should parse timestamps' do
|
73
|
+
first = Time.zone.local(2019, 1, 1, 11, 12, 13)
|
74
|
+
second = Time.zone.local(2019, 2, 2, 12, 13, 14)
|
75
|
+
|
76
|
+
payload = { 'birthday_int' => first.to_i, 'birthday_long' => second.to_i }
|
77
|
+
|
78
|
+
expect(inst.convert(payload)).to include('birthday_int' => first, 'birthday_long' => second)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should parse integer-string timestamps' do
|
82
|
+
date = Time.zone.local(2019, 1, 1, 11, 12, 13)
|
83
|
+
|
84
|
+
payload = { 'birthday_int' => '1546359133' }
|
85
|
+
|
86
|
+
expect(inst.convert(payload)).to include('birthday_int' => date)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should ignore other strings for timestamps' do
|
90
|
+
payload = { 'birthday_int' => 'some-other-val' }
|
91
|
+
|
92
|
+
expect(inst.convert(payload)).to include('birthday_int' => 'some-other-val')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should coerce nullable unions' do
|
97
|
+
date = Time.zone.local(2019, 1, 1, 11, 12, 13)
|
98
|
+
|
99
|
+
payload = { 'birthday_optional' => date.to_i }
|
100
|
+
|
101
|
+
expect(inst.convert(payload)).to include('birthday_optional' => date)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'date'
|
4
4
|
|
5
|
-
#
|
6
|
-
module
|
7
|
-
describe Deimos::ActiveRecordConsumer do
|
5
|
+
# Wrapped in a module to prevent class leakage
|
6
|
+
module ActiveRecordConsumerTest
|
7
|
+
describe Deimos::ActiveRecordConsumer, 'Message Consumer' do
|
8
8
|
|
9
9
|
before(:all) do
|
10
10
|
ActiveRecord::Base.connection.create_table(:widgets, force: true) do |t|
|
@@ -22,6 +22,10 @@ module ActiveRecordProducerTest
|
|
22
22
|
Widget.reset_column_information
|
23
23
|
end
|
24
24
|
|
25
|
+
before(:each) do
|
26
|
+
Widget.delete_all
|
27
|
+
end
|
28
|
+
|
25
29
|
after(:all) do
|
26
30
|
ActiveRecord::Base.connection.drop_table(:widgets)
|
27
31
|
end
|
@@ -101,6 +105,21 @@ module ActiveRecordProducerTest
|
|
101
105
|
|
102
106
|
end
|
103
107
|
|
108
|
+
it 'should update only updated_at' do
|
109
|
+
travel_to Time.local(2020, 5, 5, 5, 5, 5)
|
110
|
+
widget1 = Widget.create!(test_id: 'id1', some_int: 3)
|
111
|
+
expect(widget1.updated_at.in_time_zone).to eq(Time.local(2020, 5, 5, 5, 5, 5))
|
112
|
+
|
113
|
+
travel 1.day
|
114
|
+
test_consume_message(MyCustomFetchConsumer, {
|
115
|
+
test_id: 'id1',
|
116
|
+
some_int: 3
|
117
|
+
}, { call_original: true })
|
118
|
+
expect(widget1.reload.updated_at.in_time_zone).
|
119
|
+
to eq(Time.local(2020, 5, 6, 5, 5, 5))
|
120
|
+
travel_back
|
121
|
+
end
|
122
|
+
|
104
123
|
it 'should find widgets by custom logic' do
|
105
124
|
widget1 = Widget.create!(test_id: 'id1')
|
106
125
|
expect(widget1.some_int).to be_nil
|
@@ -118,13 +137,5 @@ module ActiveRecordProducerTest
|
|
118
137
|
expect(Widget.find_by_test_id('id1').some_int).to eq(3)
|
119
138
|
expect(Widget.find_by_test_id('id2').some_int).to eq(4)
|
120
139
|
end
|
121
|
-
|
122
|
-
it 'should coerce int values to datetimes' do
|
123
|
-
column = Widget.columns.find { |c| c.name == 'some_datetime_int' }
|
124
|
-
expect(MyConsumer.new.send(:_coerce_field, column, 1_579_046_400)).to eq('2020-01-14 19:00:00 -0500')
|
125
|
-
expect(MyConsumer.new.send(:_coerce_field, column, '1579046400')).to eq('2020-01-14 19:00:00 -0500')
|
126
|
-
expect(MyConsumer.new.send(:_coerce_field, column, 'some-other-val')).to eq('some-other-val')
|
127
|
-
end
|
128
|
-
|
129
140
|
end
|
130
141
|
end
|
@@ -1,107 +1,85 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
module ActiveRecordProducerTest
|
5
|
-
describe Deimos::ActiveRecordProducer do
|
3
|
+
describe Deimos::ActiveRecordProducer do
|
6
4
|
|
7
|
-
|
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
|
5
|
+
include_context 'with widgets'
|
14
6
|
|
15
|
-
|
16
|
-
class Widget < ActiveRecord::Base
|
17
|
-
# @return [String]
|
18
|
-
def generated_id
|
19
|
-
'generated_id'
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
7
|
+
prepend_before(:each) do
|
23
8
|
|
24
|
-
|
25
|
-
|
9
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
10
|
+
schema 'MySchema'
|
11
|
+
namespace 'com.my-namespace'
|
12
|
+
topic 'my-topic'
|
13
|
+
key_config none: true
|
26
14
|
end
|
15
|
+
stub_const('MyProducer', producer_class)
|
27
16
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
17
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
18
|
+
schema 'MySchemaWithBooleans'
|
19
|
+
namespace 'com.my-namespace'
|
20
|
+
topic 'my-topic-with-boolean'
|
21
|
+
key_config none: true
|
22
|
+
end
|
23
|
+
stub_const('MyBooleanProducer', producer_class)
|
52
24
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
25
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
26
|
+
schema 'MySchemaWithId'
|
27
|
+
namespace 'com.my-namespace'
|
28
|
+
topic 'my-topic-with-id'
|
29
|
+
key_config none: true
|
30
|
+
record_class Widget
|
57
31
|
|
32
|
+
# :nodoc:
|
33
|
+
def self.generate_payload(attrs, widget)
|
34
|
+
super.merge(message_id: widget.generated_id)
|
58
35
|
end
|
59
|
-
stub_const('MyProducerWithID', producer_class)
|
60
36
|
|
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
37
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
38
|
+
stub_const('MyProducerWithID', producer_class)
|
39
|
+
|
40
|
+
producer_class = Class.new(Deimos::ActiveRecordProducer) do
|
41
|
+
schema 'MySchemaWithUniqueId'
|
42
|
+
namespace 'com.my-namespace'
|
43
|
+
topic 'my-topic-with-unique-id'
|
44
|
+
key_config field: :id
|
45
|
+
record_class Widget
|
74
46
|
end
|
47
|
+
stub_const('MyProducerWithUniqueID', producer_class)
|
48
|
+
end
|
75
49
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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
|
50
|
+
it 'should send events correctly' do
|
51
|
+
MyProducer.send_event(Widget.new(test_id: 'abc', some_int: 3))
|
52
|
+
expect('my-topic').to have_sent(test_id: 'abc', some_int: 3)
|
53
|
+
end
|
90
54
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
55
|
+
it 'should coerce values' do
|
56
|
+
MyProducer.send_event(Widget.new(test_id: 'abc', some_int: '3'))
|
57
|
+
MyProducer.send_event(Widget.new(test_id: 'abc', some_int: 4.5))
|
58
|
+
expect('my-topic').to have_sent(test_id: 'abc', some_int: 3)
|
59
|
+
expect('my-topic').to have_sent(test_id: 'abc', some_int: 4)
|
60
|
+
expect {
|
61
|
+
MyProducer.send_event(Widget.new(test_id: 'abc', some_int: nil))
|
62
|
+
}.to raise_error(Avro::SchemaValidator::ValidationError)
|
63
|
+
|
64
|
+
MyBooleanProducer.send_event(Widget.new(test_id: 'abc', some_bool: nil))
|
65
|
+
MyBooleanProducer.send_event(Widget.new(test_id: 'abc', some_bool: true))
|
66
|
+
expect('my-topic-with-boolean').to have_sent(test_id: 'abc', some_bool: false)
|
67
|
+
expect('my-topic-with-boolean').to have_sent(test_id: 'abc', some_bool: true)
|
68
|
+
end
|
101
69
|
|
102
|
-
|
103
|
-
|
104
|
-
|
70
|
+
it 'should be able to call the record' do
|
71
|
+
widget = Widget.create!(test_id: 'abc2', some_int: 3)
|
72
|
+
MyProducerWithID.send_event(id: widget.id, test_id: 'abc2', some_int: 3)
|
73
|
+
expect('my-topic-with-id').to have_sent(
|
74
|
+
test_id: 'abc2',
|
75
|
+
some_int: 3,
|
76
|
+
message_id: 'generated_id',
|
77
|
+
timestamp: anything
|
78
|
+
)
|
79
|
+
end
|
105
80
|
|
81
|
+
specify '#watched_attributes' do
|
82
|
+
expect(MyProducer.watched_attributes).to eq(%w(test_id some_int))
|
106
83
|
end
|
84
|
+
|
107
85
|
end
|
data/spec/batch_consumer_spec.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'deimos/batch_consumer'
|
4
|
-
|
5
3
|
# :nodoc:
|
6
4
|
module ConsumerTest
|
7
|
-
describe Deimos::
|
5
|
+
describe Deimos::Consumer, 'Batch Consumer' do
|
8
6
|
|
9
7
|
prepend_before(:each) do
|
10
8
|
# :nodoc:
|
11
|
-
consumer_class = Class.new(
|
9
|
+
consumer_class = Class.new(described_class) do
|
12
10
|
schema 'MySchema'
|
13
11
|
namespace 'com.my-namespace'
|
14
12
|
key_config field: 'test_id'
|
@@ -32,6 +30,24 @@ module ConsumerTest
|
|
32
30
|
batch.concat([{ 'invalid' => 'key' }])
|
33
31
|
end
|
34
32
|
|
33
|
+
it 'should provide backwards compatibility for BatchConsumer class' do
|
34
|
+
consumer_class = Class.new(Deimos::BatchConsumer) do
|
35
|
+
schema 'MySchema'
|
36
|
+
namespace 'com.my-namespace'
|
37
|
+
key_config field: 'test_id'
|
38
|
+
|
39
|
+
# :nodoc:
|
40
|
+
def consume_batch(_payloads, _metadata)
|
41
|
+
raise 'This should not be called unless call_original is set'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
stub_const('ConsumerTest::MyOldBatchConsumer', consumer_class)
|
45
|
+
|
46
|
+
test_consume_batch(MyOldBatchConsumer, batch) do |received, _metadata|
|
47
|
+
expect(received).to eq(batch)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
35
51
|
it 'should consume a batch of messages' do
|
36
52
|
test_consume_batch(MyBatchConsumer, batch) do |received, _metadata|
|
37
53
|
expect(received).to eq(batch)
|
@@ -99,7 +115,7 @@ module ConsumerTest
|
|
99
115
|
end
|
100
116
|
|
101
117
|
it 'should decode plain keys for all messages in the batch' do
|
102
|
-
consumer_class = Class.new(
|
118
|
+
consumer_class = Class.new(described_class) do
|
103
119
|
schema 'MySchema'
|
104
120
|
namespace 'com.my-namespace'
|
105
121
|
key_config plain: true
|
@@ -115,7 +131,7 @@ module ConsumerTest
|
|
115
131
|
describe 'timestamps' do
|
116
132
|
before(:each) do
|
117
133
|
# :nodoc:
|
118
|
-
consumer_class = Class.new(
|
134
|
+
consumer_class = Class.new(described_class) do
|
119
135
|
schema 'MySchemaWithDateTimes'
|
120
136
|
namespace 'com.my-namespace'
|
121
137
|
key_config plain: true
|
@@ -197,7 +213,7 @@ module ConsumerTest
|
|
197
213
|
describe 'logging' do
|
198
214
|
before(:each) do
|
199
215
|
# :nodoc:
|
200
|
-
consumer_class = Class.new(
|
216
|
+
consumer_class = Class.new(described_class) do
|
201
217
|
schema 'MySchemaWithUniqueId'
|
202
218
|
namespace 'com.my-namespace'
|
203
219
|
key_config plain: true
|