karafka-rdkafka 0.20.0.rc3-x86_64-linux-gnu

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 (99) hide show
  1. checksums.yaml +7 -0
  2. data/.github/CODEOWNERS +3 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/workflows/ci_linux_x86_64_gnu.yml +248 -0
  5. data/.github/workflows/ci_macos_arm64.yml +301 -0
  6. data/.github/workflows/push_linux_x86_64_gnu.yml +60 -0
  7. data/.github/workflows/push_ruby.yml +37 -0
  8. data/.github/workflows/verify-action-pins.yml +16 -0
  9. data/.gitignore +15 -0
  10. data/.rspec +2 -0
  11. data/.ruby-gemset +1 -0
  12. data/.ruby-version +1 -0
  13. data/.yardopts +2 -0
  14. data/CHANGELOG.md +323 -0
  15. data/Gemfile +5 -0
  16. data/MIT-LICENSE +22 -0
  17. data/README.md +177 -0
  18. data/Rakefile +96 -0
  19. data/docker-compose.yml +25 -0
  20. data/ext/README.md +19 -0
  21. data/ext/Rakefile +131 -0
  22. data/ext/build_common.sh +361 -0
  23. data/ext/build_linux_x86_64_gnu.sh +306 -0
  24. data/ext/build_macos_arm64.sh +550 -0
  25. data/ext/librdkafka.so +0 -0
  26. data/karafka-rdkafka.gemspec +61 -0
  27. data/lib/rdkafka/abstract_handle.rb +116 -0
  28. data/lib/rdkafka/admin/acl_binding_result.rb +51 -0
  29. data/lib/rdkafka/admin/config_binding_result.rb +30 -0
  30. data/lib/rdkafka/admin/config_resource_binding_result.rb +18 -0
  31. data/lib/rdkafka/admin/create_acl_handle.rb +28 -0
  32. data/lib/rdkafka/admin/create_acl_report.rb +24 -0
  33. data/lib/rdkafka/admin/create_partitions_handle.rb +30 -0
  34. data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
  35. data/lib/rdkafka/admin/create_topic_handle.rb +32 -0
  36. data/lib/rdkafka/admin/create_topic_report.rb +24 -0
  37. data/lib/rdkafka/admin/delete_acl_handle.rb +30 -0
  38. data/lib/rdkafka/admin/delete_acl_report.rb +23 -0
  39. data/lib/rdkafka/admin/delete_groups_handle.rb +28 -0
  40. data/lib/rdkafka/admin/delete_groups_report.rb +24 -0
  41. data/lib/rdkafka/admin/delete_topic_handle.rb +32 -0
  42. data/lib/rdkafka/admin/delete_topic_report.rb +24 -0
  43. data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
  44. data/lib/rdkafka/admin/describe_acl_report.rb +24 -0
  45. data/lib/rdkafka/admin/describe_configs_handle.rb +33 -0
  46. data/lib/rdkafka/admin/describe_configs_report.rb +48 -0
  47. data/lib/rdkafka/admin/incremental_alter_configs_handle.rb +33 -0
  48. data/lib/rdkafka/admin/incremental_alter_configs_report.rb +48 -0
  49. data/lib/rdkafka/admin.rb +832 -0
  50. data/lib/rdkafka/bindings.rb +582 -0
  51. data/lib/rdkafka/callbacks.rb +415 -0
  52. data/lib/rdkafka/config.rb +398 -0
  53. data/lib/rdkafka/consumer/headers.rb +79 -0
  54. data/lib/rdkafka/consumer/message.rb +86 -0
  55. data/lib/rdkafka/consumer/partition.rb +57 -0
  56. data/lib/rdkafka/consumer/topic_partition_list.rb +190 -0
  57. data/lib/rdkafka/consumer.rb +663 -0
  58. data/lib/rdkafka/error.rb +201 -0
  59. data/lib/rdkafka/helpers/oauth.rb +58 -0
  60. data/lib/rdkafka/helpers/time.rb +14 -0
  61. data/lib/rdkafka/metadata.rb +115 -0
  62. data/lib/rdkafka/native_kafka.rb +139 -0
  63. data/lib/rdkafka/producer/delivery_handle.rb +48 -0
  64. data/lib/rdkafka/producer/delivery_report.rb +45 -0
  65. data/lib/rdkafka/producer/partitions_count_cache.rb +216 -0
  66. data/lib/rdkafka/producer.rb +492 -0
  67. data/lib/rdkafka/version.rb +7 -0
  68. data/lib/rdkafka.rb +54 -0
  69. data/renovate.json +92 -0
  70. data/spec/rdkafka/abstract_handle_spec.rb +117 -0
  71. data/spec/rdkafka/admin/create_acl_handle_spec.rb +56 -0
  72. data/spec/rdkafka/admin/create_acl_report_spec.rb +18 -0
  73. data/spec/rdkafka/admin/create_topic_handle_spec.rb +54 -0
  74. data/spec/rdkafka/admin/create_topic_report_spec.rb +16 -0
  75. data/spec/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
  76. data/spec/rdkafka/admin/delete_acl_report_spec.rb +72 -0
  77. data/spec/rdkafka/admin/delete_topic_handle_spec.rb +54 -0
  78. data/spec/rdkafka/admin/delete_topic_report_spec.rb +16 -0
  79. data/spec/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
  80. data/spec/rdkafka/admin/describe_acl_report_spec.rb +73 -0
  81. data/spec/rdkafka/admin_spec.rb +769 -0
  82. data/spec/rdkafka/bindings_spec.rb +222 -0
  83. data/spec/rdkafka/callbacks_spec.rb +20 -0
  84. data/spec/rdkafka/config_spec.rb +258 -0
  85. data/spec/rdkafka/consumer/headers_spec.rb +73 -0
  86. data/spec/rdkafka/consumer/message_spec.rb +139 -0
  87. data/spec/rdkafka/consumer/partition_spec.rb +57 -0
  88. data/spec/rdkafka/consumer/topic_partition_list_spec.rb +248 -0
  89. data/spec/rdkafka/consumer_spec.rb +1299 -0
  90. data/spec/rdkafka/error_spec.rb +95 -0
  91. data/spec/rdkafka/metadata_spec.rb +79 -0
  92. data/spec/rdkafka/native_kafka_spec.rb +130 -0
  93. data/spec/rdkafka/producer/delivery_handle_spec.rb +60 -0
  94. data/spec/rdkafka/producer/delivery_report_spec.rb +25 -0
  95. data/spec/rdkafka/producer/partitions_count_cache_spec.rb +359 -0
  96. data/spec/rdkafka/producer/partitions_count_spec.rb +359 -0
  97. data/spec/rdkafka/producer_spec.rb +1234 -0
  98. data/spec/spec_helper.rb +181 -0
  99. metadata +244 -0
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Rdkafka::Consumer::Message do
4
+ let(:native_client) { new_native_client }
5
+ let(:native_topic) { new_native_topic(native_client: native_client) }
6
+ let(:payload) { nil }
7
+ let(:key) { nil }
8
+ let(:native_message) do
9
+ Rdkafka::Bindings::Message.new.tap do |message|
10
+ message[:rkt] = native_topic
11
+ message[:partition] = 3
12
+ message[:offset] = 100
13
+ if payload
14
+ ptr = FFI::MemoryPointer.new(:char, payload.bytesize)
15
+ ptr.put_bytes(0, payload)
16
+ message[:payload] = ptr
17
+ message[:len] = payload.bytesize
18
+ end
19
+ if key
20
+ ptr = FFI::MemoryPointer.new(:char, key.bytesize)
21
+ ptr.put_bytes(0, key)
22
+ message[:key] = ptr
23
+ message[:key_len] = key.bytesize
24
+ end
25
+ end
26
+ end
27
+
28
+ after(:each) do
29
+ Rdkafka::Bindings.rd_kafka_destroy(native_client)
30
+ end
31
+
32
+ subject { Rdkafka::Consumer::Message.new(native_message) }
33
+
34
+ before do
35
+ # mock headers, because it produces 'segmentation fault' while settings or reading headers for
36
+ # a message which is created from scratch
37
+ #
38
+ # Code dump example:
39
+ #
40
+ # ```
41
+ # frame #7: 0x000000010dacf5ab librdkafka.dylib`rd_list_destroy + 11
42
+ # frame #8: 0x000000010dae5a7e librdkafka.dylib`rd_kafka_headers_destroy + 14
43
+ # frame #9: 0x000000010da9ab40 librdkafka.dylib`rd_kafka_message_set_headers + 32
44
+ # ```
45
+ expect( Rdkafka::Bindings).to receive(:rd_kafka_message_headers).with(any_args) do
46
+ Rdkafka::Bindings::RD_KAFKA_RESP_ERR__NOENT
47
+ end
48
+ end
49
+
50
+ it "should have a topic" do
51
+ expect(subject.topic).to eq "topic_name"
52
+ end
53
+
54
+ it "should have a partition" do
55
+ expect(subject.partition).to eq 3
56
+ end
57
+
58
+ context "payload" do
59
+ it "should have a nil payload when none is present" do
60
+ expect(subject.payload).to be_nil
61
+ end
62
+
63
+ context "present payload" do
64
+ let(:payload) { "payload content" }
65
+
66
+ it "should have a payload" do
67
+ expect(subject.payload).to eq "payload content"
68
+ end
69
+ end
70
+ end
71
+
72
+ context "key" do
73
+ it "should have a nil key when none is present" do
74
+ expect(subject.key).to be_nil
75
+ end
76
+
77
+ context "present key" do
78
+ let(:key) { "key content" }
79
+
80
+ it "should have a key" do
81
+ expect(subject.key).to eq "key content"
82
+ end
83
+ end
84
+ end
85
+
86
+ it "should have an offset" do
87
+ expect(subject.offset).to eq 100
88
+ end
89
+
90
+ describe "#timestamp" do
91
+ context "without a timestamp" do
92
+ before do
93
+ allow(Rdkafka::Bindings).to receive(:rd_kafka_message_timestamp).and_return(-1)
94
+ end
95
+
96
+ it "should have a nil timestamp if not present" do
97
+ expect(subject.timestamp).to be_nil
98
+ end
99
+ end
100
+
101
+ context "with a timestamp" do
102
+ before do
103
+ allow(Rdkafka::Bindings).to receive(:rd_kafka_message_timestamp).and_return(1505069646250)
104
+ end
105
+
106
+ it "should have timestamp if present" do
107
+ expect(subject.timestamp).to eq Time.at(1505069646, 250_000)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "#to_s" do
113
+ before do
114
+ allow(subject).to receive(:timestamp).and_return(1000)
115
+ end
116
+
117
+ it "should have a human readable representation" do
118
+ expect(subject.to_s).to eq "<Message in 'topic_name' with key '', payload '', partition 3, offset 100, timestamp 1000>"
119
+ end
120
+
121
+ context "with key and payload" do
122
+ let(:key) { "key" }
123
+ let(:payload) { "payload" }
124
+
125
+ it "should have a human readable representation" do
126
+ expect(subject.to_s).to eq "<Message in 'topic_name' with key 'key', payload 'payload', partition 3, offset 100, timestamp 1000>"
127
+ end
128
+ end
129
+
130
+ context "with a very long key and payload" do
131
+ let(:key) { "k" * 100_000 }
132
+ let(:payload) { "p" * 100_000 }
133
+
134
+ it "should have a human readable representation" do
135
+ expect(subject.to_s).to eq "<Message in 'topic_name' with key 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk...', payload 'pppppppppppppppppppppppppppppppppppppppp...', partition 3, offset 100, timestamp 1000>"
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Rdkafka::Consumer::Partition do
4
+ let(:offset) { 100 }
5
+ let(:err) { 0 }
6
+ subject { Rdkafka::Consumer::Partition.new(1, offset, err) }
7
+
8
+ it "should have a partition" do
9
+ expect(subject.partition).to eq 1
10
+ end
11
+
12
+ it "should have an offset" do
13
+ expect(subject.offset).to eq 100
14
+ end
15
+
16
+ it "should have an err code" do
17
+ expect(subject.err).to eq 0
18
+ end
19
+
20
+ describe "#to_s" do
21
+ it "should return a human readable representation" do
22
+ expect(subject.to_s).to eq "<Partition 1 offset=100>"
23
+ end
24
+ end
25
+
26
+ describe "#inspect" do
27
+ it "should return a human readable representation" do
28
+ expect(subject.to_s).to eq "<Partition 1 offset=100>"
29
+ end
30
+
31
+ context "without offset" do
32
+ let(:offset) { nil }
33
+
34
+ it "should return a human readable representation" do
35
+ expect(subject.to_s).to eq "<Partition 1>"
36
+ end
37
+ end
38
+
39
+ context "with err code" do
40
+ let(:err) { 1 }
41
+
42
+ it "should return a human readable representation" do
43
+ expect(subject.to_s).to eq "<Partition 1 offset=100 err=1>"
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "#==" do
49
+ it "should equal another partition with the same content" do
50
+ expect(subject).to eq Rdkafka::Consumer::Partition.new(1, 100)
51
+ end
52
+
53
+ it "should not equal another partition with different content" do
54
+ expect(subject).not_to eq Rdkafka::Consumer::Partition.new(2, 101)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,248 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Rdkafka::Consumer::TopicPartitionList do
4
+ it "should create a new list and add unassigned topics" do
5
+ list = Rdkafka::Consumer::TopicPartitionList.new
6
+
7
+ expect(list.count).to eq 0
8
+ expect(list.empty?).to be true
9
+
10
+ list.add_topic("topic1")
11
+ list.add_topic("topic2")
12
+
13
+ expect(list.count).to eq 2
14
+ expect(list.empty?).to be false
15
+
16
+ hash = list.to_h
17
+ expect(hash.count).to eq 2
18
+ expect(hash).to eq ({
19
+ "topic1" => nil,
20
+ "topic2" => nil
21
+ })
22
+ end
23
+
24
+ it "should create a new list and add assigned topics as a range" do
25
+ list = Rdkafka::Consumer::TopicPartitionList.new
26
+
27
+ expect(list.count).to eq 0
28
+ expect(list.empty?).to be true
29
+
30
+ list.add_topic("topic1", (0..2))
31
+ list.add_topic("topic2", (0..1))
32
+
33
+ expect(list.count).to eq 5
34
+ expect(list.empty?).to be false
35
+
36
+ hash = list.to_h
37
+ expect(hash.count).to eq 2
38
+ expect(hash["topic1"]).to eq([
39
+ Rdkafka::Consumer::Partition.new(0, nil),
40
+ Rdkafka::Consumer::Partition.new(1, nil),
41
+ Rdkafka::Consumer::Partition.new(2, nil)
42
+ ])
43
+ expect(hash["topic2"]).to eq([
44
+ Rdkafka::Consumer::Partition.new(0, nil),
45
+ Rdkafka::Consumer::Partition.new(1, nil)
46
+ ])
47
+ end
48
+
49
+ it "should create a new list and add assigned topics as an array" do
50
+ list = Rdkafka::Consumer::TopicPartitionList.new
51
+
52
+ expect(list.count).to eq 0
53
+ expect(list.empty?).to be true
54
+
55
+ list.add_topic("topic1", [0, 1, 2])
56
+ list.add_topic("topic2", [0, 1])
57
+
58
+ expect(list.count).to eq 5
59
+ expect(list.empty?).to be false
60
+
61
+ hash = list.to_h
62
+ expect(hash.count).to eq 2
63
+ expect(hash["topic1"]).to eq([
64
+ Rdkafka::Consumer::Partition.new(0, nil),
65
+ Rdkafka::Consumer::Partition.new(1, nil),
66
+ Rdkafka::Consumer::Partition.new(2, nil)
67
+ ])
68
+ expect(hash["topic2"]).to eq([
69
+ Rdkafka::Consumer::Partition.new(0, nil),
70
+ Rdkafka::Consumer::Partition.new(1, nil)
71
+ ])
72
+ end
73
+
74
+ it "should create a new list and add assigned topics as a count" do
75
+ list = Rdkafka::Consumer::TopicPartitionList.new
76
+
77
+ expect(list.count).to eq 0
78
+ expect(list.empty?).to be true
79
+
80
+ list.add_topic("topic1", 3)
81
+ list.add_topic("topic2", 2)
82
+
83
+ expect(list.count).to eq 5
84
+ expect(list.empty?).to be false
85
+
86
+ hash = list.to_h
87
+ expect(hash.count).to eq 2
88
+ expect(hash["topic1"]).to eq([
89
+ Rdkafka::Consumer::Partition.new(0, nil),
90
+ Rdkafka::Consumer::Partition.new(1, nil),
91
+ Rdkafka::Consumer::Partition.new(2, nil)
92
+ ])
93
+ expect(hash["topic2"]).to eq([
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)
113
+ ])
114
+ end
115
+
116
+ describe "#to_s" do
117
+ let(:expected) do
118
+ if RUBY_VERSION >= '3.4.0'
119
+ "<TopicPartitionList: {\"topic1\" => [<Partition 0>, <Partition 1>]}>"
120
+ else
121
+ "<TopicPartitionList: {\"topic1\"=>[<Partition 0>, <Partition 1>]}>"
122
+ end
123
+ end
124
+
125
+ it "should return a human readable representation" do
126
+ list = Rdkafka::Consumer::TopicPartitionList.new
127
+ list.add_topic("topic1", [0, 1])
128
+
129
+ expect(list.to_s).to eq expected
130
+ end
131
+ end
132
+
133
+ describe "#==" do
134
+ subject do
135
+ Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
136
+ list.add_topic("topic1", [0])
137
+ end
138
+ end
139
+
140
+ it "should equal another partition with the same content" do
141
+ other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
142
+ list.add_topic("topic1", [0])
143
+ end
144
+ expect(subject).to eq other
145
+ end
146
+
147
+ it "should not equal another partition with different content" do
148
+ expect(subject).not_to eq Rdkafka::Consumer::TopicPartitionList.new
149
+ end
150
+ end
151
+
152
+ describe ".from_native_tpl" do
153
+ it "should create a list from an existing native list" do
154
+ pointer = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5)
155
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
156
+ pointer,
157
+ "topic",
158
+ -1
159
+ )
160
+ list = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(pointer)
161
+
162
+ other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
163
+ list.add_topic("topic")
164
+ end
165
+
166
+ expect(list).to eq other
167
+ end
168
+
169
+ it "should create a list from an existing native list with offsets" do
170
+ pointer = Rdkafka::Bindings.rd_kafka_topic_partition_list_new(5)
171
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_add(
172
+ pointer,
173
+ "topic",
174
+ 0
175
+ )
176
+ Rdkafka::Bindings.rd_kafka_topic_partition_list_set_offset(
177
+ pointer,
178
+ "topic",
179
+ 0,
180
+ 100
181
+ )
182
+ list = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(pointer)
183
+
184
+ other = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
185
+ list.add_topic_and_partitions_with_offsets("topic", 0 => 100)
186
+ end
187
+
188
+ expect(list).to eq other
189
+ end
190
+ end
191
+
192
+ describe "#to_native_tpl" do
193
+ it "should create a native list" do
194
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
195
+ list.add_topic("topic")
196
+ end
197
+
198
+ tpl = list.to_native_tpl
199
+
200
+ other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
201
+
202
+ expect(list).to eq other
203
+ end
204
+
205
+ it "should create a native list with partitions" do
206
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
207
+ list.add_topic("topic", 0..16)
208
+ end
209
+
210
+ tpl = list.to_native_tpl
211
+
212
+ other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
213
+
214
+ expect(list).to eq other
215
+ end
216
+
217
+ it "should create a native list with offsets" do
218
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
219
+ list.add_topic_and_partitions_with_offsets("topic", 0 => 100)
220
+ end
221
+
222
+ tpl = list.to_native_tpl
223
+
224
+ other = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
225
+
226
+ expect(list).to eq other
227
+ end
228
+
229
+ it "should create a native list with timetamp offsets if offsets are Time" do
230
+ list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
231
+ list.add_topic_and_partitions_with_offsets("topic", 0 => Time.at(1505069646, 250_000))
232
+ end
233
+
234
+ tpl = list.to_native_tpl
235
+
236
+ compare_list = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
237
+ list.add_topic_and_partitions_with_offsets(
238
+ "topic",
239
+ 0 => (Time.at(1505069646, 250_000).to_f * 1000).floor
240
+ )
241
+ end
242
+
243
+ native_list = Rdkafka::Consumer::TopicPartitionList.from_native_tpl(tpl)
244
+
245
+ expect(native_list).to eq compare_list
246
+ end
247
+ end
248
+ end