rdkafka 0.3.5 → 0.4.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +6 -6
- data/CHANGELOG.md +12 -0
- data/README.md +42 -6
- data/Rakefile +13 -17
- data/docker-compose.yml +18 -0
- data/ext/Rakefile +17 -1
- data/lib/rdkafka/bindings.rb +19 -1
- data/lib/rdkafka/config.rb +24 -0
- data/lib/rdkafka/consumer.rb +55 -11
- data/lib/rdkafka/consumer/message.rb +16 -2
- data/lib/rdkafka/consumer/partition.rb +6 -2
- data/lib/rdkafka/consumer/topic_partition_list.rb +100 -44
- data/lib/rdkafka/producer.rb +15 -6
- data/lib/rdkafka/version.rb +2 -2
- data/spec/rdkafka/bindings_spec.rb +23 -0
- data/spec/rdkafka/config_spec.rb +16 -0
- data/spec/rdkafka/consumer/message_spec.rb +20 -6
- data/spec/rdkafka/consumer/partition_spec.rb +10 -1
- data/spec/rdkafka/consumer/topic_partition_list_spec.rb +111 -32
- data/spec/rdkafka/consumer_spec.rb +111 -4
- data/spec/rdkafka/producer_spec.rb +100 -17
- metadata +4 -3
@@ -23,23 +23,37 @@ module Rdkafka
|
|
23
23
|
attr_reader :offset
|
24
24
|
|
25
25
|
# This message's timestamp, if provided by the broker
|
26
|
-
# @return [
|
26
|
+
# @return [Time, nil]
|
27
27
|
attr_reader :timestamp
|
28
28
|
|
29
29
|
# @private
|
30
30
|
def initialize(native_message)
|
31
|
+
# Set topic
|
31
32
|
unless native_message[:rkt].null?
|
32
33
|
@topic = Rdkafka::Bindings.rd_kafka_topic_name(native_message[:rkt])
|
33
34
|
end
|
35
|
+
# Set partition
|
34
36
|
@partition = native_message[:partition]
|
37
|
+
# Set payload
|
35
38
|
unless native_message[:payload].null?
|
36
39
|
@payload = native_message[:payload].read_string(native_message[:len])
|
37
40
|
end
|
41
|
+
# Set key
|
38
42
|
unless native_message[:key].null?
|
39
43
|
@key = native_message[:key].read_string(native_message[:key_len])
|
40
44
|
end
|
45
|
+
# Set offset
|
41
46
|
@offset = native_message[:offset]
|
42
|
-
|
47
|
+
# Set timestamp
|
48
|
+
raw_timestamp = Rdkafka::Bindings.rd_kafka_message_timestamp(native_message, nil)
|
49
|
+
@timestamp = if raw_timestamp && raw_timestamp > -1
|
50
|
+
# Calculate seconds and microseconds
|
51
|
+
seconds = raw_timestamp / 1000
|
52
|
+
milliseconds = (raw_timestamp - seconds * 1000) * 1000
|
53
|
+
Time.at(seconds, milliseconds)
|
54
|
+
else
|
55
|
+
nil
|
56
|
+
end
|
43
57
|
end
|
44
58
|
|
45
59
|
# Human readable representation of this message.
|
@@ -7,7 +7,7 @@ module Rdkafka
|
|
7
7
|
attr_reader :partition
|
8
8
|
|
9
9
|
# Partition's offset
|
10
|
-
# @return [Integer]
|
10
|
+
# @return [Integer, nil]
|
11
11
|
attr_reader :offset
|
12
12
|
|
13
13
|
# @private
|
@@ -19,7 +19,11 @@ module Rdkafka
|
|
19
19
|
# Human readable representation of this partition.
|
20
20
|
# @return [String]
|
21
21
|
def to_s
|
22
|
-
|
22
|
+
if offset.nil?
|
23
|
+
"<Partition #{partition} without offset>"
|
24
|
+
else
|
25
|
+
"<Partition #{partition} with offset #{offset}>"
|
26
|
+
end
|
23
27
|
end
|
24
28
|
|
25
29
|
# Human readable representation of this partition.
|
@@ -2,34 +2,37 @@ module Rdkafka
|
|
2
2
|
class Consumer
|
3
3
|
# A list of topics with their partition information
|
4
4
|
class TopicPartitionList
|
5
|
-
# Create a
|
5
|
+
# Create a topic partition list.
|
6
6
|
#
|
7
|
-
# @param
|
7
|
+
# @param data [Hash<String => [nil,Partition]>] The topic and partion data or nil to create an empty list
|
8
8
|
#
|
9
9
|
# @return [TopicPartitionList]
|
10
|
-
def initialize(
|
11
|
-
@
|
12
|
-
Rdkafka::Bindings::TopicPartitionList.new(
|
13
|
-
FFI::AutoPointer.new(
|
14
|
-
pointer || Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5),
|
15
|
-
Rdkafka::Bindings.method(:rd_kafka_topic_partition_list_destroy)
|
16
|
-
)
|
17
|
-
)
|
10
|
+
def initialize(data=nil)
|
11
|
+
@data = data || {}
|
18
12
|
end
|
19
13
|
|
20
14
|
# Number of items in the list
|
21
15
|
# @return [Integer]
|
22
16
|
def count
|
23
|
-
|
17
|
+
i = 0
|
18
|
+
@data.each do |_topic, partitions|
|
19
|
+
if partitions
|
20
|
+
i += partitions.count
|
21
|
+
else
|
22
|
+
i+= 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
i
|
24
26
|
end
|
25
27
|
|
26
28
|
# Whether this list is empty
|
27
29
|
# @return [Boolean]
|
28
30
|
def empty?
|
29
|
-
|
31
|
+
@data.empty?
|
30
32
|
end
|
31
33
|
|
32
34
|
# Add a topic with optionally partitions to the list.
|
35
|
+
# Calling this method multiple times for the same topic will overwrite the previous configuraton.
|
33
36
|
#
|
34
37
|
# @example Add a topic with unassigned partitions
|
35
38
|
# tpl.add_topic("topic")
|
@@ -41,48 +44,36 @@ module Rdkafka
|
|
41
44
|
# tpl.add_topic("topic", 9)
|
42
45
|
#
|
43
46
|
# @param topic [String] The topic's name
|
44
|
-
# @param
|
47
|
+
# @param partitions [Array<Integer>, Range<Integer>, Integer] The topic's partitions or partition count
|
45
48
|
#
|
46
49
|
# @return [nil]
|
47
50
|
def add_topic(topic, partitions=nil)
|
48
|
-
if partitions.is_a? Integer
|
49
|
-
partitions = (0..partitions - 1)
|
50
|
-
end
|
51
51
|
if partitions.nil?
|
52
|
-
|
53
|
-
@tpl,
|
54
|
-
topic,
|
55
|
-
-1
|
56
|
-
)
|
52
|
+
@data[topic.to_s] = nil
|
57
53
|
else
|
58
|
-
partitions.
|
59
|
-
|
60
|
-
@tpl,
|
61
|
-
topic,
|
62
|
-
partition
|
63
|
-
)
|
54
|
+
if partitions.is_a? Integer
|
55
|
+
partitions = (0..partitions - 1)
|
64
56
|
end
|
57
|
+
@data[topic.to_s] = partitions.map { |p| Partition.new(p, nil) }
|
65
58
|
end
|
66
59
|
end
|
67
60
|
|
61
|
+
# Add a topic with partitions and offsets set to the list
|
62
|
+
# Calling this method multiple times for the same topic will overwrite the previous configuraton.
|
63
|
+
#
|
64
|
+
# @param topic [String] The topic's name
|
65
|
+
# @param partitions_with_offsets [Hash<Integer, Integer>] The topic's partitions and offsets
|
66
|
+
#
|
67
|
+
# @return [nil]
|
68
|
+
def add_topic_and_partitions_with_offsets(topic, partitions_with_offsets)
|
69
|
+
@data[topic.to_s] = partitions_with_offsets.map { |p, o| Partition.new(p, o) }
|
70
|
+
end
|
71
|
+
|
68
72
|
# Return a `Hash` with the topics as keys and and an array of partition information as the value if present.
|
69
73
|
#
|
70
74
|
# @return [Hash<String, [Array<Partition>, nil]>]
|
71
75
|
def to_h
|
72
|
-
|
73
|
-
count.times do |i|
|
74
|
-
ptr = @tpl[:elems] + (i * Rdkafka::Bindings::TopicPartition.size)
|
75
|
-
elem = Rdkafka::Bindings::TopicPartition.new(ptr)
|
76
|
-
if elem[:partition] == -1
|
77
|
-
out[elem[:topic]] = nil
|
78
|
-
else
|
79
|
-
partitions = out[elem[:topic]] || []
|
80
|
-
partition = Partition.new(elem[:partition], elem[:offset])
|
81
|
-
partitions.push(partition)
|
82
|
-
out[elem[:topic]] = partitions
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
76
|
+
@data
|
86
77
|
end
|
87
78
|
|
88
79
|
# Human readable representation of this list.
|
@@ -95,10 +86,75 @@ module Rdkafka
|
|
95
86
|
self.to_h == other.to_h
|
96
87
|
end
|
97
88
|
|
98
|
-
#
|
89
|
+
# Create a new topic partition list based of a native one.
|
90
|
+
#
|
91
|
+
# @param pointer [FFI::Pointer] Optional pointer to an existing native list. Its contents will be copied and afterwards it will be destroyed.
|
92
|
+
#
|
93
|
+
# @return [TopicPartitionList]
|
94
|
+
#
|
95
|
+
# @private
|
96
|
+
def self.from_native_tpl(pointer)
|
97
|
+
# Data to be moved into the tpl
|
98
|
+
data = {}
|
99
|
+
|
100
|
+
# Create struct and copy its contents
|
101
|
+
native_tpl = Rdkafka::Bindings::TopicPartitionList.new(pointer)
|
102
|
+
native_tpl[:cnt].times do |i|
|
103
|
+
ptr = native_tpl[:elems] + (i * Rdkafka::Bindings::TopicPartition.size)
|
104
|
+
elem = Rdkafka::Bindings::TopicPartition.new(ptr)
|
105
|
+
if elem[:partition] == -1
|
106
|
+
data[elem[:topic]] = nil
|
107
|
+
else
|
108
|
+
partitions = data[elem[:topic]] || []
|
109
|
+
offset = if elem[:offset] == -1001
|
110
|
+
nil
|
111
|
+
else
|
112
|
+
elem[:offset]
|
113
|
+
end
|
114
|
+
partition = Partition.new(elem[:partition], offset)
|
115
|
+
partitions.push(partition)
|
116
|
+
data[elem[:topic]] = partitions
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return the created object
|
121
|
+
TopicPartitionList.new(data)
|
122
|
+
ensure
|
123
|
+
# Destroy the tpl
|
124
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_destroy(pointer)
|
125
|
+
end
|
126
|
+
|
127
|
+
# Create a native tpl with the contents of this object added
|
128
|
+
#
|
99
129
|
# @private
|
100
|
-
def
|
101
|
-
Rdkafka::Bindings.
|
130
|
+
def to_native_tpl
|
131
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_new(count).tap do |tpl|
|
132
|
+
@data.each do |topic, partitions|
|
133
|
+
if partitions
|
134
|
+
partitions.each do |p|
|
135
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
136
|
+
tpl,
|
137
|
+
topic,
|
138
|
+
p.partition
|
139
|
+
)
|
140
|
+
if p.offset
|
141
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(
|
142
|
+
tpl,
|
143
|
+
topic,
|
144
|
+
p.partition,
|
145
|
+
p.offset
|
146
|
+
)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
else
|
150
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
151
|
+
tpl,
|
152
|
+
topic,
|
153
|
+
-1
|
154
|
+
)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
102
158
|
end
|
103
159
|
end
|
104
160
|
end
|
data/lib/rdkafka/producer.rb
CHANGED
@@ -32,10 +32,10 @@ module Rdkafka
|
|
32
32
|
# When a timestamp is provided this is used instead of the autogenerated timestamp.
|
33
33
|
#
|
34
34
|
# @param topic [String] The topic to produce to
|
35
|
-
# @param payload [String] The message's payload
|
35
|
+
# @param payload [String,nil] The message's payload
|
36
36
|
# @param key [String] The message's key
|
37
|
-
# @param partition [Integer] Optional partition to produce to
|
38
|
-
# @param timestamp [Integer] Optional timestamp of this message
|
37
|
+
# @param partition [Integer,nil] Optional partition to produce to
|
38
|
+
# @param timestamp [Time,Integer,nil] Optional timestamp of this message. Integer timestamp is in milliseconds since Jan 1 1970.
|
39
39
|
#
|
40
40
|
# @raise [RdkafkaError] When adding the message to rdkafka's queue failed
|
41
41
|
#
|
@@ -61,8 +61,17 @@ module Rdkafka
|
|
61
61
|
# on the key/randomly if there is no key
|
62
62
|
partition = -1 if partition.nil?
|
63
63
|
|
64
|
-
# If timestamp is nil use 0 and let Kafka set one
|
65
|
-
|
64
|
+
# If timestamp is nil use 0 and let Kafka set one. If an integer or time
|
65
|
+
# use it.
|
66
|
+
raw_timestamp = if timestamp.nil?
|
67
|
+
0
|
68
|
+
elsif timestamp.is_a?(Integer)
|
69
|
+
timestamp
|
70
|
+
elsif timestamp.is_a?(Time)
|
71
|
+
(timestamp.to_i * 1000) + (timestamp.usec / 1000)
|
72
|
+
else
|
73
|
+
raise TypeError.new("Timestamp has to be nil, an Integer or a Time")
|
74
|
+
end
|
66
75
|
|
67
76
|
delivery_handle = DeliveryHandle.new
|
68
77
|
delivery_handle[:pending] = true
|
@@ -79,7 +88,7 @@ module Rdkafka
|
|
79
88
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_VALUE, :buffer_in, payload, :size_t, payload_size,
|
80
89
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_KEY, :buffer_in, key, :size_t, key_size,
|
81
90
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_PARTITION, :int32, partition,
|
82
|
-
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_TIMESTAMP, :int64,
|
91
|
+
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_TIMESTAMP, :int64, raw_timestamp,
|
83
92
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_OPAQUE, :pointer, delivery_handle,
|
84
93
|
:int, Rdkafka::Bindings::RD_KAFKA_VTYPE_END
|
85
94
|
)
|
data/lib/rdkafka/version.rb
CHANGED
@@ -59,4 +59,27 @@ describe Rdkafka::Bindings do
|
|
59
59
|
expect(log.string).to include "ANY -- : rdkafka: log line"
|
60
60
|
end
|
61
61
|
end
|
62
|
+
|
63
|
+
describe "stats callback" do
|
64
|
+
context "without a stats callback" do
|
65
|
+
it "should do nothing" do
|
66
|
+
expect {
|
67
|
+
Rdkafka::Bindings::StatsCallback.call(nil, "{}", 2, nil)
|
68
|
+
}.not_to raise_error
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context "with a stats callback" do
|
73
|
+
before do
|
74
|
+
Rdkafka::Config.statistics_callback = lambda do |stats|
|
75
|
+
$received_stats = stats
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should call the stats callback with a stats hash" do
|
80
|
+
Rdkafka::Bindings::StatsCallback.call(nil, "{\"received\":1}", 13, nil)
|
81
|
+
expect($received_stats).to eq({'received' => 1})
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
62
85
|
end
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -20,6 +20,22 @@ describe Rdkafka::Config do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
context "statistics callback" do
|
24
|
+
it "should set the callback" do
|
25
|
+
expect {
|
26
|
+
Rdkafka::Config.statistics_callback = lambda do |stats|
|
27
|
+
puts stats
|
28
|
+
end
|
29
|
+
}.not_to raise_error
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not accept a callback that's not a proc" do
|
33
|
+
expect {
|
34
|
+
Rdkafka::Config.statistics_callback = 'a string'
|
35
|
+
}.to raise_error(TypeError)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
23
39
|
context "configuration" do
|
24
40
|
it "should store configuration" do
|
25
41
|
config = Rdkafka::Config.new
|
@@ -65,12 +65,26 @@ describe Rdkafka::Consumer::Message do
|
|
65
65
|
expect(subject.offset).to eq 100
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
68
|
+
describe "#timestamp" do
|
69
|
+
context "without a timestamp" do
|
70
|
+
before do
|
71
|
+
allow(Rdkafka::Bindings).to receive(:rd_kafka_message_timestamp).and_return(-1)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should have a nil timestamp if not present" do
|
75
|
+
expect(subject.timestamp).to be_nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "with a timestamp" do
|
80
|
+
before do
|
81
|
+
allow(Rdkafka::Bindings).to receive(:rd_kafka_message_timestamp).and_return(1505069646250)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should have timestamp if present" do
|
85
|
+
expect(subject.timestamp).to eq Time.at(1505069646, 250_000)
|
86
|
+
end
|
87
|
+
end
|
74
88
|
end
|
75
89
|
|
76
90
|
describe "#to_s" do
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Rdkafka::Consumer::Partition do
|
4
|
-
|
4
|
+
let(:offset) { 100 }
|
5
|
+
subject { Rdkafka::Consumer::Partition.new(1, offset) }
|
5
6
|
|
6
7
|
it "should have a partition" do
|
7
8
|
expect(subject.partition).to eq 1
|
@@ -21,6 +22,14 @@ describe Rdkafka::Consumer::Partition do
|
|
21
22
|
it "should return a human readable representation" do
|
22
23
|
expect(subject.to_s).to eq "<Partition 1 with offset 100>"
|
23
24
|
end
|
25
|
+
|
26
|
+
context "without offset" do
|
27
|
+
let(:offset) { nil }
|
28
|
+
|
29
|
+
it "should return a human readable representation" do
|
30
|
+
expect(subject.to_s).to eq "<Partition 1 without offset>"
|
31
|
+
end
|
32
|
+
end
|
24
33
|
end
|
25
34
|
|
26
35
|
describe "#==" do
|
@@ -1,22 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Rdkafka::Consumer::TopicPartitionList do
|
4
|
-
it "should create a list from an existing native list" do
|
5
|
-
pointer = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5)
|
6
|
-
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
7
|
-
pointer,
|
8
|
-
"topic",
|
9
|
-
-1
|
10
|
-
)
|
11
|
-
list = Rdkafka::Consumer::TopicPartitionList.new(pointer)
|
12
|
-
|
13
|
-
other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
14
|
-
list.add_topic("topic")
|
15
|
-
end
|
16
|
-
|
17
|
-
expect(list).to eq other
|
18
|
-
end
|
19
|
-
|
20
4
|
it "should create a new list and add unassigned topics" do
|
21
5
|
list = Rdkafka::Consumer::TopicPartitionList.new
|
22
6
|
|
@@ -52,13 +36,13 @@ describe Rdkafka::Consumer::TopicPartitionList do
|
|
52
36
|
hash = list.to_h
|
53
37
|
expect(hash.count).to eq 2
|
54
38
|
expect(hash["topic1"]).to eq([
|
55
|
-
Rdkafka::Consumer::Partition.new(0,
|
56
|
-
Rdkafka::Consumer::Partition.new(1,
|
57
|
-
Rdkafka::Consumer::Partition.new(2,
|
39
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
40
|
+
Rdkafka::Consumer::Partition.new(1, nil),
|
41
|
+
Rdkafka::Consumer::Partition.new(2, nil)
|
58
42
|
])
|
59
43
|
expect(hash["topic2"]).to eq([
|
60
|
-
Rdkafka::Consumer::Partition.new(0,
|
61
|
-
Rdkafka::Consumer::Partition.new(1,
|
44
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
45
|
+
Rdkafka::Consumer::Partition.new(1, nil)
|
62
46
|
])
|
63
47
|
end
|
64
48
|
|
@@ -77,13 +61,13 @@ describe Rdkafka::Consumer::TopicPartitionList do
|
|
77
61
|
hash = list.to_h
|
78
62
|
expect(hash.count).to eq 2
|
79
63
|
expect(hash["topic1"]).to eq([
|
80
|
-
Rdkafka::Consumer::Partition.new(0,
|
81
|
-
Rdkafka::Consumer::Partition.new(1,
|
82
|
-
Rdkafka::Consumer::Partition.new(2,
|
64
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
65
|
+
Rdkafka::Consumer::Partition.new(1, nil),
|
66
|
+
Rdkafka::Consumer::Partition.new(2, nil)
|
83
67
|
])
|
84
68
|
expect(hash["topic2"]).to eq([
|
85
|
-
Rdkafka::Consumer::Partition.new(0,
|
86
|
-
Rdkafka::Consumer::Partition.new(1,
|
69
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
70
|
+
Rdkafka::Consumer::Partition.new(1, nil)
|
87
71
|
])
|
88
72
|
end
|
89
73
|
|
@@ -102,13 +86,30 @@ describe Rdkafka::Consumer::TopicPartitionList do
|
|
102
86
|
hash = list.to_h
|
103
87
|
expect(hash.count).to eq 2
|
104
88
|
expect(hash["topic1"]).to eq([
|
105
|
-
Rdkafka::Consumer::Partition.new(0,
|
106
|
-
Rdkafka::Consumer::Partition.new(1,
|
107
|
-
Rdkafka::Consumer::Partition.new(2,
|
89
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
90
|
+
Rdkafka::Consumer::Partition.new(1, nil),
|
91
|
+
Rdkafka::Consumer::Partition.new(2, nil)
|
108
92
|
])
|
109
93
|
expect(hash["topic2"]).to eq([
|
110
|
-
Rdkafka::Consumer::Partition.new(0,
|
111
|
-
Rdkafka::Consumer::Partition.new(1,
|
94
|
+
Rdkafka::Consumer::Partition.new(0, nil),
|
95
|
+
Rdkafka::Consumer::Partition.new(1, nil)
|
96
|
+
])
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should create a new list and add topics and partitions with an offset" do
|
100
|
+
list = Rdkafka::Consumer::TopicPartitionList.new
|
101
|
+
|
102
|
+
expect(list.count).to eq 0
|
103
|
+
expect(list.empty?).to be true
|
104
|
+
|
105
|
+
list.add_topic_and_partitions_with_offsets("topic1", 0 => 5, 1 => 6, 2 => 7)
|
106
|
+
|
107
|
+
hash = list.to_h
|
108
|
+
expect(hash.count).to eq 1
|
109
|
+
expect(hash["topic1"]).to eq([
|
110
|
+
Rdkafka::Consumer::Partition.new(0, 5),
|
111
|
+
Rdkafka::Consumer::Partition.new(1, 6),
|
112
|
+
Rdkafka::Consumer::Partition.new(2, 7)
|
112
113
|
])
|
113
114
|
end
|
114
115
|
|
@@ -117,7 +118,7 @@ describe Rdkafka::Consumer::TopicPartitionList do
|
|
117
118
|
list = Rdkafka::Consumer::TopicPartitionList.new
|
118
119
|
list.add_topic("topic1", [0, 1])
|
119
120
|
|
120
|
-
expected = "<TopicPartitionList: {\"topic1\"=>[<Partition 0
|
121
|
+
expected = "<TopicPartitionList: {\"topic1\"=>[<Partition 0 without offset>, <Partition 1 without offset>]}>"
|
121
122
|
|
122
123
|
expect(list.to_s).to eq expected
|
123
124
|
end
|
@@ -141,4 +142,82 @@ describe Rdkafka::Consumer::TopicPartitionList do
|
|
141
142
|
expect(subject).not_to eq Rdkafka::Consumer::TopicPartitionList.new
|
142
143
|
end
|
143
144
|
end
|
145
|
+
|
146
|
+
describe ".from_native_tpl" do
|
147
|
+
it "should create a list from an existing native list" do
|
148
|
+
pointer = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5)
|
149
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
150
|
+
pointer,
|
151
|
+
"topic",
|
152
|
+
-1
|
153
|
+
)
|
154
|
+
list = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(pointer)
|
155
|
+
|
156
|
+
other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
157
|
+
list.add_topic("topic")
|
158
|
+
end
|
159
|
+
|
160
|
+
expect(list).to eq other
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should create a list from an existing native list with offsets" do
|
164
|
+
pointer = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5)
|
165
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
|
166
|
+
pointer,
|
167
|
+
"topic",
|
168
|
+
0
|
169
|
+
)
|
170
|
+
Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(
|
171
|
+
pointer,
|
172
|
+
"topic",
|
173
|
+
0,
|
174
|
+
100
|
175
|
+
)
|
176
|
+
list = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(pointer)
|
177
|
+
|
178
|
+
other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
179
|
+
list.add_topic_and_partitions_with_offsets("topic", 0 => 100)
|
180
|
+
end
|
181
|
+
|
182
|
+
expect(list).to eq other
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#to_native_tpl" do
|
187
|
+
it "should create a native list" do
|
188
|
+
list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
189
|
+
list.add_topic("topic")
|
190
|
+
end
|
191
|
+
|
192
|
+
tpl = list.to_native_tpl
|
193
|
+
|
194
|
+
other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
|
195
|
+
|
196
|
+
expect(list).to eq other
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should create a native list with partitions" do
|
200
|
+
list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
201
|
+
list.add_topic("topic", 0..16)
|
202
|
+
end
|
203
|
+
|
204
|
+
tpl = list.to_native_tpl
|
205
|
+
|
206
|
+
other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
|
207
|
+
|
208
|
+
expect(list).to eq other
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should create a native list with offsets" do
|
212
|
+
list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
|
213
|
+
list.add_topic_and_partitions_with_offsets("topic", 0 => 100)
|
214
|
+
end
|
215
|
+
|
216
|
+
tpl = list.to_native_tpl
|
217
|
+
|
218
|
+
other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
|
219
|
+
|
220
|
+
expect(list).to eq other
|
221
|
+
end
|
222
|
+
end
|
144
223
|
end
|