rdkafka 0.16.0.beta1 → 0.16.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.
@@ -16,12 +16,12 @@ describe Rdkafka::Admin do
16
16
  admin.close
17
17
  end
18
18
 
19
- let(:topic_name) { "test-topic-#{Random.new.rand(0..1_000_000)}" }
19
+ let(:topic_name) { "test-topic-#{SecureRandom.uuid}" }
20
20
  let(:topic_partition_count) { 3 }
21
21
  let(:topic_replication_factor) { 1 }
22
22
  let(:topic_config) { {"cleanup.policy" => "compact", "min.cleanable.dirty.ratio" => 0.8} }
23
23
  let(:invalid_topic_config) { {"cleeeeenup.policee" => "campact"} }
24
- let(:group_name) { "test-group-#{Random.new.rand(0..1_000_000)}" }
24
+ let(:group_name) { "test-group-#{SecureRandom.uuid}" }
25
25
 
26
26
  let(:resource_name) {"acl-test-topic"}
27
27
  let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
@@ -31,6 +31,14 @@ describe Rdkafka::Admin do
31
31
  let(:operation) {Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ}
32
32
  let(:permission_type) {Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW}
33
33
 
34
+ describe '#describe_errors' do
35
+ let(:errors) { admin.class.describe_errors }
36
+
37
+ it { expect(errors.size).to eq(162) }
38
+ it { expect(errors[-184]).to eq(code: -184, description: 'Local: Queue full', name: '_QUEUE_FULL') }
39
+ it { expect(errors[21]).to eq(code: 21, description: 'Broker: Invalid required acks value', name: 'INVALID_REQUIRED_ACKS') }
40
+ end
41
+
34
42
  describe 'admin without auto-start' do
35
43
  let(:admin) { config.admin(native_kafka_auto_start: false) }
36
44
 
@@ -142,6 +150,275 @@ expect(ex.broker_message).to match(/Topic name.*is invalid: .* contains one or m
142
150
  end
143
151
  end
144
152
 
153
+ describe "describe_configs" do
154
+ subject(:resources_results) { admin.describe_configs(resources).wait.resources }
155
+
156
+ before do
157
+ admin.create_topic(topic_name, 2, 1).wait
158
+ sleep(1)
159
+ end
160
+
161
+ context 'when describing config of an existing topic' do
162
+ let(:resources) { [{ resource_type: 2, resource_name: topic_name }] }
163
+
164
+ it do
165
+ expect(resources_results.size).to eq(1)
166
+ expect(resources_results.first.type).to eq(2)
167
+ expect(resources_results.first.name).to eq(topic_name)
168
+ expect(resources_results.first.configs.size).to be > 25
169
+ expect(resources_results.first.configs.first.name).to eq('compression.type')
170
+ expect(resources_results.first.configs.first.value).to eq('producer')
171
+ expect(resources_results.first.configs.map(&:synonyms)).not_to be_empty
172
+ end
173
+ end
174
+
175
+ context 'when describing config of a non-existing topic' do
176
+ let(:resources) { [{ resource_type: 2, resource_name: SecureRandom.uuid }] }
177
+
178
+ it 'expect to raise error' do
179
+ expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /unknown_topic_or_part/)
180
+ end
181
+ end
182
+
183
+ context 'when describing both existing and non-existing topics' do
184
+ let(:resources) do
185
+ [
186
+ { resource_type: 2, resource_name: topic_name },
187
+ { resource_type: 2, resource_name: SecureRandom.uuid }
188
+ ]
189
+ end
190
+
191
+ it 'expect to raise error' do
192
+ expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /unknown_topic_or_part/)
193
+ end
194
+ end
195
+
196
+ context 'when describing multiple existing topics' do
197
+ let(:resources) do
198
+ [
199
+ { resource_type: 2, resource_name: 'example_topic' },
200
+ { resource_type: 2, resource_name: topic_name }
201
+ ]
202
+ end
203
+
204
+ it do
205
+ expect(resources_results.size).to eq(2)
206
+ expect(resources_results.first.type).to eq(2)
207
+ expect(resources_results.first.name).to eq('example_topic')
208
+ expect(resources_results.last.type).to eq(2)
209
+ expect(resources_results.last.name).to eq(topic_name)
210
+ end
211
+ end
212
+
213
+ context 'when trying to describe invalid resource type' do
214
+ let(:resources) { [{ resource_type: 0, resource_name: SecureRandom.uuid }] }
215
+
216
+ it 'expect to raise error' do
217
+ expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_request/)
218
+ end
219
+ end
220
+
221
+ context 'when trying to describe invalid broker' do
222
+ let(:resources) { [{ resource_type: 4, resource_name: 'non-existing' }] }
223
+
224
+ it 'expect to raise error' do
225
+ expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_arg/)
226
+ end
227
+ end
228
+
229
+ context 'when trying to describe valid broker' do
230
+ let(:resources) { [{ resource_type: 4, resource_name: '1' }] }
231
+
232
+ it do
233
+ expect(resources_results.size).to eq(1)
234
+ expect(resources_results.first.type).to eq(4)
235
+ expect(resources_results.first.name).to eq('1')
236
+ expect(resources_results.first.configs.size).to be > 230
237
+ expect(resources_results.first.configs.first.name).to eq('log.cleaner.min.compaction.lag.ms')
238
+ expect(resources_results.first.configs.first.value).to eq('0')
239
+ expect(resources_results.first.configs.map(&:synonyms)).not_to be_empty
240
+ end
241
+ end
242
+
243
+ context 'when describing valid broker with topics in one request' do
244
+ let(:resources) do
245
+ [
246
+ { resource_type: 4, resource_name: '1' },
247
+ { resource_type: 2, resource_name: topic_name }
248
+ ]
249
+ end
250
+
251
+ it do
252
+ expect(resources_results.size).to eq(2)
253
+ expect(resources_results.first.type).to eq(4)
254
+ expect(resources_results.first.name).to eq('1')
255
+ expect(resources_results.first.configs.size).to be > 230
256
+ expect(resources_results.first.configs.first.name).to eq('log.cleaner.min.compaction.lag.ms')
257
+ expect(resources_results.first.configs.first.value).to eq('0')
258
+ expect(resources_results.last.type).to eq(2)
259
+ expect(resources_results.last.name).to eq(topic_name)
260
+ expect(resources_results.last.configs.size).to be > 25
261
+ expect(resources_results.last.configs.first.name).to eq('compression.type')
262
+ expect(resources_results.last.configs.first.value).to eq('producer')
263
+ end
264
+ end
265
+ end
266
+
267
+ describe "incremental_alter_configs" do
268
+ subject(:resources_results) { admin.incremental_alter_configs(resources_with_configs).wait.resources }
269
+
270
+ before do
271
+ admin.create_topic(topic_name, 2, 1).wait
272
+ sleep(1)
273
+ end
274
+
275
+ context 'when altering one topic with one valid config via set' do
276
+ let(:target_retention) { (86400002 + rand(10_000)).to_s }
277
+ let(:resources_with_configs) do
278
+ [
279
+ {
280
+ resource_type: 2,
281
+ resource_name: topic_name,
282
+ configs: [
283
+ {
284
+ name: 'delete.retention.ms',
285
+ value: target_retention,
286
+ op_type: 0
287
+ }
288
+ ]
289
+ }
290
+ ]
291
+ end
292
+
293
+ it do
294
+ expect(resources_results.size).to eq(1)
295
+ expect(resources_results.first.type).to eq(2)
296
+ expect(resources_results.first.name).to eq(topic_name)
297
+
298
+ ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
299
+ config.name == 'delete.retention.ms'
300
+ end
301
+
302
+ expect(ret_config.value).to eq(target_retention)
303
+ end
304
+ end
305
+
306
+ context 'when altering one topic with one valid config via delete' do
307
+ let(:target_retention) { (8640002 + rand(10_000)).to_s }
308
+ let(:resources_with_configs) do
309
+ [
310
+ {
311
+ resource_type: 2,
312
+ resource_name: topic_name,
313
+ configs: [
314
+ {
315
+ name: 'delete.retention.ms',
316
+ value: target_retention,
317
+ op_type: 1
318
+ }
319
+ ]
320
+ }
321
+ ]
322
+ end
323
+
324
+ it do
325
+ expect(resources_results.size).to eq(1)
326
+ expect(resources_results.first.type).to eq(2)
327
+ expect(resources_results.first.name).to eq(topic_name)
328
+ ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
329
+ config.name == 'delete.retention.ms'
330
+ end
331
+
332
+ expect(ret_config.value).to eq('86400000')
333
+ end
334
+ end
335
+
336
+ context 'when altering one topic with one valid config via append' do
337
+ let(:target_policy) { 'compact' }
338
+ let(:resources_with_configs) do
339
+ [
340
+ {
341
+ resource_type: 2,
342
+ resource_name: topic_name,
343
+ configs: [
344
+ {
345
+ name: 'cleanup.policy',
346
+ value: target_policy,
347
+ op_type: 2
348
+ }
349
+ ]
350
+ }
351
+ ]
352
+ end
353
+
354
+ it do
355
+ expect(resources_results.size).to eq(1)
356
+ expect(resources_results.first.type).to eq(2)
357
+ expect(resources_results.first.name).to eq(topic_name)
358
+
359
+ ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
360
+ config.name == 'cleanup.policy'
361
+ end
362
+
363
+ expect(ret_config.value).to eq("delete,#{target_policy}")
364
+ end
365
+ end
366
+
367
+ context 'when altering one topic with one valid config via subtrack' do
368
+ let(:target_policy) { 'delete' }
369
+ let(:resources_with_configs) do
370
+ [
371
+ {
372
+ resource_type: 2,
373
+ resource_name: topic_name,
374
+ configs: [
375
+ {
376
+ name: 'cleanup.policy',
377
+ value: target_policy,
378
+ op_type: 3
379
+ }
380
+ ]
381
+ }
382
+ ]
383
+ end
384
+
385
+ it do
386
+ expect(resources_results.size).to eq(1)
387
+ expect(resources_results.first.type).to eq(2)
388
+ expect(resources_results.first.name).to eq(topic_name)
389
+
390
+ ret_config = admin.describe_configs(resources_with_configs).wait.resources.first.configs.find do |config|
391
+ config.name == 'cleanup.policy'
392
+ end
393
+
394
+ expect(ret_config.value).to eq('')
395
+ end
396
+ end
397
+
398
+ context 'when altering one topic with invalid config' do
399
+ let(:target_retention) { '-10' }
400
+ let(:resources_with_configs) do
401
+ [
402
+ {
403
+ resource_type: 2,
404
+ resource_name: topic_name,
405
+ configs: [
406
+ {
407
+ name: 'delete.retention.ms',
408
+ value: target_retention,
409
+ op_type: 0
410
+ }
411
+ ]
412
+ }
413
+ ]
414
+ end
415
+
416
+ it 'expect to raise error' do
417
+ expect { resources_results }.to raise_error(Rdkafka::RdkafkaError, /invalid_config/)
418
+ end
419
+ end
420
+ end
421
+
145
422
  describe "#delete_topic" do
146
423
  describe "called with invalid input" do
147
424
  # https://github.com/apache/kafka/blob/trunk/clients/src/main/java/org/apache/kafka/common/internals/Topic.java#L29
@@ -412,7 +689,10 @@ expect(ex.broker_message).to match(/Topic name.*is invalid: .* contains one or m
412
689
  end
413
690
 
414
691
  context 'when topic has less then desired number of partitions' do
415
- before { admin.create_topic(topic_name, 1, 1).wait }
692
+ before do
693
+ admin.create_topic(topic_name, 1, 1).wait
694
+ sleep(1)
695
+ end
416
696
 
417
697
  it 'expect to change number of partitions' do
418
698
  admin.create_partitions(topic_name, 10).wait
@@ -50,11 +50,8 @@ describe Rdkafka::Consumer::Headers do
50
50
  expect(subject['version']).to eq("2.1.3")
51
51
  end
52
52
 
53
- it 'allows Symbol key, but warns' do
54
- expect(Kernel).to \
55
- receive(:warn).with("rdkafka deprecation warning: header access with Symbol key :version treated as a String. " \
56
- "Please change your code to use String keys to avoid this warning. Symbol keys will break in version 1.")
57
- expect(subject[:version]).to eq("2.1.3")
53
+ it 'does not support symbols mappings' do
54
+ expect(subject.key?(:version)).to eq(false)
58
55
  end
59
56
  end
60
57
  end
@@ -9,7 +9,7 @@ describe Rdkafka::Producer::DeliveryHandle do
9
9
  handle[:response] = response
10
10
  handle[:partition] = 2
11
11
  handle[:offset] = 100
12
- handle[:topic_name] = FFI::MemoryPointer.from_string("produce_test_topic")
12
+ handle.topic = "produce_test_topic"
13
13
  end
14
14
  end
15
15
 
@@ -31,6 +31,48 @@ describe Rdkafka::Producer do
31
31
  it { expect(producer.name).to include('rdkafka#producer-') }
32
32
  end
33
33
 
34
+ describe '#produce with topic config alterations' do
35
+ context 'when config is not valid' do
36
+ it 'expect to raise error' do
37
+ expect do
38
+ producer.produce(topic: 'test', payload: '', topic_config: { 'invalid': 'invalid' })
39
+ end.to raise_error(Rdkafka::Config::ConfigError)
40
+ end
41
+ end
42
+
43
+ context 'when config is valid' do
44
+ it 'expect to raise error' do
45
+ expect do
46
+ producer.produce(topic: 'test', payload: '', topic_config: { 'acks': 1 }).wait
47
+ end.not_to raise_error
48
+ end
49
+
50
+ context 'when alteration should change behavior' do
51
+ # This is set incorrectly for a reason
52
+ # If alteration would not work, this will hang the spec suite
53
+ let(:producer) do
54
+ rdkafka_producer_config(
55
+ 'message.timeout.ms': 1_000_000,
56
+ :"bootstrap.servers" => "localhost:9094",
57
+ ).producer
58
+ end
59
+
60
+ it 'expect to give up on delivery fast based on alteration config' do
61
+ expect do
62
+ producer.produce(
63
+ topic: 'produce_config_test',
64
+ payload: 'test',
65
+ topic_config: {
66
+ 'compression.type': 'gzip',
67
+ 'message.timeout.ms': 1
68
+ }
69
+ ).wait
70
+ end.to raise_error(Rdkafka::RdkafkaError, /msg_timed_out/)
71
+ end
72
+ end
73
+ end
74
+ end
75
+
34
76
  context "delivery callback" do
35
77
  context "with a proc/lambda" do
36
78
  it "should set the callback" do
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rdkafka
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0.beta1
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
@@ -36,7 +36,7 @@ cert_chain:
36
36
  AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
37
37
  msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
38
38
  -----END CERTIFICATE-----
39
- date: 2024-04-29 00:00:00.000000000 Z
39
+ date: 2024-06-13 00:00:00.000000000 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: ffi
@@ -193,6 +193,8 @@ files:
193
193
  - lib/rdkafka/abstract_handle.rb
194
194
  - lib/rdkafka/admin.rb
195
195
  - lib/rdkafka/admin/acl_binding_result.rb
196
+ - lib/rdkafka/admin/config_binding_result.rb
197
+ - lib/rdkafka/admin/config_resource_binding_result.rb
196
198
  - lib/rdkafka/admin/create_acl_handle.rb
197
199
  - lib/rdkafka/admin/create_acl_report.rb
198
200
  - lib/rdkafka/admin/create_partitions_handle.rb
@@ -207,6 +209,10 @@ files:
207
209
  - lib/rdkafka/admin/delete_topic_report.rb
208
210
  - lib/rdkafka/admin/describe_acl_handle.rb
209
211
  - lib/rdkafka/admin/describe_acl_report.rb
212
+ - lib/rdkafka/admin/describe_configs_handle.rb
213
+ - lib/rdkafka/admin/describe_configs_report.rb
214
+ - lib/rdkafka/admin/incremental_alter_configs_handle.rb
215
+ - lib/rdkafka/admin/incremental_alter_configs_report.rb
210
216
  - lib/rdkafka/bindings.rb
211
217
  - lib/rdkafka/callbacks.rb
212
218
  - lib/rdkafka/config.rb
@@ -272,14 +278,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
272
278
  requirements:
273
279
  - - ">="
274
280
  - !ruby/object:Gem::Version
275
- version: '2.7'
281
+ version: '3.0'
276
282
  required_rubygems_version: !ruby/object:Gem::Requirement
277
283
  requirements:
278
284
  - - ">="
279
285
  - !ruby/object:Gem::Version
280
286
  version: '0'
281
287
  requirements: []
282
- rubygems_version: 3.5.9
288
+ rubygems_version: 3.5.11
283
289
  signing_key:
284
290
  specification_version: 4
285
291
  summary: The rdkafka gem is a modern Kafka client library for Ruby based on librdkafka.
metadata.gz.sig CHANGED
Binary file