rdkafka 0.14.0 → 0.15.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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/FUNDING.yml +1 -0
  4. data/CHANGELOG.md +11 -0
  5. data/README.md +32 -22
  6. data/docker-compose.yml +2 -0
  7. data/lib/rdkafka/admin/acl_binding_result.rb +37 -0
  8. data/lib/rdkafka/admin/create_acl_handle.rb +28 -0
  9. data/lib/rdkafka/admin/create_acl_report.rb +24 -0
  10. data/lib/rdkafka/admin/create_partitions_handle.rb +27 -0
  11. data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
  12. data/lib/rdkafka/admin/delete_acl_handle.rb +30 -0
  13. data/lib/rdkafka/admin/delete_acl_report.rb +23 -0
  14. data/lib/rdkafka/admin/delete_groups_handle.rb +28 -0
  15. data/lib/rdkafka/admin/delete_groups_report.rb +24 -0
  16. data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
  17. data/lib/rdkafka/admin/describe_acl_report.rb +23 -0
  18. data/lib/rdkafka/admin.rb +443 -0
  19. data/lib/rdkafka/bindings.rb +119 -0
  20. data/lib/rdkafka/callbacks.rb +187 -0
  21. data/lib/rdkafka/config.rb +24 -3
  22. data/lib/rdkafka/consumer/headers.rb +1 -1
  23. data/lib/rdkafka/consumer/topic_partition_list.rb +8 -7
  24. data/lib/rdkafka/consumer.rb +46 -10
  25. data/lib/rdkafka/producer.rb +2 -2
  26. data/lib/rdkafka/version.rb +3 -3
  27. data/lib/rdkafka.rb +11 -0
  28. data/spec/rdkafka/admin/create_acl_handle_spec.rb +56 -0
  29. data/spec/rdkafka/admin/create_acl_report_spec.rb +18 -0
  30. data/spec/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
  31. data/spec/rdkafka/admin/delete_acl_report_spec.rb +71 -0
  32. data/spec/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
  33. data/spec/rdkafka/admin/describe_acl_report_spec.rb +72 -0
  34. data/spec/rdkafka/admin_spec.rb +204 -0
  35. data/spec/rdkafka/config_spec.rb +8 -0
  36. data/spec/rdkafka/consumer_spec.rb +69 -0
  37. data/spec/spec_helper.rb +3 -1
  38. data.tar.gz.sig +0 -0
  39. metadata +26 -2
  40. metadata.gz.sig +0 -0
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Rdkafka::Admin::DeleteAclReport do
6
+
7
+ let(:resource_name) {"acl-test-topic"}
8
+ let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
9
+ let(:resource_pattern_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL}
10
+ let(:principal) {"User:anonymous"}
11
+ let(:host) {"*"}
12
+ let(:operation) {Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ}
13
+ let(:permission_type) {Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW}
14
+ let(:delete_acl_ptr) {FFI::Pointer::NULL}
15
+
16
+ subject do
17
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
18
+ delete_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBinding_new(
19
+ resource_type,
20
+ FFI::MemoryPointer.from_string(resource_name),
21
+ resource_pattern_type,
22
+ FFI::MemoryPointer.from_string(principal),
23
+ FFI::MemoryPointer.from_string(host),
24
+ operation,
25
+ permission_type,
26
+ error_buffer,
27
+ 256
28
+ )
29
+ if delete_acl_ptr.null?
30
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
31
+ end
32
+ pointer_array = [delete_acl_ptr]
33
+ delete_acls_array_ptr = FFI::MemoryPointer.new(:pointer)
34
+ delete_acls_array_ptr.write_array_of_pointer(pointer_array)
35
+ Rdkafka::Admin::DeleteAclReport.new(matching_acls: delete_acls_array_ptr, matching_acls_count: 1)
36
+ end
37
+
38
+ after do
39
+ if delete_acl_ptr != FFI::Pointer::NULL
40
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(delete_acl_ptr)
41
+ end
42
+ end
43
+
44
+ it "should get deleted acl resource type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC" do
45
+ expect(subject.deleted_acls[0].matching_acl_resource_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC)
46
+ end
47
+
48
+ it "should get deleted acl resource name as acl-test-topic" do
49
+ expect(subject.deleted_acls[0].matching_acl_resource_name).to eq(resource_name)
50
+ end
51
+
52
+ it "should get deleted acl resource pattern type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL" do
53
+ expect(subject.deleted_acls[0].matching_acl_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
54
+ end
55
+
56
+ it "should get deleted acl principal as User:anonymous" do
57
+ expect(subject.deleted_acls[0].matching_acl_principal).to eq("User:anonymous")
58
+ end
59
+
60
+ it "should get deleted acl host as * " do
61
+ expect(subject.deleted_acls[0].matching_acl_host).to eq("*")
62
+ end
63
+
64
+ it "should get deleted acl operation as Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ" do
65
+ expect(subject.deleted_acls[0].matching_acl_operation).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ)
66
+ end
67
+
68
+ it "should get deleted acl permission_type as Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW" do
69
+ expect(subject.deleted_acls[0].matching_acl_permission_type).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW)
70
+ end
71
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Rdkafka::Admin::DescribeAclHandle do
6
+ let(:response) { Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR }
7
+ let(:resource_name) {"acl-test-topic"}
8
+ let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
9
+ let(:resource_pattern_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL}
10
+ let(:principal) {"User:anonymous"}
11
+ let(:host) {"*"}
12
+ let(:operation) {Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ}
13
+ let(:permission_type) {Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW}
14
+ let(:describe_acl_ptr) {FFI::Pointer::NULL}
15
+
16
+ subject do
17
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
18
+ describe_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBinding_new(
19
+ resource_type,
20
+ FFI::MemoryPointer.from_string(resource_name),
21
+ resource_pattern_type,
22
+ FFI::MemoryPointer.from_string(principal),
23
+ FFI::MemoryPointer.from_string(host),
24
+ operation,
25
+ permission_type,
26
+ error_buffer,
27
+ 256
28
+ )
29
+ if describe_acl_ptr.null?
30
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
31
+ end
32
+ pointer_array = [describe_acl_ptr]
33
+ describe_acls_array_ptr = FFI::MemoryPointer.new(:pointer)
34
+ describe_acls_array_ptr.write_array_of_pointer(pointer_array)
35
+ Rdkafka::Admin::DescribeAclHandle.new.tap do |handle|
36
+ handle[:pending] = pending_handle
37
+ handle[:response] = response
38
+ handle[:response_string] = FFI::MemoryPointer.from_string("")
39
+ handle[:acls] = describe_acls_array_ptr
40
+ handle[:acls_count] = 1
41
+ end
42
+ end
43
+
44
+ after do
45
+ if describe_acl_ptr != FFI::Pointer::NULL
46
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(describe_acl_ptr)
47
+ end
48
+ end
49
+
50
+ describe "#wait" do
51
+ let(:pending_handle) { true }
52
+
53
+ it "should wait until the timeout and then raise an error" do
54
+ expect {
55
+ subject.wait(max_wait_timeout: 0.1)
56
+ }.to raise_error Rdkafka::Admin::DescribeAclHandle::WaitTimeoutError, /describe acl/
57
+ end
58
+
59
+ context "when not pending anymore and no error" do
60
+ let(:pending_handle) { false }
61
+
62
+ it "should return a describe acl report" do
63
+ report = subject.wait
64
+
65
+ expect(report.acls.length).to eq(1)
66
+ end
67
+
68
+ it "should wait without a timeout" do
69
+ report = subject.wait(max_wait_timeout: nil)
70
+
71
+ expect(report.acls[0].matching_acl_resource_name).to eq("acl-test-topic")
72
+ end
73
+ end
74
+ end
75
+
76
+ describe "#raise_error" do
77
+ let(:pending_handle) { false }
78
+
79
+ it "should raise the appropriate error" do
80
+ expect {
81
+ subject.raise_error
82
+ }.to raise_exception(Rdkafka::RdkafkaError, /Success \(no_error\)/)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ describe Rdkafka::Admin::DescribeAclReport do
6
+
7
+ let(:resource_name) {"acl-test-topic"}
8
+ let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
9
+ let(:resource_pattern_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL}
10
+ let(:principal) {"User:anonymous"}
11
+ let(:host) {"*"}
12
+ let(:operation) {Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ}
13
+ let(:permission_type) {Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW}
14
+ let(:describe_acl_ptr) {FFI::Pointer::NULL}
15
+
16
+ subject do
17
+ error_buffer = FFI::MemoryPointer.from_string(" " * 256)
18
+ describe_acl_ptr = Rdkafka::Bindings.rd_kafka_AclBinding_new(
19
+ resource_type,
20
+ FFI::MemoryPointer.from_string(resource_name),
21
+ resource_pattern_type,
22
+ FFI::MemoryPointer.from_string(principal),
23
+ FFI::MemoryPointer.from_string(host),
24
+ operation,
25
+ permission_type,
26
+ error_buffer,
27
+ 256
28
+ )
29
+ if describe_acl_ptr.null?
30
+ raise Rdkafka::Config::ConfigError.new(error_buffer.read_string)
31
+ end
32
+ pointer_array = [describe_acl_ptr]
33
+ describe_acls_array_ptr = FFI::MemoryPointer.new(:pointer)
34
+ describe_acls_array_ptr.write_array_of_pointer(pointer_array)
35
+ Rdkafka::Admin::DescribeAclReport.new(acls: describe_acls_array_ptr, acls_count: 1)
36
+ end
37
+
38
+ after do
39
+ if describe_acl_ptr != FFI::Pointer::NULL
40
+ Rdkafka::Bindings.rd_kafka_AclBinding_destroy(describe_acl_ptr)
41
+ end
42
+ end
43
+
44
+
45
+ it "should get matching acl resource type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC" do
46
+ expect(subject.acls[0].matching_acl_resource_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC)
47
+ end
48
+
49
+ it "should get matching acl resource name as acl-test-topic" do
50
+ expect(subject.acls[0].matching_acl_resource_name).to eq(resource_name)
51
+ end
52
+
53
+ it "should get matching acl resource pattern type as Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL" do
54
+ expect(subject.acls[0].matching_acl_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
55
+ end
56
+
57
+ it "should get matching acl principal as User:anonymous" do
58
+ expect(subject.acls[0].matching_acl_principal).to eq("User:anonymous")
59
+ end
60
+
61
+ it "should get matching acl host as * " do
62
+ expect(subject.acls[0].matching_acl_host).to eq("*")
63
+ end
64
+
65
+ it "should get matching acl operation as Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ" do
66
+ expect(subject.acls[0].matching_acl_operation).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ)
67
+ end
68
+
69
+ it "should get matching acl permission_type as Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW" do
70
+ expect(subject.acls[0].matching_acl_permission_type).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW)
71
+ end
72
+ end
@@ -9,6 +9,10 @@ describe Rdkafka::Admin do
9
9
  after do
10
10
  # Registry should always end up being empty
11
11
  expect(Rdkafka::Admin::CreateTopicHandle::REGISTRY).to be_empty
12
+ expect(Rdkafka::Admin::CreatePartitionsHandle::REGISTRY).to be_empty
13
+ expect(Rdkafka::Admin::DescribeAclHandle::REGISTRY).to be_empty
14
+ expect(Rdkafka::Admin::CreateAclHandle::REGISTRY).to be_empty
15
+ expect(Rdkafka::Admin::DeleteAclHandle::REGISTRY).to be_empty
12
16
  admin.close
13
17
  end
14
18
 
@@ -17,6 +21,15 @@ describe Rdkafka::Admin do
17
21
  let(:topic_replication_factor) { 1 }
18
22
  let(:topic_config) { {"cleanup.policy" => "compact", "min.cleanable.dirty.ratio" => 0.8} }
19
23
  let(:invalid_topic_config) { {"cleeeeenup.policee" => "campact"} }
24
+ let(:group_name) { "test-group-#{Random.new.rand(0..1_000_000)}" }
25
+
26
+ let(:resource_name) {"acl-test-topic"}
27
+ let(:resource_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_TOPIC}
28
+ let(:resource_pattern_type) {Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL}
29
+ let(:principal) {"User:anonymous"}
30
+ let(:host) {"*"}
31
+ let(:operation) {Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ}
32
+ let(:permission_type) {Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW}
20
33
 
21
34
  describe "#create_topic" do
22
35
  describe "called with invalid input" do
@@ -200,4 +213,195 @@ expect(ex.broker_message).to match(/Topic name.*is invalid: .* contains one or m
200
213
  expect(delete_topic_report.result_name).to eq(topic_name)
201
214
  end
202
215
  end
216
+
217
+ describe "#ACL tests" do
218
+ let(:non_existing_resource_name) {"non-existing-topic"}
219
+ before do
220
+ #create topic for testing acl
221
+ create_topic_handle = admin.create_topic(resource_name, topic_partition_count, topic_replication_factor)
222
+ create_topic_report = create_topic_handle.wait(max_wait_timeout: 15.0)
223
+ end
224
+
225
+ after do
226
+ #delete acl
227
+ delete_acl_handle = admin.delete_acl(resource_type: resource_type, resource_name: resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
228
+ delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
229
+
230
+ #delete topic that was created for testing acl
231
+ delete_topic_handle = admin.delete_topic(resource_name)
232
+ delete_topic_report = delete_topic_handle.wait(max_wait_timeout: 15.0)
233
+ end
234
+
235
+ describe "#create_acl" do
236
+ it "create acl for a topic that does not exist" do
237
+ # acl creation for resources that does not exist will still get created successfully.
238
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: non_existing_resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
239
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
240
+ expect(create_acl_report.rdkafka_response).to eq(0)
241
+ expect(create_acl_report.rdkafka_response_string).to eq("")
242
+
243
+ # delete the acl that was created for a non existing topic"
244
+ delete_acl_handle = admin.delete_acl(resource_type: resource_type, resource_name: non_existing_resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
245
+ delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
246
+ expect(delete_acl_handle[:response]).to eq(0)
247
+ expect(delete_acl_report.deleted_acls.size).to eq(1)
248
+ end
249
+
250
+ it "creates a acl for topic that was newly created" do
251
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
252
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
253
+ expect(create_acl_report.rdkafka_response).to eq(0)
254
+ expect(create_acl_report.rdkafka_response_string).to eq("")
255
+ end
256
+ end
257
+
258
+ describe "#describe_acl" do
259
+ it "describe acl of a topic that does not exist" do
260
+ describe_acl_handle = admin.describe_acl(resource_type: resource_type, resource_name: non_existing_resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
261
+ describe_acl_report = describe_acl_handle.wait(max_wait_timeout: 15.0)
262
+ expect(describe_acl_handle[:response]).to eq(0)
263
+ expect(describe_acl_report.acls.size).to eq(0)
264
+ end
265
+
266
+ it "create acls and describe the newly created acls" do
267
+ #create_acl
268
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: "test_acl_topic_1", resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
269
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
270
+ expect(create_acl_report.rdkafka_response).to eq(0)
271
+ expect(create_acl_report.rdkafka_response_string).to eq("")
272
+
273
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: "test_acl_topic_2", resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
274
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
275
+ expect(create_acl_report.rdkafka_response).to eq(0)
276
+ expect(create_acl_report.rdkafka_response_string).to eq("")
277
+
278
+ #describe_acl
279
+ describe_acl_handle = admin.describe_acl(resource_type: Rdkafka::Bindings::RD_KAFKA_RESOURCE_ANY, resource_name: nil, resource_pattern_type: Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_ANY, principal: nil, host: nil, operation: Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_ANY, permission_type: Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ANY)
280
+ describe_acl_report = describe_acl_handle.wait(max_wait_timeout: 15.0)
281
+ expect(describe_acl_handle[:response]).to eq(0)
282
+ expect(describe_acl_report.acls.length).to eq(2)
283
+ end
284
+ end
285
+
286
+ describe "#delete_acl" do
287
+ it "delete acl of a topic that does not exist" do
288
+ delete_acl_handle = admin.delete_acl(resource_type: resource_type, resource_name: non_existing_resource_name, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
289
+ delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
290
+ expect(delete_acl_handle[:response]).to eq(0)
291
+ expect(delete_acl_report.deleted_acls.size).to eq(0)
292
+ end
293
+
294
+ it "create an acl and delete the newly created acl" do
295
+ #create_acl
296
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: "test_acl_topic_1", resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
297
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
298
+ expect(create_acl_report.rdkafka_response).to eq(0)
299
+ expect(create_acl_report.rdkafka_response_string).to eq("")
300
+
301
+ create_acl_handle = admin.create_acl(resource_type: resource_type, resource_name: "test_acl_topic_2", resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
302
+ create_acl_report = create_acl_handle.wait(max_wait_timeout: 15.0)
303
+ expect(create_acl_report.rdkafka_response).to eq(0)
304
+ expect(create_acl_report.rdkafka_response_string).to eq("")
305
+
306
+ #delete_acl - resource_name nil - to delete all acls with any resource name and matching all other filters.
307
+ delete_acl_handle = admin.delete_acl(resource_type: resource_type, resource_name: nil, resource_pattern_type: resource_pattern_type, principal: principal, host: host, operation: operation, permission_type: permission_type)
308
+ delete_acl_report = delete_acl_handle.wait(max_wait_timeout: 15.0)
309
+ expect(delete_acl_handle[:response]).to eq(0)
310
+ expect(delete_acl_report.deleted_acls.length).to eq(2)
311
+
312
+ end
313
+ end
314
+ end
315
+
316
+ describe('Group tests') do
317
+ describe "#delete_group" do
318
+ describe("with an existing group") do
319
+ let(:consumer_config) { rdkafka_consumer_config('group.id': group_name) }
320
+ let(:producer_config) { rdkafka_producer_config }
321
+ let(:producer) { producer_config.producer }
322
+ let(:consumer) { consumer_config.consumer }
323
+
324
+ before do
325
+ # Create a topic, post a message to it, consume it and commit offsets, this will create a group that we can then delete.
326
+ admin.create_topic(topic_name, topic_partition_count, topic_replication_factor).wait(max_wait_timeout: 15.0)
327
+
328
+ producer.produce(topic: topic_name, payload: "test", key: "test").wait(max_wait_timeout: 15.0)
329
+
330
+ consumer.subscribe(topic_name)
331
+ wait_for_assignment(consumer)
332
+ message = consumer.poll(100)
333
+
334
+ expect(message).to_not be_nil
335
+
336
+ consumer.commit
337
+ consumer.close
338
+ end
339
+
340
+ after do
341
+ producer.close
342
+ consumer.close
343
+ end
344
+
345
+ it "deletes the group" do
346
+ delete_group_handle = admin.delete_group(group_name)
347
+ report = delete_group_handle.wait(max_wait_timeout: 15.0)
348
+
349
+ expect(report.result_name).to eql(group_name)
350
+ end
351
+ end
352
+
353
+ describe "called with invalid input" do
354
+ describe "with the name of a group that does not exist" do
355
+ it "raises an exception" do
356
+ delete_group_handle = admin.delete_group(group_name)
357
+
358
+ expect {
359
+ delete_group_handle.wait(max_wait_timeout: 15.0)
360
+ }.to raise_exception { |ex|
361
+ expect(ex).to be_a(Rdkafka::RdkafkaError)
362
+ expect(ex.message).to match(/Broker: The group id does not exist \(group_id_not_found\)/)
363
+ }
364
+ end
365
+ end
366
+ end
367
+
368
+ end
369
+ end
370
+
371
+ describe '#create_partitions' do
372
+ let(:metadata) { admin.metadata(topic_name).topics.first }
373
+
374
+ context 'when topic does not exist' do
375
+ it 'expect to fail due to unknown partition' do
376
+ expect { admin.create_partitions(topic_name, 10).wait }.to raise_error(Rdkafka::RdkafkaError, /unknown_topic_or_part/)
377
+ end
378
+ end
379
+
380
+ context 'when topic already has the desired number of partitions' do
381
+ before { admin.create_topic(topic_name, 2, 1).wait }
382
+
383
+ it 'expect not to change number of partitions' do
384
+ expect { admin.create_partitions(topic_name, 2).wait }.to raise_error(Rdkafka::RdkafkaError, /invalid_partitions/)
385
+ expect(metadata[:partition_count]).to eq(2)
386
+ end
387
+ end
388
+
389
+ context 'when topic has more than the requested number of partitions' do
390
+ before { admin.create_topic(topic_name, 5, 1).wait }
391
+
392
+ it 'expect not to change number of partitions' do
393
+ expect { admin.create_partitions(topic_name, 2).wait }.to raise_error(Rdkafka::RdkafkaError, /invalid_partitions/)
394
+ expect(metadata[:partition_count]).to eq(5)
395
+ end
396
+ end
397
+
398
+ context 'when topic has less then desired number of partitions' do
399
+ before { admin.create_topic(topic_name, 1, 1).wait }
400
+
401
+ it 'expect to change number of partitions' do
402
+ admin.create_partitions(topic_name, 10).wait
403
+ expect(metadata[:partition_count]).to eq(10)
404
+ end
405
+ end
406
+ end
203
407
  end
@@ -113,6 +113,14 @@ describe Rdkafka::Config do
113
113
  consumer.close
114
114
  end
115
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
+
116
124
  it "should raise an error when creating a consumer with invalid config" do
117
125
  config = Rdkafka::Config.new('invalid.key' => 'value')
118
126
  expect {
@@ -54,6 +54,30 @@ describe Rdkafka::Consumer do
54
54
  consumer.subscription
55
55
  }.to raise_error(Rdkafka::RdkafkaError)
56
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
57
81
  end
58
82
 
59
83
  describe "#pause and #resume" do
@@ -273,6 +297,28 @@ describe Rdkafka::Consumer do
273
297
  end
274
298
  end
275
299
 
300
+ describe '#assignment_lost?' do
301
+ it "should not return true as we do have an assignment" do
302
+ consumer.subscribe("consume_test_topic")
303
+ expected_subscription = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
304
+ list.add_topic("consume_test_topic")
305
+ end
306
+
307
+ expect(consumer.assignment_lost?).to eq false
308
+ consumer.unsubscribe
309
+ end
310
+
311
+ it "should not return true after voluntary unsubscribing" do
312
+ consumer.subscribe("consume_test_topic")
313
+ expected_subscription = Rdkafka::Consumer::TopicPartitionList.new.tap do |list|
314
+ list.add_topic("consume_test_topic")
315
+ end
316
+
317
+ consumer.unsubscribe
318
+ expect(consumer.assignment_lost?).to eq false
319
+ end
320
+ end
321
+
276
322
  describe "#close" do
277
323
  it "should close a consumer" do
278
324
  consumer.subscribe("consume_test_topic")
@@ -1054,6 +1100,29 @@ describe Rdkafka::Consumer do
1054
1100
  end
1055
1101
  end
1056
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
+
1057
1126
  describe "a rebalance listener" do
1058
1127
  let(:consumer) do
1059
1128
  config = rdkafka_consumer_config
data/spec/spec_helper.rb CHANGED
@@ -11,6 +11,7 @@ require "pry"
11
11
  require "rspec"
12
12
  require "rdkafka"
13
13
  require "timeout"
14
+ require "securerandom"
14
15
 
15
16
  def rdkafka_base_config
16
17
  {
@@ -35,7 +36,7 @@ def rdkafka_consumer_config(config_overrides={})
35
36
  # Add consumer specific fields to it
36
37
  config[:"auto.offset.reset"] = "earliest"
37
38
  config[:"enable.partition.eof"] = false
38
- config[:"group.id"] = "ruby-test-#{Random.new.rand(0..1_000_000)}"
39
+ config[:"group.id"] = "ruby-test-#{SecureRandom.uuid}"
39
40
  # Enable debug mode if required
40
41
  if ENV["DEBUG_CONSUMER"]
41
42
  config[:debug] = "cgrp,topic,fetch"
@@ -134,6 +135,7 @@ RSpec.configure do |config|
134
135
  rake_test_topic: 3,
135
136
  watermarks_test_topic: 3,
136
137
  partitioner_test_topic: 25,
138
+ example_topic: 1
137
139
  }.each do |topic, partitions|
138
140
  create_topic_handle = admin.create_topic(topic.to_s, partitions, 1)
139
141
  begin
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.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thijs Cadier
@@ -35,7 +35,7 @@ cert_chain:
35
35
  AnG1dJU+yL2BK7vaVytLTstJME5mepSZ46qqIJXMuWob/YPDmVaBF39TDSG9e34s
36
36
  msG3BiCqgOgHAnL23+CN3Rt8MsuRfEtoTKpJVcCfoEoNHOkc
37
37
  -----END CERTIFICATE-----
38
- date: 2023-11-21 00:00:00.000000000 Z
38
+ date: 2023-12-03 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: ffi
@@ -171,6 +171,7 @@ extensions:
171
171
  - ext/Rakefile
172
172
  extra_rdoc_files: []
173
173
  files:
174
+ - ".github/FUNDING.yml"
174
175
  - ".github/workflows/ci.yml"
175
176
  - ".gitignore"
176
177
  - ".rspec"
@@ -190,10 +191,21 @@ files:
190
191
  - lib/rdkafka.rb
191
192
  - lib/rdkafka/abstract_handle.rb
192
193
  - lib/rdkafka/admin.rb
194
+ - lib/rdkafka/admin/acl_binding_result.rb
195
+ - lib/rdkafka/admin/create_acl_handle.rb
196
+ - lib/rdkafka/admin/create_acl_report.rb
197
+ - lib/rdkafka/admin/create_partitions_handle.rb
198
+ - lib/rdkafka/admin/create_partitions_report.rb
193
199
  - lib/rdkafka/admin/create_topic_handle.rb
194
200
  - lib/rdkafka/admin/create_topic_report.rb
201
+ - lib/rdkafka/admin/delete_acl_handle.rb
202
+ - lib/rdkafka/admin/delete_acl_report.rb
203
+ - lib/rdkafka/admin/delete_groups_handle.rb
204
+ - lib/rdkafka/admin/delete_groups_report.rb
195
205
  - lib/rdkafka/admin/delete_topic_handle.rb
196
206
  - lib/rdkafka/admin/delete_topic_report.rb
207
+ - lib/rdkafka/admin/describe_acl_handle.rb
208
+ - lib/rdkafka/admin/describe_acl_report.rb
197
209
  - lib/rdkafka/bindings.rb
198
210
  - lib/rdkafka/callbacks.rb
199
211
  - lib/rdkafka/config.rb
@@ -213,10 +225,16 @@ files:
213
225
  - rdkafka.gemspec
214
226
  - renovate.json
215
227
  - spec/rdkafka/abstract_handle_spec.rb
228
+ - spec/rdkafka/admin/create_acl_handle_spec.rb
229
+ - spec/rdkafka/admin/create_acl_report_spec.rb
216
230
  - spec/rdkafka/admin/create_topic_handle_spec.rb
217
231
  - spec/rdkafka/admin/create_topic_report_spec.rb
232
+ - spec/rdkafka/admin/delete_acl_handle_spec.rb
233
+ - spec/rdkafka/admin/delete_acl_report_spec.rb
218
234
  - spec/rdkafka/admin/delete_topic_handle_spec.rb
219
235
  - spec/rdkafka/admin/delete_topic_report_spec.rb
236
+ - spec/rdkafka/admin/describe_acl_handle_spec.rb
237
+ - spec/rdkafka/admin/describe_acl_report_spec.rb
220
238
  - spec/rdkafka/admin_spec.rb
221
239
  - spec/rdkafka/bindings_spec.rb
222
240
  - spec/rdkafka/callbacks_spec.rb
@@ -267,10 +285,16 @@ summary: The rdkafka gem is a modern Kafka client library for Ruby based on libr
267
285
  and Ruby 2.4+.
268
286
  test_files:
269
287
  - spec/rdkafka/abstract_handle_spec.rb
288
+ - spec/rdkafka/admin/create_acl_handle_spec.rb
289
+ - spec/rdkafka/admin/create_acl_report_spec.rb
270
290
  - spec/rdkafka/admin/create_topic_handle_spec.rb
271
291
  - spec/rdkafka/admin/create_topic_report_spec.rb
292
+ - spec/rdkafka/admin/delete_acl_handle_spec.rb
293
+ - spec/rdkafka/admin/delete_acl_report_spec.rb
272
294
  - spec/rdkafka/admin/delete_topic_handle_spec.rb
273
295
  - spec/rdkafka/admin/delete_topic_report_spec.rb
296
+ - spec/rdkafka/admin/describe_acl_handle_spec.rb
297
+ - spec/rdkafka/admin/describe_acl_report_spec.rb
274
298
  - spec/rdkafka/admin_spec.rb
275
299
  - spec/rdkafka/bindings_spec.rb
276
300
  - spec/rdkafka/callbacks_spec.rb
metadata.gz.sig CHANGED
Binary file