heller 0.0.3-java → 0.2.0-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +193 -0
- data/lib/heller/configuration.rb +41 -0
- data/lib/heller/consumer.rb +93 -57
- data/lib/heller/consumer_configuration.rb +38 -0
- data/lib/heller/errors.rb +9 -0
- data/lib/heller/fetch_request.rb +11 -0
- data/lib/heller/fetch_response.rb +33 -0
- data/lib/heller/message.rb +9 -0
- data/lib/heller/message_set_enumerator.rb +35 -0
- data/lib/heller/offset_request.rb +23 -0
- data/lib/heller/offset_response.rb +29 -0
- data/lib/heller/producer.rb +24 -38
- data/lib/heller/producer_configuration.rb +44 -0
- data/lib/heller/topic_metadata_response.rb +66 -0
- data/lib/heller/version.rb +5 -0
- data/lib/heller/zookeeper_consumer.rb +47 -0
- data/lib/heller.rb +21 -2
- data/lib/kafka.rb +50 -27
- data/spec/heller/consumer_configuration_spec.rb +196 -0
- data/spec/heller/consumer_spec.rb +376 -0
- data/spec/heller/fetch_response_spec.rb +93 -0
- data/spec/heller/message_set_enumerator_spec.rb +54 -0
- data/spec/heller/offset_response_spec.rb +68 -0
- data/spec/heller/producer_configuration_spec.rb +178 -0
- data/spec/heller/producer_spec.rb +65 -0
- data/spec/heller/topic_metadata_response_spec.rb +122 -0
- data/spec/heller/zookeeper_consumer_spec.rb +166 -0
- data/spec/integration/end_to_end_communication_spec.rb +316 -0
- data/spec/integration/zookeeper_consumer_spec.rb +85 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/support/fakers.rb +45 -0
- metadata +62 -27
@@ -0,0 +1,178 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Heller
|
6
|
+
describe ProducerConfiguration do
|
7
|
+
it 'has sane defaults for running locally' do
|
8
|
+
configuration = described_class.new
|
9
|
+
|
10
|
+
expect(configuration[:brokers]).to eq('localhost:9092')
|
11
|
+
expect(configuration[:serializer]).to eq('kafka.serializer.StringEncoder')
|
12
|
+
expect(configuration[:ack]).to eq(-1)
|
13
|
+
expect(configuration[:type]).to eq(:sync)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'given hash with user-defined options' do
|
17
|
+
context 'with Symbol keys' do
|
18
|
+
it 'merges them with the defaults' do
|
19
|
+
configuration = described_class.new({
|
20
|
+
brokers: 'localhost:9092,localhost:9093',
|
21
|
+
serializer: 'kafka.serializer.DefaultEncoder',
|
22
|
+
batch_size: 1500
|
23
|
+
})
|
24
|
+
|
25
|
+
expect(configuration[:brokers]).to eq('localhost:9092,localhost:9093')
|
26
|
+
expect(configuration[:serializer]).to eq('kafka.serializer.DefaultEncoder')
|
27
|
+
expect(configuration[:batch_size]).to eq(1500)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with String keys' do
|
32
|
+
it 'merges them with the defaults' do
|
33
|
+
configuration = described_class.new({
|
34
|
+
'brokers' => 'localhost:9092,localhost:9093',
|
35
|
+
'serializer' => 'kafka.serializer.DefaultEncoder',
|
36
|
+
'batch_size' => 1500
|
37
|
+
})
|
38
|
+
|
39
|
+
expect(configuration[:brokers]).to eq('localhost:9092,localhost:9093')
|
40
|
+
expect(configuration[:serializer]).to eq('kafka.serializer.DefaultEncoder')
|
41
|
+
expect(configuration[:batch_size]).to eq(1500)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context '#to_java' do
|
47
|
+
shared_examples_for 'a ProducerConfiguration' do
|
48
|
+
let :configuration do
|
49
|
+
described_class.new(options).to_java
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'returns an instance of Kafka::Producer::ProducerConfig' do
|
53
|
+
expect(configuration).to be_a(Kafka::Producer::ProducerConfig)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'sets #broker_list' do
|
57
|
+
expect(configuration.broker_list).to eq('localhost:9092,localhost:9093')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'sets #request_required_acks' do
|
61
|
+
expect(configuration.request_required_acks).to eq(-1)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'sets #producer_type' do
|
65
|
+
expect(configuration.producer_type).to eq('async')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'sets serializer_class' do
|
69
|
+
expect(configuration.serializer_class).to eq('kafka.serializer.StringEncoder')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'sets #key_serializer_class' do
|
73
|
+
expect(configuration.key_serializer_class).to eq('kafka.serializer.DefaultEncoder')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'sets #partitioner_class' do
|
77
|
+
expect(configuration.partitioner_class).to eq('kafka.producer.DefaultPartitioner')
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'sets #compression_codec' do
|
81
|
+
expect(configuration.compression_codec.name).to eq('gzip')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'sets #message_send_max_retries' do
|
85
|
+
expect(configuration.message_send_max_retries).to eq(5)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'sets #retry_backoff_ms' do
|
89
|
+
expect(configuration.retry_backoff_ms).to eq(1500)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'sets #topic_metadata_refresh_interval_ms' do
|
93
|
+
expect(configuration.topic_metadata_refresh_interval_ms).to eq(5000)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'sets #queue_buffering_max_ms' do
|
97
|
+
expect(configuration.queue_buffering_max_ms).to eq(1000 * 100)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'sets #queue_buffering_max_messages' do
|
101
|
+
expect(configuration.queue_buffering_max_messages).to eq(10000)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'sets #queue_enqueue_timeout_ms' do
|
105
|
+
expect(configuration.queue_enqueue_timeout_ms).to eq(1000)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'sets #batch_num_messages' do
|
109
|
+
expect(configuration.batch_num_messages).to eq(2000)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'sets #send_buffer_bytes' do
|
113
|
+
expect(configuration.send_buffer_bytes).to eq(1024 * 1000)
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'sets #client_id' do
|
117
|
+
expect(configuration.client_id).to eq('spec-client')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'sets #request_timeout_ms' do
|
121
|
+
expect(configuration.request_timeout_ms).to eq(10000)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'with Symbol keys' do
|
126
|
+
let :options do
|
127
|
+
{
|
128
|
+
brokers: 'localhost:9092,localhost:9093',
|
129
|
+
type: :async,
|
130
|
+
serializer: 'kafka.serializer.StringEncoder',
|
131
|
+
key_serializer: 'kafka.serializer.DefaultEncoder',
|
132
|
+
partitioner: 'kafka.producer.DefaultPartitioner',
|
133
|
+
compression: :gzip,
|
134
|
+
num_retries: 5,
|
135
|
+
retry_backoff: 1500,
|
136
|
+
metadata_refresh_interval: 5000,
|
137
|
+
batch_size: 2000,
|
138
|
+
client_id: 'spec-client',
|
139
|
+
request_timeout: 10000,
|
140
|
+
buffer_limit: 100 * 100,
|
141
|
+
buffer_timeout: 1000 * 100,
|
142
|
+
enqueue_timeout: 1000,
|
143
|
+
socket_buffer: 1024 * 1000,
|
144
|
+
ack: -1
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
it_behaves_like 'a ProducerConfiguration'
|
149
|
+
end
|
150
|
+
|
151
|
+
context 'with String keys' do
|
152
|
+
let :options do
|
153
|
+
{
|
154
|
+
'brokers' => 'localhost:9092,localhost:9093',
|
155
|
+
'type' => :async,
|
156
|
+
'serializer' => 'kafka.serializer.StringEncoder',
|
157
|
+
'key_serializer' => 'kafka.serializer.DefaultEncoder',
|
158
|
+
'partitioner' => 'kafka.producer.DefaultPartitioner',
|
159
|
+
'compression' => :gzip,
|
160
|
+
'num_retries' => 5,
|
161
|
+
'retry_backoff' => 1500,
|
162
|
+
'metadata_refresh_interval' => 5000,
|
163
|
+
'batch_size' => 2000,
|
164
|
+
'client_id' => 'spec-client',
|
165
|
+
'request_timeout' => 10000,
|
166
|
+
'buffer_limit' => 100 * 100,
|
167
|
+
'buffer_timeout' => 1000 * 100,
|
168
|
+
'enqueue_timeout' => 1000,
|
169
|
+
'socket_buffer' => 1024 * 1000,
|
170
|
+
'ack' => -1
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
174
|
+
it_behaves_like 'a ProducerConfiguration'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Heller
|
6
|
+
describe Producer do
|
7
|
+
let(:producer) do
|
8
|
+
described_class.new('localhost:9092', producer_impl: producer_impl)
|
9
|
+
end
|
10
|
+
|
11
|
+
let :producer_impl do
|
12
|
+
double(:producer_impl, new: producer_spy)
|
13
|
+
end
|
14
|
+
|
15
|
+
let :producer_spy do
|
16
|
+
double(:producer, send: nil, close: nil)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#new' do
|
20
|
+
it 'converts options to a Kafka::Producer::ProducerConfig object' do
|
21
|
+
described_class.new('localhost:9092,localhost:9093', type: :async, producer_impl: producer_impl)
|
22
|
+
|
23
|
+
expect(producer_impl).to have_received(:new).with(instance_of(Kafka::Producer::ProducerConfig))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#push' do
|
28
|
+
it 'wraps messages in a java.util.ArrayList' do
|
29
|
+
messages = [Heller::Message.new('topic', 'actual message', 'key!'), Heller::Message.new('topic2', 'payload')]
|
30
|
+
|
31
|
+
expect(producer_spy).to receive(:send) do |msgs|
|
32
|
+
expect(msgs).to be_a(java.util.ArrayList)
|
33
|
+
expect(msgs.to_a).to eq(messages)
|
34
|
+
end
|
35
|
+
|
36
|
+
producer.push(messages)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'allows sending a single message' do
|
40
|
+
message = Heller::Message.new('topic', 'actual message')
|
41
|
+
|
42
|
+
expect(producer_spy).to receive(:send) do |msgs|
|
43
|
+
expect(msgs.size).to eq(1)
|
44
|
+
expect(msgs.first).to eq(message)
|
45
|
+
end
|
46
|
+
|
47
|
+
producer.push(message)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe '#disconnect' do
|
52
|
+
it 'calls #close on the underlying producer' do
|
53
|
+
producer.disconnect
|
54
|
+
|
55
|
+
expect(producer_spy).to have_received(:close)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'is aliased to #close' do
|
59
|
+
producer.close
|
60
|
+
|
61
|
+
expect(producer_spy).to have_received(:close)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module Heller
|
6
|
+
describe TopicMetadataResponse do
|
7
|
+
let :response do
|
8
|
+
described_class.new(underlying)
|
9
|
+
end
|
10
|
+
|
11
|
+
let :underlying do
|
12
|
+
double(:topic_metadata_response, topics_metadata: [fake_topics_metadata])
|
13
|
+
end
|
14
|
+
|
15
|
+
let :fake_topics_metadata do
|
16
|
+
double(:topics_metadata)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#each' do
|
20
|
+
let :fake_partition_metadata do
|
21
|
+
double(:partition_metadata)
|
22
|
+
end
|
23
|
+
|
24
|
+
before do
|
25
|
+
allow(fake_topics_metadata).to receive(:topic).and_return('spec')
|
26
|
+
allow(fake_topics_metadata).to receive(:partitions_metadata).and_return([fake_partition_metadata])
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'yields topic and partition_metadata' do
|
30
|
+
yielded = []
|
31
|
+
response.each { |topic, meta| yielded << [topic, meta] }
|
32
|
+
expect(yielded.flatten).to eq(['spec', fake_partition_metadata])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#metadata' do
|
37
|
+
before do
|
38
|
+
allow(underlying).to receive(:topics_metadata)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'returns #topics_metadata' do
|
42
|
+
response.metadata
|
43
|
+
|
44
|
+
expect(underlying).to have_received(:topics_metadata).once
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#leader_for' do
|
49
|
+
context 'given a topic-partition combination that exists' do
|
50
|
+
let :fake_partition_metadata do
|
51
|
+
double(:partition_metadata)
|
52
|
+
end
|
53
|
+
|
54
|
+
before do
|
55
|
+
allow(fake_topics_metadata).to receive(:topic).and_return('spec')
|
56
|
+
allow(fake_topics_metadata).to receive(:partitions_metadata).and_return([fake_partition_metadata])
|
57
|
+
allow(fake_partition_metadata).to receive(:partition_id).and_return(0)
|
58
|
+
allow(fake_partition_metadata).to receive(:leader).and_return('a non-nil value')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'returns the leader' do
|
62
|
+
expect(response.leader_for('spec', 0)).not_to be_nil
|
63
|
+
|
64
|
+
expect(fake_partition_metadata).to have_received(:leader)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'caches the result' do
|
68
|
+
2.times { expect(response.leader_for('spec', 0)).not_to be_nil }
|
69
|
+
|
70
|
+
expect(fake_partition_metadata).to have_received(:leader).once
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'given a topic-partition combination that does not exist' do
|
75
|
+
before do
|
76
|
+
allow(fake_topics_metadata).to receive(:topic).and_return('not-spec')
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'raises NoSuchTopicPartitionCombinationError' do
|
80
|
+
expect { response.leader_for('non-existent', 1) }.to raise_error(NoSuchTopicPartitionCombinationError)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#isr_for' do
|
86
|
+
context 'given a topic-partition combination that exists' do
|
87
|
+
let :fake_partition_metadata do
|
88
|
+
double(:partition_metadata)
|
89
|
+
end
|
90
|
+
|
91
|
+
before do
|
92
|
+
allow(fake_topics_metadata).to receive(:topic).and_return('spec')
|
93
|
+
allow(fake_topics_metadata).to receive(:partitions_metadata).and_return([fake_partition_metadata])
|
94
|
+
allow(fake_partition_metadata).to receive(:partition_id).and_return(0)
|
95
|
+
allow(fake_partition_metadata).to receive(:isr).and_return(['a non-nil value'])
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'returns in sync replicas' do
|
99
|
+
expect(response.isr_for('spec', 0)).not_to be_nil
|
100
|
+
|
101
|
+
expect(fake_partition_metadata).to have_received(:isr)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'caches the result' do
|
105
|
+
2.times { expect(response.isr_for('spec', 0)).not_to be_nil }
|
106
|
+
|
107
|
+
expect(fake_partition_metadata).to have_received(:isr).once
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'given a topic-partition combination that does not exist' do
|
112
|
+
before do
|
113
|
+
allow(fake_topics_metadata).to receive(:topic).and_return('not-spec')
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'raises NoSuchTopicPartitionCombinationError' do
|
117
|
+
expect { response.isr_for('non-existent', 1) }.to raise_error(NoSuchTopicPartitionCombinationError)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
|
6
|
+
module Heller
|
7
|
+
describe ZookeeperConsumer do
|
8
|
+
let :consumer do
|
9
|
+
described_class.new('localhost:2181', options, consumer_impl)
|
10
|
+
end
|
11
|
+
|
12
|
+
let :options do
|
13
|
+
{
|
14
|
+
group_id: 'test',
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let :consumer_impl do
|
19
|
+
double(:consumer_impl)
|
20
|
+
end
|
21
|
+
|
22
|
+
let :values do
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
|
26
|
+
before do
|
27
|
+
allow(consumer_impl).to receive(:createJavaConsumerConnector).and_return(consumer_impl)
|
28
|
+
allow(consumer_impl).to receive(:create_message_streams) do |hash, *args|
|
29
|
+
values.concat(hash.values)
|
30
|
+
end
|
31
|
+
allow(consumer_impl).to receive(:create_message_streams_by_filter)
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#initialize' do
|
35
|
+
it 'creates a JavaConsumerConnector' do
|
36
|
+
described_class.new('localhost:2181', options, consumer_impl)
|
37
|
+
|
38
|
+
expect(consumer_impl).to have_received(:createJavaConsumerConnector)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'includes ZooKeeper hosts in configuration' do
|
42
|
+
allow(consumer_impl).to receive(:createJavaConsumerConnector) do |config|
|
43
|
+
expect(config.zk_connect).to eq('localhost:2181')
|
44
|
+
end
|
45
|
+
|
46
|
+
described_class.new('localhost:2181', options, consumer_impl)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#create_streams' do
|
51
|
+
context 'when given :key_decoder and :value_decoder' do
|
52
|
+
let :key_decoder do
|
53
|
+
double(:key_decoder)
|
54
|
+
end
|
55
|
+
|
56
|
+
let :value_decoder do
|
57
|
+
double(:value_decoder)
|
58
|
+
end
|
59
|
+
|
60
|
+
before do
|
61
|
+
consumer.create_streams({'topic1' => 2}, key_decoder: key_decoder, value_decoder: value_decoder)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'creates message streams with given key decoder' do
|
65
|
+
expect(consumer_impl).to have_received(:create_message_streams).with(anything, key_decoder, anything)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'creates message streams with given value decoder' do
|
69
|
+
expect(consumer_impl).to have_received(:create_message_streams).with(anything, anything, value_decoder)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'converts longs to integers' do
|
73
|
+
values.each do |value|
|
74
|
+
expect(value).to be_a(java.lang.Integer)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when not given any options' do
|
80
|
+
before do
|
81
|
+
consumer.create_streams({'topic1' => 2})
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'creates message streams' do
|
85
|
+
expect(consumer_impl).to have_received(:create_message_streams)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'converts longs to integers' do
|
89
|
+
values.each do |value|
|
90
|
+
expect(value).to be_a(java.lang.Integer)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#create_streams_by_filter' do
|
97
|
+
let :key_decoder do
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
let :value_decoder do
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
before do
|
106
|
+
consumer.create_streams_by_filter('hello-world', 1, key_decoder: key_decoder, value_decoder: value_decoder)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'creates message streams' do
|
110
|
+
expect(consumer_impl).to have_received(:create_message_streams_by_filter)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'creates a Whitelist object from given filter' do
|
114
|
+
expect(consumer_impl).to have_received(:create_message_streams_by_filter).with(instance_of(Kafka::Consumer::Whitelist), 1)
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when given :key_decoder and :value_decoder' do
|
118
|
+
let :key_decoder do
|
119
|
+
double(:key_decoder)
|
120
|
+
end
|
121
|
+
|
122
|
+
let :value_decoder do
|
123
|
+
double(:value_decoder)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'creates message streams with given key decoder' do
|
127
|
+
expect(consumer_impl).to have_received(:create_message_streams_by_filter).with(anything, 1, key_decoder, anything)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'creates message streams with given value decoder' do
|
131
|
+
expect(consumer_impl).to have_received(:create_message_streams_by_filter).with(anything, 1, anything, value_decoder)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#commit' do
|
137
|
+
before do
|
138
|
+
allow(consumer_impl).to receive(:commit_offsets)
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'calls #commit_offsets' do
|
142
|
+
consumer.commit
|
143
|
+
|
144
|
+
expect(consumer_impl).to have_received(:commit_offsets)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#close' do
|
149
|
+
before do
|
150
|
+
allow(consumer_impl).to receive(:shutdown)
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'calls #shutdown' do
|
154
|
+
consumer.close
|
155
|
+
|
156
|
+
expect(consumer_impl).to have_received(:shutdown)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'is aliased as #shutdown' do
|
160
|
+
consumer.shutdown
|
161
|
+
|
162
|
+
expect(consumer_impl).to have_received(:shutdown)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|