heller 0.0.3-java → 0.2.0-java

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.
@@ -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