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.
@@ -0,0 +1,316 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe 'End-to-end communication' do
7
+ let :producer do
8
+ Heller::Producer.new('localhost:9092', producer_options)
9
+ end
10
+
11
+ let :consumer do
12
+ Heller::Consumer.new('localhost:9092', client_id: 'spec-consumer')
13
+ end
14
+
15
+ let :producer_options do
16
+ {
17
+ client_id: 'spec-producer',
18
+ batch_size: 1,
19
+ num_retries: 10,
20
+ retry_backoff: 1000,
21
+ }
22
+ end
23
+
24
+ after do
25
+ producer.close
26
+ consumer.close
27
+ end
28
+
29
+ context 'Producer' do
30
+ context 'without an explicit key' do
31
+ let :topic do
32
+ "spec-without-explicit-key-#{Time.now.to_i.to_s(36)}"
33
+ end
34
+
35
+ it 'is able to push messages' do
36
+ expect { producer.push(Heller::Message.new(topic, 'simple string message')) }.not_to raise_error
37
+ end
38
+ end
39
+
40
+ context 'with an explicit key' do
41
+ let :topic do
42
+ "spec-with-explicit-key-#{Time.now.to_i.to_s(36)}"
43
+ end
44
+
45
+ it 'is able to push messages' do
46
+ expect { producer.push(Heller::Message.new(topic, 'simple string message', 'some-key')) }.not_to raise_error
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'Consumer' do
52
+ describe '#fetch' do
53
+ let :fetch_response do
54
+ consumer.fetch(Heller::FetchRequest.new(topic, 0, 0))
55
+ end
56
+
57
+ let :enumerator do
58
+ fetch_response.messages(topic, 0)
59
+ end
60
+
61
+ context 'simple string messages' do
62
+ let :topic do
63
+ "spec-simple-string-#{Time.now.to_i.to_s(36)}"
64
+ end
65
+
66
+ before do
67
+ producer.push(Heller::Message.new(topic, 'simple string message'))
68
+ end
69
+
70
+ it 'is no big deal' do
71
+ expect(enumerator).to be_a(Heller::MessageSetEnumerator)
72
+
73
+ messages = enumerator.to_a
74
+ expect(messages.size).to eq(1)
75
+
76
+ offset, message = messages.last
77
+ expect(offset).to be_zero
78
+ expect(message).to eq('simple string message')
79
+ end
80
+ end
81
+
82
+ context 'JSON serialized hashes' do
83
+ let :topic do
84
+ "spec-json-hash-#{Time.now.to_i.to_s(36)}"
85
+ end
86
+
87
+ before do
88
+ producer.push(Heller::Message.new(topic, {'a key' => 'a value'}.to_json))
89
+ end
90
+
91
+ it 'is no big deal' do
92
+ expect(enumerator).to be_a(Heller::MessageSetEnumerator)
93
+
94
+ messages = enumerator.to_a
95
+ expect(messages.size).to eq(1)
96
+
97
+ offset, message = messages.last
98
+ expect(offset).to be_zero
99
+ expect(JSON.parse(message)).to eq({'a key' => 'a value'})
100
+ end
101
+ end
102
+
103
+ context 'with Snappy compression' do
104
+ let :producer_options do
105
+ super.merge({
106
+ client_id: 'spec-producer-snappy',
107
+ compression: :snappy,
108
+ })
109
+ end
110
+
111
+ context 'simple string messages' do
112
+ let :topic do
113
+ "spec-snappy-simple-string-#{Time.now.to_i.to_s(36)}"
114
+ end
115
+
116
+ before do
117
+ producer.push(Heller::Message.new(topic, 'simple string message'))
118
+ end
119
+
120
+ it 'is no big deal' do
121
+ expect(enumerator).to be_a(Heller::MessageSetEnumerator)
122
+
123
+ messages = enumerator.to_a
124
+ expect(messages.size).to eq(1)
125
+
126
+ offset, message = messages.last
127
+ expect(offset).to be_zero
128
+ expect(message).to eq('simple string message')
129
+ end
130
+ end
131
+
132
+ context 'JSON serialized hashes' do
133
+ let :topic do
134
+ "spec-snappy-json-hash-#{Time.now.to_i.to_s(36)}"
135
+ end
136
+
137
+ before do
138
+ producer.push(Heller::Message.new(topic, {'a key' => 'a value'}.to_json))
139
+ end
140
+
141
+ it 'is no big deal' do
142
+ expect(enumerator).to be_a(Heller::MessageSetEnumerator)
143
+
144
+ messages = enumerator.to_a
145
+ expect(messages.size).to eq(1)
146
+
147
+ offset, message = messages.last
148
+ expect(offset).to be_zero
149
+ expect(JSON.parse(message)).to eq({'a key' => 'a value'})
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ describe '#metadata' do
156
+ before do
157
+ topics.each { |topic| producer.push(Heller::Message.new(topic, 'metadata request message')) }
158
+ end
159
+
160
+ context 'when given a single topic' do
161
+ let :topics do
162
+ ["spec-single-metadata-topic-#{Time.now.to_i.to_s(36)}"]
163
+ end
164
+
165
+ it 'returns metadata about given topic' do
166
+ response = consumer.metadata(topics)
167
+ metadata = response.metadata
168
+
169
+ expect(metadata.size).to eq(1)
170
+
171
+ topic_metadata = metadata.first
172
+ expect(topic_metadata.topic).to eq(topics.first)
173
+ end
174
+ end
175
+
176
+ context 'when given several topics' do
177
+ let :topics do
178
+ [1, 2, 3].map { |i| "spec-multiple-metadata-topics-#{i}-#{Time.now.to_i.to_s(36)}" }
179
+ end
180
+
181
+ it 'returns metadata about given topics' do
182
+ response = consumer.metadata(topics)
183
+ metadata = response.metadata
184
+
185
+ expect(metadata.size).to eq(3)
186
+
187
+ topics.zip(metadata).each do |topic, metadata|
188
+ expect(metadata.topic).to eq(topic)
189
+ end
190
+ end
191
+ end
192
+
193
+ describe '#leader_for' do
194
+ let :topics do
195
+ [1, 2, 3].map { |i| "spec-metadata-leader-for-#{i}-#{Time.now.to_i.to_s(36)}" }
196
+ end
197
+
198
+ let :response do
199
+ consumer.metadata(topics)
200
+ end
201
+
202
+ context 'for existing topic-partition combinations' do
203
+ it 'returns the correct leader for each topic-partition combination' do
204
+ topics.each do |topic|
205
+ leader = response.leader_for(topic, 0)
206
+
207
+ expect(leader.connection_string).to match(/[a-z0-9\-\.]+:9092/i)
208
+ end
209
+ end
210
+ end
211
+
212
+ context 'for non-existing topic-partition combinations' do
213
+ it 'raises NoSuchTopicPartitionCombinationError' do
214
+ expect { response.leader_for('non-existent', 0) }.to raise_error(Heller::NoSuchTopicPartitionCombinationError)
215
+ end
216
+ end
217
+ end
218
+
219
+ describe '#isr_for' do
220
+ let :topics do
221
+ [1, 2, 3].map { |i| "spec-metadata-isr-for-#{i}-#{Time.now.to_i.to_s(36)}" }
222
+ end
223
+
224
+ let :response do
225
+ consumer.metadata(topics)
226
+ end
227
+
228
+ context 'for existing topic-partition combinations' do
229
+ it 'returns the correct in sync replicas for each topic-partition combination' do
230
+ topics.each do |topic|
231
+ isr = response.isr_for(topic, 0)
232
+
233
+ expect(isr.size).to eq(1)
234
+
235
+ replica = isr.first
236
+
237
+ expect(replica.connection_string).to match(/[a-z0-9\-\.]+:9092/i)
238
+ end
239
+ end
240
+ end
241
+
242
+ context 'for non-existing topic-partition combinations' do
243
+ it 'raises NoSuchTopicPartitionCombinationError' do
244
+ expect { response.isr_for('non-existent', 0) }.to raise_error(Heller::NoSuchTopicPartitionCombinationError)
245
+ end
246
+ end
247
+ end
248
+ end
249
+
250
+ describe '#offsets_before' do
251
+ let :topic do
252
+ "spec-offsets-before-#{Time.now.to_i.to_s(36)}"
253
+ end
254
+
255
+ let :requests do
256
+ Heller::OffsetRequest.new(topic, 0, (Time.now + 1).to_i * 1000, 3)
257
+ end
258
+
259
+ let :response do
260
+ consumer.offsets_before(requests)
261
+ end
262
+
263
+ before do
264
+ 3.times { producer.push(Heller::Message.new(topic, 'offsets request message')) }
265
+ end
266
+
267
+ context 'for existing topic-partition combination(s)' do
268
+ it 'returns the expected offsets' do
269
+ offsets = response.offsets(topic, 0)
270
+
271
+ expect(offsets.size).to eq(2)
272
+ expect(offsets.first).to be > offsets.last
273
+ end
274
+ end
275
+
276
+ context 'for non-existing topic-partition combination(s)' do
277
+ it 'raises NoSuchTopicPartitionCombinationError' do
278
+ expect { response.offsets('non-existent', 0) }.to raise_error(Heller::NoSuchTopicPartitionCombinationError)
279
+ end
280
+ end
281
+ end
282
+
283
+ describe '#earliest_offset' do
284
+ let :topic do
285
+ "spec-earliest-offset-#{Time.now.to_i.to_s(36)}"
286
+ end
287
+
288
+ let :response do
289
+ consumer.earliest_offset(topic, 0)
290
+ end
291
+
292
+ before do
293
+ 3.times { producer.push(Heller::Message.new(topic, 'offsets request message')) }
294
+ end
295
+
296
+ it 'returns the earliest offset' do
297
+ expect(response).to be_zero
298
+ end
299
+ end
300
+
301
+ describe '#latest_offset' do
302
+ let :topic do
303
+ "spec-latest-offset-#{Time.now.to_i.to_s(36)}"
304
+ end
305
+
306
+ before do
307
+ 3.times { producer.push(Heller::Message.new(topic, 'offsets request message')) }
308
+ end
309
+
310
+ it 'returns the latest offset' do
311
+ response = consumer.latest_offset(topic, 0)
312
+ expect(response).to eq(3)
313
+ end
314
+ end
315
+ end
316
+ end
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe 'End-to-end communication using ZookeeperConsumer' do
7
+ let :producer do
8
+ Heller::Producer.new('localhost:9092', client_id: 'test-producer', batch_size: 1, num_retries: 10, retry_backoff: 1000)
9
+ end
10
+
11
+ let :consumer do
12
+ Heller::ZookeeperConsumer.new('localhost:2181', {
13
+ group_id: 'test',
14
+ auto_reset_offset: :smallest,
15
+ timeout: 1000,
16
+ fetch_max_wait: 1000,
17
+ })
18
+ end
19
+
20
+ let :decoder do
21
+ Kafka::Serializer::StringDecoder.new(nil)
22
+ end
23
+
24
+ let :consumed do
25
+ []
26
+ end
27
+
28
+ before do
29
+ messages.each do |message|
30
+ producer.push(Heller::Message.new(topic, message))
31
+ end
32
+ end
33
+
34
+ after do
35
+ producer.close
36
+ consumer.close
37
+ end
38
+
39
+ describe '#create_streams' do
40
+ let :topic do
41
+ "spec-create-streams-#{Time.now.to_i.to_s(36).upcase}"
42
+ end
43
+
44
+ let :messages do
45
+ %w[first-stream-message second-stream-message third-stream-message]
46
+ end
47
+
48
+ it 'can actually consume messages' do
49
+ streams_map = consumer.create_streams({topic => 1}, {key_decoder: decoder, value_decoder: decoder})
50
+ stream = streams_map[topic].first
51
+ iterator = stream.iterator
52
+
53
+ messages.size.times do
54
+ consumed << iterator.next.message
55
+ end
56
+
57
+ expect(consumed).to eq(messages)
58
+ end
59
+ end
60
+
61
+ describe '#create_streams_by_filter' do
62
+ let :topic do
63
+ "spec-with-filter-#{time_component}"
64
+ end
65
+
66
+ let :time_component do
67
+ Time.now.to_i.to_s(36).upcase
68
+ end
69
+
70
+ let :messages do
71
+ %w[first-filter-message second-filter-message third-filter-message]
72
+ end
73
+
74
+ it 'can actually consume messages' do
75
+ streams = consumer.create_streams_by_filter(".+-#{time_component}", 1, {key_decoder: decoder, value_decoder: decoder})
76
+ iterator = streams.first.iterator
77
+
78
+ messages.size.times do
79
+ consumed << iterator.next.message
80
+ end
81
+
82
+ expect(consumed).to eq(messages)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'bundler/setup'
4
+ require 'json'
5
+ require 'spec/support/fakers'
6
+
7
+ RSpec.configure do |config|
8
+ config.include(Fakers)
9
+ config.order = 'random'
10
+ config.raise_errors_for_deprecations!
11
+ config.before(:suite) do
12
+ unless java.lang.System.getProperty('log4j.configuration')
13
+ @log4j_config_file = Tempfile.new('silent-log4j.properties')
14
+ @log4j_config_file.puts('log4j.rootLogger=OFF')
15
+ @log4j_config_file.rewind
16
+ java.lang.System.setProperty('log4j.configuration', %(file://#{@log4j_config_file.path}))
17
+ end
18
+ end
19
+ config.after(:suite) do
20
+ if @log4j_config_file
21
+ @log4j_config_file.close
22
+ @log4j_config_file.unlink
23
+ end
24
+ end
25
+ end
26
+
27
+ require 'coveralls'
28
+ require 'simplecov'
29
+
30
+ if ENV.include?('TRAVIS')
31
+ Coveralls.wear!
32
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
33
+ end
34
+
35
+ SimpleCov.start do
36
+ add_group 'Source', 'lib'
37
+ add_group 'Unit tests', 'spec/heller'
38
+ add_group 'Integration tests', 'spec/integration'
39
+ end
40
+
41
+ require 'heller'
@@ -0,0 +1,45 @@
1
+ module Fakers
2
+ FakeMessageAndOffset = Struct.new(:message, :offset)
3
+ FakeMessage = Struct.new(:payload)
4
+
5
+ class FakePayload
6
+ def initialize(payload)
7
+ @payload = payload.to_java_bytes
8
+ end
9
+
10
+ def limit
11
+ @payload.size
12
+ end
13
+
14
+ def get(buffer)
15
+ @payload.each_with_index do |b, i|
16
+ buffer[i] = b
17
+ end
18
+ end
19
+ end
20
+
21
+ def create_fake_message(payload)
22
+ FakeMessage.new(FakePayload.new(payload))
23
+ end
24
+
25
+ FakeMessageSet = Struct.new(:iterator)
26
+
27
+ class FakeIterator < Struct.new(:messages)
28
+ def next
29
+ messages.shift
30
+ end
31
+
32
+ def has_next?
33
+ messages.any?
34
+ end
35
+ end
36
+
37
+ def create_fake_message_set(*payloads)
38
+ messages = payloads.each_with_index.map do |payload, index|
39
+ message = create_fake_message(payload)
40
+ FakeMessageAndOffset.new(message, index)
41
+ end
42
+
43
+ FakeMessageSet.new(FakeIterator.new(messages))
44
+ end
45
+ end
metadata CHANGED
@@ -1,67 +1,102 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
5
- prerelease:
4
+ version: 0.2.0
6
5
  platform: java
7
6
  authors:
8
7
  - Mathias Söderberg
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-15 00:00:00.000000000 Z
11
+ date: 2015-05-13 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: kafka-jars
16
- version_requirements: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ~>
19
- - !ruby/object:Gem::Version
20
- version: 0.7.2.2
21
- none: false
22
14
  requirement: !ruby/object:Gem::Requirement
23
15
  requirements:
24
16
  - - ~>
25
17
  - !ruby/object:Gem::Version
26
- version: 0.7.2.2
27
- none: false
18
+ version: 0.8.2
19
+ name: kafka-jars
28
20
  prerelease: false
29
21
  type: :runtime
30
- description: Attempts to make Kafka's Java API fit a bit better with Ruby
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.2
27
+ description: Attempts to make Kafka's Java API a bit more Rubyesque
31
28
  email:
32
- - mathias.soederberg@gmail.com
29
+ - mths@sdrbrg.se
33
30
  executables: []
34
31
  extensions: []
35
32
  extra_rdoc_files: []
36
33
  files:
34
+ - README.md
37
35
  - lib/heller.rb
38
- - lib/kafka.rb
36
+ - lib/heller/configuration.rb
39
37
  - lib/heller/consumer.rb
38
+ - lib/heller/consumer_configuration.rb
39
+ - lib/heller/errors.rb
40
+ - lib/heller/fetch_request.rb
41
+ - lib/heller/fetch_response.rb
42
+ - lib/heller/message.rb
43
+ - lib/heller/message_set_enumerator.rb
44
+ - lib/heller/offset_request.rb
45
+ - lib/heller/offset_response.rb
40
46
  - lib/heller/producer.rb
41
- homepage: http://github.com/mthssdrbrg/heller
42
- licenses: []
47
+ - lib/heller/producer_configuration.rb
48
+ - lib/heller/topic_metadata_response.rb
49
+ - lib/heller/version.rb
50
+ - lib/heller/zookeeper_consumer.rb
51
+ - lib/kafka.rb
52
+ - spec/heller/consumer_configuration_spec.rb
53
+ - spec/heller/consumer_spec.rb
54
+ - spec/heller/fetch_response_spec.rb
55
+ - spec/heller/message_set_enumerator_spec.rb
56
+ - spec/heller/offset_response_spec.rb
57
+ - spec/heller/producer_configuration_spec.rb
58
+ - spec/heller/producer_spec.rb
59
+ - spec/heller/topic_metadata_response_spec.rb
60
+ - spec/heller/zookeeper_consumer_spec.rb
61
+ - spec/integration/end_to_end_communication_spec.rb
62
+ - spec/integration/zookeeper_consumer_spec.rb
63
+ - spec/spec_helper.rb
64
+ - spec/support/fakers.rb
65
+ homepage: https://github.com/mthssdrbrg/heller
66
+ licenses:
67
+ - Apache License 2.0
68
+ metadata: {}
43
69
  post_install_message:
44
70
  rdoc_options: []
45
71
  require_paths:
46
72
  - lib
47
73
  required_ruby_version: !ruby/object:Gem::Requirement
48
74
  requirements:
49
- - - ! '>='
75
+ - - '>='
50
76
  - !ruby/object:Gem::Version
51
77
  version: '0'
52
- none: false
53
78
  required_rubygems_version: !ruby/object:Gem::Requirement
54
79
  requirements:
55
- - - ! '>='
80
+ - - '>='
56
81
  - !ruby/object:Gem::Version
57
82
  version: '0'
58
- none: false
59
83
  requirements: []
60
- rubyforge_project: heller
61
- rubygems_version: 1.8.24
84
+ rubyforge_project:
85
+ rubygems_version: 2.4.6
62
86
  signing_key:
63
- specification_version: 3
87
+ specification_version: 4
64
88
  summary: JRuby wrapper for Kafka
65
- test_files: []
66
- has_rdoc:
67
- ...
89
+ test_files:
90
+ - spec/spec_helper.rb
91
+ - spec/heller/consumer_configuration_spec.rb
92
+ - spec/heller/consumer_spec.rb
93
+ - spec/heller/fetch_response_spec.rb
94
+ - spec/heller/message_set_enumerator_spec.rb
95
+ - spec/heller/offset_response_spec.rb
96
+ - spec/heller/producer_configuration_spec.rb
97
+ - spec/heller/producer_spec.rb
98
+ - spec/heller/topic_metadata_response_spec.rb
99
+ - spec/heller/zookeeper_consumer_spec.rb
100
+ - spec/integration/end_to_end_communication_spec.rb
101
+ - spec/integration/zookeeper_consumer_spec.rb
102
+ - spec/support/fakers.rb