rdkafka 0.14.0 → 0.15.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.github/FUNDING.yml +1 -0
- data/CHANGELOG.md +11 -0
- data/README.md +32 -22
- data/docker-compose.yml +2 -0
- data/lib/rdkafka/admin/acl_binding_result.rb +37 -0
- data/lib/rdkafka/admin/create_acl_handle.rb +28 -0
- data/lib/rdkafka/admin/create_acl_report.rb +24 -0
- data/lib/rdkafka/admin/create_partitions_handle.rb +27 -0
- data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
- data/lib/rdkafka/admin/delete_acl_handle.rb +30 -0
- data/lib/rdkafka/admin/delete_acl_report.rb +23 -0
- data/lib/rdkafka/admin/delete_groups_handle.rb +28 -0
- data/lib/rdkafka/admin/delete_groups_report.rb +24 -0
- data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
- data/lib/rdkafka/admin/describe_acl_report.rb +23 -0
- data/lib/rdkafka/admin.rb +443 -0
- data/lib/rdkafka/bindings.rb +119 -0
- data/lib/rdkafka/callbacks.rb +187 -0
- data/lib/rdkafka/config.rb +24 -3
- data/lib/rdkafka/consumer/headers.rb +1 -1
- data/lib/rdkafka/consumer/topic_partition_list.rb +8 -7
- data/lib/rdkafka/consumer.rb +46 -10
- data/lib/rdkafka/producer.rb +2 -2
- data/lib/rdkafka/version.rb +3 -3
- data/lib/rdkafka.rb +11 -0
- data/spec/rdkafka/admin/create_acl_handle_spec.rb +56 -0
- data/spec/rdkafka/admin/create_acl_report_spec.rb +18 -0
- data/spec/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
- data/spec/rdkafka/admin/delete_acl_report_spec.rb +71 -0
- data/spec/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
- data/spec/rdkafka/admin/describe_acl_report_spec.rb +72 -0
- data/spec/rdkafka/admin_spec.rb +204 -0
- data/spec/rdkafka/config_spec.rb +8 -0
- data/spec/rdkafka/consumer_spec.rb +69 -0
- data/spec/spec_helper.rb +3 -1
- data.tar.gz.sig +0 -0
- metadata +26 -2
- 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
|
data/spec/rdkafka/admin_spec.rb
CHANGED
@@ -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
|
data/spec/rdkafka/config_spec.rb
CHANGED
@@ -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-#{
|
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.
|
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-
|
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
|