karafka-rdkafka 0.13.2 → 0.13.9

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/ci.yml +9 -4
  4. data/.gitignore +4 -0
  5. data/.rspec +1 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +54 -26
  9. data/{LICENSE → MIT-LICENSE} +2 -1
  10. data/README.md +19 -20
  11. data/certs/cert_chain.pem +21 -21
  12. data/docker-compose.yml +16 -15
  13. data/ext/README.md +1 -1
  14. data/ext/Rakefile +1 -1
  15. data/karafka-rdkafka.gemspec +2 -2
  16. data/lib/rdkafka/abstract_handle.rb +41 -27
  17. data/lib/rdkafka/admin/create_partitions_handle.rb +6 -3
  18. data/lib/rdkafka/admin/create_topic_handle.rb +6 -3
  19. data/lib/rdkafka/admin/delete_topic_handle.rb +6 -3
  20. data/lib/rdkafka/admin.rb +6 -7
  21. data/lib/rdkafka/bindings.rb +24 -6
  22. data/lib/rdkafka/config.rb +53 -19
  23. data/lib/rdkafka/consumer/headers.rb +2 -4
  24. data/lib/rdkafka/consumer.rb +119 -93
  25. data/lib/rdkafka/error.rb +60 -1
  26. data/lib/rdkafka/helpers/time.rb +14 -0
  27. data/lib/rdkafka/metadata.rb +4 -4
  28. data/lib/rdkafka/native_kafka.rb +6 -1
  29. data/lib/rdkafka/producer/delivery_handle.rb +16 -1
  30. data/lib/rdkafka/producer/delivery_report.rb +3 -2
  31. data/lib/rdkafka/producer.rb +89 -17
  32. data/lib/rdkafka/version.rb +3 -3
  33. data/lib/rdkafka.rb +10 -1
  34. data/renovate.json +6 -0
  35. data/spec/rdkafka/abstract_handle_spec.rb +0 -2
  36. data/spec/rdkafka/admin/create_topic_handle_spec.rb +4 -4
  37. data/spec/rdkafka/admin/create_topic_report_spec.rb +0 -2
  38. data/spec/rdkafka/admin/delete_topic_handle_spec.rb +3 -3
  39. data/spec/rdkafka/admin/delete_topic_report_spec.rb +0 -2
  40. data/spec/rdkafka/admin_spec.rb +1 -2
  41. data/spec/rdkafka/bindings_spec.rb +0 -1
  42. data/spec/rdkafka/callbacks_spec.rb +0 -2
  43. data/spec/rdkafka/config_spec.rb +8 -2
  44. data/spec/rdkafka/consumer/headers_spec.rb +0 -2
  45. data/spec/rdkafka/consumer/message_spec.rb +0 -2
  46. data/spec/rdkafka/consumer/partition_spec.rb +0 -2
  47. data/spec/rdkafka/consumer/topic_partition_list_spec.rb +0 -2
  48. data/spec/rdkafka/consumer_spec.rb +122 -38
  49. data/spec/rdkafka/error_spec.rb +0 -2
  50. data/spec/rdkafka/metadata_spec.rb +2 -3
  51. data/spec/rdkafka/native_kafka_spec.rb +2 -3
  52. data/spec/rdkafka/producer/delivery_handle_spec.rb +15 -2
  53. data/spec/rdkafka/producer/delivery_report_spec.rb +0 -2
  54. data/spec/rdkafka/producer_spec.rb +293 -1
  55. data/spec/spec_helper.rb +7 -1
  56. data.tar.gz.sig +0 -0
  57. metadata +31 -28
  58. metadata.gz.sig +0 -0
  59. data/certs/karafka-pro.pem +0 -11
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "objspace"
4
-
5
3
  module Rdkafka
6
4
  # A producer for Kafka messages. To create a producer set up a {Config} and call {Config#producer producer} on that.
7
5
  class Producer
6
+ include Helpers::Time
7
+
8
8
  # Cache partitions count for 30 seconds
9
9
  PARTITIONS_COUNT_TTL = 30
10
10
 
@@ -63,6 +63,47 @@ module Rdkafka
63
63
  @delivery_callback_arity = arity(callback)
64
64
  end
65
65
 
66
+ # Init transactions
67
+ # Run once per producer
68
+ def init_transactions
69
+ closed_producer_check(__method__)
70
+
71
+ @native_kafka.with_inner do |inner|
72
+ response_ptr = Rdkafka::Bindings.rd_kafka_init_transactions(inner, -1)
73
+
74
+ Rdkafka::RdkafkaError.validate!(response_ptr) || true
75
+ end
76
+ end
77
+
78
+ def begin_transaction
79
+ closed_producer_check(__method__)
80
+
81
+ @native_kafka.with_inner do |inner|
82
+ response_ptr = Rdkafka::Bindings.rd_kafka_begin_transaction(inner)
83
+
84
+ Rdkafka::RdkafkaError.validate!(response_ptr)
85
+ end
86
+ end
87
+
88
+ def commit_transaction(timeout_ms = -1)
89
+ closed_producer_check(__method__)
90
+
91
+ @native_kafka.with_inner do |inner|
92
+ response_ptr = Rdkafka::Bindings.rd_kafka_commit_transaction(inner, timeout_ms)
93
+
94
+ Rdkafka::RdkafkaError.validate!(response_ptr)
95
+ end
96
+ end
97
+
98
+ def abort_transaction(timeout_ms = -1)
99
+ closed_producer_check(__method__)
100
+
101
+ @native_kafka.with_inner do |inner|
102
+ response_ptr = Rdkafka::Bindings.rd_kafka_abort_transaction(inner, timeout_ms)
103
+ Rdkafka::RdkafkaError.validate!(response_ptr)
104
+ end
105
+ end
106
+
66
107
  # Close this producer and wait for the internal poll queue to empty.
67
108
  def close
68
109
  return if closed?
@@ -79,27 +120,63 @@ module Rdkafka
79
120
  # in seconds. Call this before closing a producer to ensure delivery of all messages.
80
121
  #
81
122
  # @param timeout_ms [Integer] how long should we wait for flush of all messages
123
+ # @return [Boolean] true if no more data and all was flushed, false in case there are still
124
+ # outgoing messages after the timeout
125
+ #
126
+ # @note We raise an exception for other errors because based on the librdkafka docs, there
127
+ # should be no other errors.
128
+ #
129
+ # @note For `timed_out` we do not raise an error to keep it backwards compatible
82
130
  def flush(timeout_ms=5_000)
83
131
  closed_producer_check(__method__)
84
132
 
133
+ error = @native_kafka.with_inner do |inner|
134
+ response = Rdkafka::Bindings.rd_kafka_flush(inner, timeout_ms)
135
+ Rdkafka::RdkafkaError.build(response)
136
+ end
137
+
138
+ # Early skip not to build the error message
139
+ return true unless error
140
+ return false if error.code == :timed_out
141
+
142
+ raise(error)
143
+ end
144
+
145
+ # Purges the outgoing queue and releases all resources.
146
+ #
147
+ # Useful when closing the producer with outgoing messages to unstable clusters or when for
148
+ # any other reasons waiting cannot go on anymore. This purges both the queue and all the
149
+ # inflight requests + updates the delivery handles statuses so they can be materialized into
150
+ # `purge_queue` errors.
151
+ def purge
152
+ closed_producer_check(__method__)
153
+
85
154
  @native_kafka.with_inner do |inner|
86
- Rdkafka::Bindings.rd_kafka_flush(inner, timeout_ms)
155
+ response = Bindings.rd_kafka_purge(
156
+ inner,
157
+ Bindings::RD_KAFKA_PURGE_F_QUEUE | Bindings::RD_KAFKA_PURGE_F_INFLIGHT
158
+ )
159
+
160
+ Rdkafka::RdkafkaError.validate!(response)
87
161
  end
162
+
163
+ # Wait for the purge to affect everything
164
+ sleep(0.001) until flush(100)
165
+
166
+ true
88
167
  end
89
168
 
90
169
  # Partition count for a given topic.
91
- # NOTE: If 'allow.auto.create.topics' is set to true in the broker, the topic will be auto-created after returning nil.
92
170
  #
93
171
  # @param topic [String] The topic name.
172
+ # @return [Integer] partition count for a given topic
94
173
  #
95
- # @return partition count [Integer,nil]
96
- #
97
- # We cache the partition count for a given topic for given time
98
- # This prevents us in case someone uses `partition_key` from querying for the count with
99
- # each message. Instead we query once every 30 seconds at most
174
+ # @note If 'allow.auto.create.topics' is set to true in the broker, the topic will be
175
+ # auto-created after returning nil.
100
176
  #
101
- # @param topic [String] topic name
102
- # @return [Integer] partition count for a given topic
177
+ # @note We cache the partition count for a given topic for given time.
178
+ # This prevents us in case someone uses `partition_key` from querying for the count with
179
+ # each message. Instead we query once every 30 seconds at most
103
180
  def partition_count(topic)
104
181
  closed_producer_check(__method__)
105
182
 
@@ -208,7 +285,7 @@ module Rdkafka
208
285
  # Raise error if the produce call was not successful
209
286
  if response != 0
210
287
  DeliveryHandle.remove(delivery_handle.to_ptr.address)
211
- raise RdkafkaError.new(response)
288
+ Rdkafka::RdkafkaError.validate!(response)
212
289
  end
213
290
 
214
291
  delivery_handle
@@ -229,11 +306,6 @@ module Rdkafka
229
306
 
230
307
  private
231
308
 
232
- def monotonic_now
233
- # needed because Time.now can go backwards
234
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
235
- end
236
-
237
309
  def closed_producer_check(method)
238
310
  raise Rdkafka::ClosedProducerError.new(method) if closed?
239
311
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rdkafka
4
- VERSION = "0.13.2"
5
- LIBRDKAFKA_VERSION = "2.1.1"
6
- LIBRDKAFKA_SOURCE_SHA256 = "7be1fc37ab10ebdc037d5c5a9b35b48931edafffae054b488faaff99e60e0108"
4
+ VERSION = "0.13.9"
5
+ LIBRDKAFKA_VERSION = "2.2.0"
6
+ LIBRDKAFKA_SOURCE_SHA256 = "af9a820cbecbc64115629471df7c7cecd40403b6c34bfdbb9223152677a47226"
7
7
  end
data/lib/rdkafka.rb CHANGED
@@ -1,7 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rdkafka/version"
3
+ require "logger"
4
+ require "objspace"
5
+ require "ffi"
6
+ require "json"
4
7
 
8
+ require "rdkafka/version"
9
+ require "rdkafka/helpers/time"
5
10
  require "rdkafka/abstract_handle"
6
11
  require "rdkafka/admin"
7
12
  require "rdkafka/admin/create_topic_handle"
@@ -24,3 +29,7 @@ require "rdkafka/native_kafka"
24
29
  require "rdkafka/producer"
25
30
  require "rdkafka/producer/delivery_handle"
26
31
  require "rdkafka/producer/delivery_report"
32
+
33
+ # Main Rdkafka namespace of this gem
34
+ module Rdkafka
35
+ end
data/renovate.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
+ "extends": [
4
+ "config:base"
5
+ ]
6
+ }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::AbstractHandle do
6
4
  let(:response) { 0 }
7
5
  let(:result) { -1 }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Admin::CreateTopicHandle do
6
4
  let(:response) { 0 }
7
5
 
@@ -45,10 +43,12 @@ describe Rdkafka::Admin::CreateTopicHandle do
45
43
  describe "#raise_error" do
46
44
  let(:pending_handle) { false }
47
45
 
48
- it "should raise the appropriate error" do
46
+ before { subject[:response] = -1 }
47
+
48
+ it "should raise the appropriate error when there is an error" do
49
49
  expect {
50
50
  subject.raise_error
51
- }.to raise_exception(Rdkafka::RdkafkaError, /Success \(no_error\)/)
51
+ }.to raise_exception(Rdkafka::RdkafkaError, /Unknown broker error \(unknown\)/)
52
52
  end
53
53
  end
54
54
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Admin::CreateTopicReport do
6
4
  subject { Rdkafka::Admin::CreateTopicReport.new(
7
5
  FFI::MemoryPointer.from_string("error string"),
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Admin::DeleteTopicHandle do
6
4
  let(:response) { 0 }
7
5
 
@@ -45,10 +43,12 @@ describe Rdkafka::Admin::DeleteTopicHandle do
45
43
  describe "#raise_error" do
46
44
  let(:pending_handle) { false }
47
45
 
46
+ before { subject[:response] = -1 }
47
+
48
48
  it "should raise the appropriate error" do
49
49
  expect {
50
50
  subject.raise_error
51
- }.to raise_exception(Rdkafka::RdkafkaError, /Success \(no_error\)/)
51
+ }.to raise_exception(Rdkafka::RdkafkaError, /Unknown broker error \(unknown\)/)
52
52
  end
53
53
  end
54
54
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Admin::DeleteTopicReport do
6
4
  subject { Rdkafka::Admin::DeleteTopicReport.new(
7
5
  FFI::MemoryPointer.from_string("error string"),
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
3
  require "ostruct"
5
4
 
6
5
  describe Rdkafka::Admin do
@@ -33,7 +32,7 @@ describe Rdkafka::Admin do
33
32
  }.to raise_exception { |ex|
34
33
  expect(ex).to be_a(Rdkafka::RdkafkaError)
35
34
  expect(ex.message).to match(/Broker: Invalid topic \(topic_exception\)/)
36
- expect(ex.broker_message).to match(/Topic name.*is illegal, it contains a character other than ASCII alphanumerics/)
35
+ expect(ex.broker_message).to match(/Topic name.*is invalid: .* contains one or more characters other than ASCII alphanumerics, '.', '_' and '-'/)
37
36
  }
38
37
  end
39
38
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
3
  require 'zlib'
5
4
 
6
5
  describe Rdkafka::Bindings do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Callbacks do
6
4
 
7
5
  # The code in the call back functions is 100% covered by other specs. Due to
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Config do
6
4
  context "logger" do
7
5
  it "should have a default logger" do
@@ -115,6 +113,14 @@ describe Rdkafka::Config do
115
113
  consumer.close
116
114
  end
117
115
 
116
+ it "should create a consumer with consumer_poll_set set to false" do
117
+ config = rdkafka_consumer_config
118
+ config.consumer_poll_set = false
119
+ consumer = config.consumer
120
+ expect(consumer).to be_a Rdkafka::Consumer
121
+ consumer.close
122
+ end
123
+
118
124
  it "should raise an error when creating a consumer with invalid config" do
119
125
  config = Rdkafka::Config.new('invalid.key' => 'value')
120
126
  expect {
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Consumer::Headers do
6
4
  let(:headers) do
7
5
  { # Note String keys!
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Consumer::Message do
6
4
  let(:native_client) { new_native_client }
7
5
  let(:native_topic) { new_native_topic(native_client: native_client) }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Consumer::Partition do
6
4
  let(:offset) { 100 }
7
5
  let(:err) { 0 }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Consumer::TopicPartitionList do
6
4
  it "should create a new list and add unassigned topics" do
7
5
  list = Rdkafka::Consumer::TopicPartitionList.new
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
3
  require "ostruct"
5
4
  require 'securerandom'
6
5
 
@@ -55,6 +54,30 @@ describe Rdkafka::Consumer do
55
54
  consumer.subscription
56
55
  }.to raise_error(Rdkafka::RdkafkaError)
57
56
  end
57
+
58
+ context "when using consumer without the poll set" do
59
+ let(:consumer) do
60
+ config = rdkafka_consumer_config
61
+ config.consumer_poll_set = false
62
+ config.consumer
63
+ end
64
+
65
+ it "should subscribe, unsubscribe and return the subscription" do
66
+ expect(consumer.subscription).to be_empty
67
+
68
+ consumer.subscribe("consume_test_topic")
69
+
70
+ expect(consumer.subscription).not_to be_empty
71
+ expected_subscription = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
72
+ list.add_topic("consume_test_topic")
73
+ end
74
+ expect(consumer.subscription).to eq expected_subscription
75
+
76
+ consumer.unsubscribe
77
+
78
+ expect(consumer.subscription).to be_empty
79
+ end
80
+ end
58
81
  end
59
82
 
60
83
  describe "#pause and #resume" do
@@ -337,8 +360,9 @@ describe Rdkafka::Consumer do
337
360
  end
338
361
  end
339
362
 
340
- describe "#commit, #committed and #store_offset" do
341
- # Make sure there's a stored offset
363
+
364
+ describe "#position, #commit, #committed and #store_offset" do
365
+ # Make sure there are messages to work with
342
366
  let!(:report) do
343
367
  producer.produce(
344
368
  topic: "consume_test_topic",
@@ -356,29 +380,33 @@ describe Rdkafka::Consumer do
356
380
  )
357
381
  end
358
382
 
359
- it "should only accept a topic partition list in committed" do
360
- expect {
361
- consumer.committed("list")
362
- }.to raise_error TypeError
383
+ describe "#position" do
384
+ it "should only accept a topic partition list in position if not nil" do
385
+ expect {
386
+ consumer.position("list")
387
+ }.to raise_error TypeError
388
+ end
363
389
  end
364
390
 
365
- it "should commit in sync mode" do
366
- expect {
367
- consumer.commit(nil, true)
368
- }.not_to raise_error
369
- end
391
+ describe "#committed" do
392
+ it "should only accept a topic partition list in commit if not nil" do
393
+ expect {
394
+ consumer.commit("list")
395
+ }.to raise_error TypeError
396
+ end
370
397
 
371
- it "should only accept a topic partition list in commit if not nil" do
372
- expect {
373
- consumer.commit("list")
374
- }.to raise_error TypeError
398
+ it "should commit in sync mode" do
399
+ expect {
400
+ consumer.commit(nil, true)
401
+ }.not_to raise_error
402
+ end
375
403
  end
376
404
 
377
405
  context "with a committed consumer" do
378
406
  before :all do
379
407
  # Make sure there are some messages.
380
408
  handles = []
381
- producer = rdkafka_producer_config.producer
409
+ producer = rdkafka_config.producer
382
410
  10.times do
383
411
  (0..2).each do |i|
384
412
  handles << producer.produce(
@@ -422,31 +450,33 @@ describe Rdkafka::Consumer do
422
450
  }.to raise_error(Rdkafka::RdkafkaError)
423
451
  end
424
452
 
425
- it "should fetch the committed offsets for the current assignment" do
426
- partitions = consumer.committed.to_h["consume_test_topic"]
427
- expect(partitions).not_to be_nil
428
- expect(partitions[0].offset).to eq 1
429
- end
453
+ describe "#committed" do
454
+ it "should fetch the committed offsets for the current assignment" do
455
+ partitions = consumer.committed.to_h["consume_test_topic"]
456
+ expect(partitions).not_to be_nil
457
+ expect(partitions[0].offset).to eq 1
458
+ end
430
459
 
431
- it "should fetch the committed offsets for a specified topic partition list" do
432
- list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
433
- list.add_topic("consume_test_topic", [0, 1, 2])
460
+ it "should fetch the committed offsets for a specified topic partition list" do
461
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
462
+ list.add_topic("consume_test_topic", [0, 1, 2])
463
+ end
464
+ partitions = consumer.committed(list).to_h["consume_test_topic"]
465
+ expect(partitions).not_to be_nil
466
+ expect(partitions[0].offset).to eq 1
467
+ expect(partitions[1].offset).to eq 1
468
+ expect(partitions[2].offset).to eq 1
434
469
  end
435
- partitions = consumer.committed(list).to_h["consume_test_topic"]
436
- expect(partitions).not_to be_nil
437
- expect(partitions[0].offset).to eq 1
438
- expect(partitions[1].offset).to eq 1
439
- expect(partitions[2].offset).to eq 1
440
- end
441
470
 
442
- it "should raise an error when getting committed fails" do
443
- expect(Rdkafka::Bindings).to receive(:rd_kafka_committed).and_return(20)
444
- list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
445
- list.add_topic("consume_test_topic", [0, 1, 2])
471
+ it "should raise an error when getting committed fails" do
472
+ expect(Rdkafka::Bindings).to receive(:rd_kafka_committed).and_return(20)
473
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
474
+ list.add_topic("consume_test_topic", [0, 1, 2])
475
+ end
476
+ expect {
477
+ consumer.committed(list)
478
+ }.to raise_error Rdkafka::RdkafkaError
446
479
  end
447
- expect {
448
- consumer.committed(list)
449
- }.to raise_error Rdkafka::RdkafkaError
450
480
  end
451
481
 
452
482
  describe "#store_offset" do
@@ -467,6 +497,8 @@ describe Rdkafka::Consumer do
467
497
  @new_consumer.store_offset(message)
468
498
  @new_consumer.commit
469
499
 
500
+ # TODO use position here, should be at offset
501
+
470
502
  list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
471
503
  list.add_topic("consume_test_topic", [0, 1, 2])
472
504
  end
@@ -481,6 +513,35 @@ describe Rdkafka::Consumer do
481
513
  @new_consumer.store_offset(message)
482
514
  }.to raise_error Rdkafka::RdkafkaError
483
515
  end
516
+
517
+ describe "#position" do
518
+ it "should fetch the positions for the current assignment" do
519
+ consumer.store_offset(message)
520
+
521
+ partitions = consumer.position.to_h["consume_test_topic"]
522
+ expect(partitions).not_to be_nil
523
+ expect(partitions[0].offset).to eq message.offset + 1
524
+ end
525
+
526
+ it "should fetch the positions for a specified assignment" do
527
+ consumer.store_offset(message)
528
+
529
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
530
+ list.add_topic_and_partitions_with_offsets("consume_test_topic", 0 => nil, 1 => nil, 2 => nil)
531
+ end
532
+ partitions = consumer.position(list).to_h["consume_test_topic"]
533
+ expect(partitions).not_to be_nil
534
+ expect(partitions[0].offset).to eq message.offset + 1
535
+ end
536
+
537
+ it "should raise an error when getting the position fails" do
538
+ expect(Rdkafka::Bindings).to receive(:rd_kafka_position).and_return(20)
539
+
540
+ expect {
541
+ consumer.position
542
+ }.to raise_error(Rdkafka::RdkafkaError)
543
+ end
544
+ end
484
545
  end
485
546
  end
486
547
  end
@@ -1039,6 +1100,29 @@ describe Rdkafka::Consumer do
1039
1100
  end
1040
1101
  end
1041
1102
 
1103
+ # Only relevant in case of a consumer with separate queues
1104
+ describe '#events_poll' do
1105
+ let(:stats) { [] }
1106
+
1107
+ before { Rdkafka::Config.statistics_callback = ->(published) { stats << published } }
1108
+
1109
+ after { Rdkafka::Config.statistics_callback = nil }
1110
+
1111
+ let(:consumer) do
1112
+ config = rdkafka_consumer_config('statistics.interval.ms': 100)
1113
+ config.consumer_poll_set = false
1114
+ config.consumer
1115
+ end
1116
+
1117
+ it "expect to run events_poll, operate and propagate stats on events_poll and not poll" do
1118
+ consumer.subscribe("consume_test_topic")
1119
+ consumer.poll(1_000)
1120
+ expect(stats).to be_empty
1121
+ consumer.events_poll(-1)
1122
+ expect(stats).not_to be_empty
1123
+ end
1124
+ end
1125
+
1042
1126
  describe "a rebalance listener" do
1043
1127
  let(:consumer) do
1044
1128
  config = rdkafka_consumer_config
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::RdkafkaError do
6
4
  it "should raise a type error for a nil response" do
7
5
  expect {
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
3
  require "securerandom"
5
4
 
6
5
  describe Rdkafka::Metadata do
@@ -31,7 +30,7 @@ describe Rdkafka::Metadata do
31
30
  it "#brokers returns our single broker" do
32
31
  expect(subject.brokers.length).to eq(1)
33
32
  expect(subject.brokers[0][:broker_id]).to eq(1)
34
- expect(subject.brokers[0][:broker_name]).to eq("localhost")
33
+ expect(subject.brokers[0][:broker_name]).to eq("127.0.0.1")
35
34
  expect(subject.brokers[0][:broker_port]).to eq(9092)
36
35
  end
37
36
 
@@ -54,7 +53,7 @@ describe Rdkafka::Metadata do
54
53
  it "#brokers returns our single broker" do
55
54
  expect(subject.brokers.length).to eq(1)
56
55
  expect(subject.brokers[0][:broker_id]).to eq(1)
57
- expect(subject.brokers[0][:broker_name]).to eq("localhost")
56
+ expect(subject.brokers[0][:broker_name]).to eq("127.0.0.1")
58
57
  expect(subject.brokers[0][:broker_port]).to eq(9092)
59
58
  end
60
59
 
@@ -1,14 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::NativeKafka do
6
4
  let(:config) { rdkafka_producer_config }
7
5
  let(:native) { config.send(:native_kafka, config.send(:native_config), :rd_kafka_producer) }
8
6
  let(:closing) { false }
9
7
  let(:thread) { double(Thread) }
8
+ let(:opaque) { Rdkafka::Opaque.new }
10
9
 
11
- subject(:client) { described_class.new(native, run_polling_thread: true) }
10
+ subject(:client) { described_class.new(native, run_polling_thread: true, opaque: opaque) }
12
11
 
13
12
  before do
14
13
  allow(Thread).to receive(:new).and_return(thread)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Producer::DeliveryHandle do
6
4
  let(:response) { 0 }
7
5
 
@@ -44,4 +42,19 @@ describe Rdkafka::Producer::DeliveryHandle do
44
42
  end
45
43
  end
46
44
  end
45
+
46
+ describe '#create_result' do
47
+ let(:pending_handle) { false }
48
+ let(:report) { subject.create_result }
49
+
50
+ context 'when response is 0' do
51
+ it { expect(report.error).to eq(nil) }
52
+ end
53
+
54
+ context 'when response is not 0' do
55
+ let(:response) { 1 }
56
+
57
+ it { expect(report.error).to eq(Rdkafka::RdkafkaError.new(response)) }
58
+ end
59
+ end
47
60
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Rdkafka::Producer::DeliveryReport do
6
4
  subject { Rdkafka::Producer::DeliveryReport.new(2, 100, "topic", -1) }
7
5