rdkafka 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|