karafka-rdkafka 0.21.0-aarch64-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.
- checksums.yaml +7 -0
- data/.github/CODEOWNERS +3 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/ci_linux_alpine_x86_64_musl.yml +197 -0
- data/.github/workflows/ci_linux_alpine_x86_64_musl_complementary.yml +264 -0
- data/.github/workflows/ci_linux_debian_x86_64_gnu.yml +271 -0
- data/.github/workflows/ci_linux_debian_x86_64_gnu_complementary.yml +334 -0
- data/.github/workflows/ci_linux_ubuntu_aarch64_gnu.yml +271 -0
- data/.github/workflows/ci_linux_ubuntu_aarch64_gnu_complementary.yml +295 -0
- data/.github/workflows/ci_linux_ubuntu_x86_64_gnu.yml +281 -0
- data/.github/workflows/ci_linux_ubuntu_x86_64_gnu_complementary.yml +294 -0
- data/.github/workflows/ci_macos_arm64.yml +284 -0
- data/.github/workflows/push_linux_aarch64_gnu.yml +65 -0
- data/.github/workflows/push_linux_x86_64_gnu.yml +65 -0
- data/.github/workflows/push_linux_x86_64_musl.yml +79 -0
- data/.github/workflows/push_macos_arm64.yml +54 -0
- data/.github/workflows/push_ruby.yml +37 -0
- data/.github/workflows/trigger-wiki-refresh.yml +30 -0
- data/.github/workflows/verify-action-pins.yml +16 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.yardopts +2 -0
- data/CHANGELOG.md +344 -0
- data/Gemfile +5 -0
- data/MIT-LICENSE +22 -0
- data/README.md +78 -0
- data/Rakefile +96 -0
- data/dist/cyrus-sasl-2.1.28.tar.gz +0 -0
- data/dist/krb5-1.21.3.tar.gz +0 -0
- data/dist/openssl-3.0.16.tar.gz +0 -0
- data/dist/zlib-1.3.1.tar.gz +0 -0
- data/dist/zstd-1.5.7.tar.gz +0 -0
- data/docker-compose-ssl.yml +35 -0
- data/docker-compose.yml +25 -0
- data/ext/README.md +19 -0
- data/ext/Rakefile +131 -0
- data/ext/build_common.sh +376 -0
- data/ext/build_linux_aarch64_gnu.sh +326 -0
- data/ext/build_linux_x86_64_gnu.sh +317 -0
- data/ext/build_linux_x86_64_musl.sh +773 -0
- data/ext/build_macos_arm64.sh +557 -0
- data/ext/generate-ssl-certs.sh +109 -0
- data/ext/librdkafka.so +0 -0
- data/karafka-rdkafka.gemspec +65 -0
- data/lib/rdkafka/abstract_handle.rb +116 -0
- data/lib/rdkafka/admin/acl_binding_result.rb +51 -0
- data/lib/rdkafka/admin/config_binding_result.rb +30 -0
- data/lib/rdkafka/admin/config_resource_binding_result.rb +18 -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 +30 -0
- data/lib/rdkafka/admin/create_partitions_report.rb +6 -0
- data/lib/rdkafka/admin/create_topic_handle.rb +32 -0
- data/lib/rdkafka/admin/create_topic_report.rb +24 -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/delete_topic_handle.rb +32 -0
- data/lib/rdkafka/admin/delete_topic_report.rb +24 -0
- data/lib/rdkafka/admin/describe_acl_handle.rb +30 -0
- data/lib/rdkafka/admin/describe_acl_report.rb +24 -0
- data/lib/rdkafka/admin/describe_configs_handle.rb +33 -0
- data/lib/rdkafka/admin/describe_configs_report.rb +48 -0
- data/lib/rdkafka/admin/incremental_alter_configs_handle.rb +33 -0
- data/lib/rdkafka/admin/incremental_alter_configs_report.rb +48 -0
- data/lib/rdkafka/admin.rb +832 -0
- data/lib/rdkafka/bindings.rb +583 -0
- data/lib/rdkafka/callbacks.rb +415 -0
- data/lib/rdkafka/config.rb +395 -0
- data/lib/rdkafka/consumer/headers.rb +79 -0
- data/lib/rdkafka/consumer/message.rb +86 -0
- data/lib/rdkafka/consumer/partition.rb +57 -0
- data/lib/rdkafka/consumer/topic_partition_list.rb +190 -0
- data/lib/rdkafka/consumer.rb +663 -0
- data/lib/rdkafka/error.rb +201 -0
- data/lib/rdkafka/helpers/oauth.rb +58 -0
- data/lib/rdkafka/helpers/time.rb +14 -0
- data/lib/rdkafka/metadata.rb +115 -0
- data/lib/rdkafka/native_kafka.rb +139 -0
- data/lib/rdkafka/producer/delivery_handle.rb +48 -0
- data/lib/rdkafka/producer/delivery_report.rb +45 -0
- data/lib/rdkafka/producer/partitions_count_cache.rb +216 -0
- data/lib/rdkafka/producer.rb +497 -0
- data/lib/rdkafka/version.rb +7 -0
- data/lib/rdkafka.rb +54 -0
- data/renovate.json +92 -0
- data/spec/integrations/ssl_stress_spec.rb +121 -0
- data/spec/lib/rdkafka/abstract_handle_spec.rb +117 -0
- data/spec/lib/rdkafka/admin/create_acl_handle_spec.rb +56 -0
- data/spec/lib/rdkafka/admin/create_acl_report_spec.rb +18 -0
- data/spec/lib/rdkafka/admin/create_topic_handle_spec.rb +54 -0
- data/spec/lib/rdkafka/admin/create_topic_report_spec.rb +16 -0
- data/spec/lib/rdkafka/admin/delete_acl_handle_spec.rb +85 -0
- data/spec/lib/rdkafka/admin/delete_acl_report_spec.rb +72 -0
- data/spec/lib/rdkafka/admin/delete_topic_handle_spec.rb +54 -0
- data/spec/lib/rdkafka/admin/delete_topic_report_spec.rb +16 -0
- data/spec/lib/rdkafka/admin/describe_acl_handle_spec.rb +85 -0
- data/spec/lib/rdkafka/admin/describe_acl_report_spec.rb +73 -0
- data/spec/lib/rdkafka/admin_spec.rb +982 -0
- data/spec/lib/rdkafka/bindings_spec.rb +198 -0
- data/spec/lib/rdkafka/callbacks_spec.rb +20 -0
- data/spec/lib/rdkafka/config_spec.rb +258 -0
- data/spec/lib/rdkafka/consumer/headers_spec.rb +73 -0
- data/spec/lib/rdkafka/consumer/message_spec.rb +139 -0
- data/spec/lib/rdkafka/consumer/partition_spec.rb +57 -0
- data/spec/lib/rdkafka/consumer/topic_partition_list_spec.rb +248 -0
- data/spec/lib/rdkafka/consumer_spec.rb +1343 -0
- data/spec/lib/rdkafka/error_spec.rb +95 -0
- data/spec/lib/rdkafka/metadata_spec.rb +79 -0
- data/spec/lib/rdkafka/native_kafka_spec.rb +130 -0
- data/spec/lib/rdkafka/producer/delivery_handle_spec.rb +60 -0
- data/spec/lib/rdkafka/producer/delivery_report_spec.rb +25 -0
- data/spec/lib/rdkafka/producer/partitions_count_cache_spec.rb +359 -0
- data/spec/lib/rdkafka/producer_spec.rb +1527 -0
- data/spec/spec_helper.rb +230 -0
- metadata +320 -0
@@ -0,0 +1,121 @@
|
|
1
|
+
# ssl_stress_test.rb
|
2
|
+
#
|
3
|
+
# This script is designed to stress-test the OpenSSL SSL/TLS layer under high concurrency
|
4
|
+
# to help detect regressions like the one described in OpenSSL issue #28171:
|
5
|
+
# https://github.com/openssl/openssl/issues/28171
|
6
|
+
#
|
7
|
+
# Issue summary:
|
8
|
+
# - OpenSSL 3.0.17 introduced a concurrency-related regression.
|
9
|
+
# - Multiple threads sharing the same SSL_CTX and making parallel TLS connections
|
10
|
+
# (often with certificate verification enabled) can cause segmentation faults
|
11
|
+
# due to race conditions in X509 store handling.
|
12
|
+
# - Affected users include Python (httpx), Rust (reqwest, native-tls), and C applications.
|
13
|
+
#
|
14
|
+
# Script details:
|
15
|
+
# - Starts 100 SSL servers using self-signed, in-memory certs on sequential localhost ports.
|
16
|
+
# - Uses `rdkafka-ruby` to spin up 100 consumer threads that continuously create and destroy
|
17
|
+
# SSL connections to these servers for a given duration.
|
18
|
+
# - This mimics high TLS connection churn and aims to trigger latent SSL_CTX or X509_STORE
|
19
|
+
# threading bugs like double-frees, memory corruption, or segmentation faults.
|
20
|
+
#
|
21
|
+
# Goal:
|
22
|
+
# - Catch regressions early by validating that heavy concurrent SSL use does not lead to crashes.
|
23
|
+
# - Provide a minimal and repeatable reproducer when diagnosing OpenSSL-level SSL instability.
|
24
|
+
#
|
25
|
+
# In case of a failure, segfault will happen
|
26
|
+
|
27
|
+
require 'rdkafka'
|
28
|
+
require 'socket'
|
29
|
+
require 'openssl'
|
30
|
+
|
31
|
+
$stdout.sync = true
|
32
|
+
|
33
|
+
STARTING_PORT = 19093
|
34
|
+
NUM_PORTS = 150
|
35
|
+
BATCHES = 100
|
36
|
+
PORTS = STARTING_PORT...(STARTING_PORT + NUM_PORTS)
|
37
|
+
|
38
|
+
CONFIG = {
|
39
|
+
'bootstrap.servers': Array.new(NUM_PORTS) { |i| "127.0.0.1:#{19093+i}" }.join(','),
|
40
|
+
'security.protocol': 'SSL',
|
41
|
+
'enable.ssl.certificate.verification': false
|
42
|
+
}
|
43
|
+
|
44
|
+
# Generate in-memory self-signed cert
|
45
|
+
key = OpenSSL::PKey::RSA.new(2048)
|
46
|
+
|
47
|
+
name = OpenSSL::X509::Name.parse("/CN=127.0.0.1")
|
48
|
+
cert = OpenSSL::X509::Certificate.new
|
49
|
+
cert.version = 2
|
50
|
+
cert.serial = 1
|
51
|
+
cert.subject = name
|
52
|
+
cert.issuer = name
|
53
|
+
cert.public_key = key.public_key
|
54
|
+
cert.not_before = Time.now
|
55
|
+
cert.not_after = Time.now + 3600
|
56
|
+
cert.sign(key, OpenSSL::Digest::SHA256.new)
|
57
|
+
|
58
|
+
# Start servers on multiple ports
|
59
|
+
PORTS.map do |port|
|
60
|
+
Thread.new do
|
61
|
+
# Prepare SSL context
|
62
|
+
# We do not use a shared context for the server because the goal is to stress librdkafka layer
|
63
|
+
# and not the Ruby SSL layer
|
64
|
+
ssl_context = OpenSSL::SSL::SSLContext.new
|
65
|
+
ssl_context.cert = cert
|
66
|
+
ssl_context.key = key
|
67
|
+
|
68
|
+
tcp_server = TCPServer.new('127.0.0.1', port)
|
69
|
+
ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server, ssl_context)
|
70
|
+
|
71
|
+
loop do
|
72
|
+
begin
|
73
|
+
ssl_socket = ssl_server.accept
|
74
|
+
ssl_socket.close
|
75
|
+
rescue => e
|
76
|
+
# Some errors are expected and irrelevant
|
77
|
+
next if e.message.include?('unexpected eof while reading')
|
78
|
+
|
79
|
+
puts "Port #{port} SSL error: #{e}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
puts "Starting #{NUM_PORTS} on ports from #{PORTS.first} to #{PORTS.last} SSL servers"
|
86
|
+
|
87
|
+
timeout = 30
|
88
|
+
start = Time.now
|
89
|
+
|
90
|
+
# Wait for the servers to be available
|
91
|
+
# We want to make sure that they are available so we are sure that librdkafka actually hammers
|
92
|
+
# them
|
93
|
+
loop do
|
94
|
+
all_up = PORTS.all? do |port|
|
95
|
+
TCPSocket.new('127.0.0.1', port).close
|
96
|
+
true
|
97
|
+
rescue
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
break if all_up
|
102
|
+
|
103
|
+
raise "Timeout waiting for SSL servers" if Time.now - start > timeout
|
104
|
+
|
105
|
+
sleep 0.1
|
106
|
+
end
|
107
|
+
|
108
|
+
puts "SSL servers ready"
|
109
|
+
|
110
|
+
start_time = Time.now
|
111
|
+
duration = 60 * 10 # 10 minutes - it should crash faster than that if SSL vulnerable
|
112
|
+
attempts = 0
|
113
|
+
|
114
|
+
while Time.now - start_time < duration do
|
115
|
+
css = Array.new(BATCHES) { Rdkafka::Config.new(CONFIG) }
|
116
|
+
csss = css.map(&:consumer)
|
117
|
+
# This print is needed. No idea why but it increases the chances of segfault
|
118
|
+
p attempts += 1
|
119
|
+
sleep(1)
|
120
|
+
csss.each(&:close)
|
121
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Rdkafka::AbstractHandle do
|
4
|
+
let(:response) { 0 }
|
5
|
+
let(:result) { -1 }
|
6
|
+
|
7
|
+
context "A subclass that does not implement the required methods" do
|
8
|
+
|
9
|
+
class BadTestHandle < Rdkafka::AbstractHandle
|
10
|
+
layout :pending, :bool,
|
11
|
+
:response, :int
|
12
|
+
end
|
13
|
+
|
14
|
+
it "raises an exception if operation_name is called" do
|
15
|
+
expect {
|
16
|
+
BadTestHandle.new.operation_name
|
17
|
+
}.to raise_exception(RuntimeError, /Must be implemented by subclass!/)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "raises an exception if create_result is called" do
|
21
|
+
expect {
|
22
|
+
BadTestHandle.new.create_result
|
23
|
+
}.to raise_exception(RuntimeError, /Must be implemented by subclass!/)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TestHandle < Rdkafka::AbstractHandle
|
28
|
+
layout :pending, :bool,
|
29
|
+
:response, :int,
|
30
|
+
:result, :int
|
31
|
+
|
32
|
+
def operation_name
|
33
|
+
"test_operation"
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_result
|
37
|
+
self[:result]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
subject do
|
42
|
+
TestHandle.new.tap do |handle|
|
43
|
+
handle[:pending] = pending_handle
|
44
|
+
handle[:response] = response
|
45
|
+
handle[:result] = result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".register and .remove" do
|
50
|
+
let(:pending_handle) { true }
|
51
|
+
|
52
|
+
it "should register and remove a delivery handle" do
|
53
|
+
Rdkafka::AbstractHandle.register(subject)
|
54
|
+
removed = Rdkafka::AbstractHandle.remove(subject.to_ptr.address)
|
55
|
+
expect(removed).to eq subject
|
56
|
+
expect(Rdkafka::AbstractHandle::REGISTRY).to be_empty
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#pending?" do
|
61
|
+
context "when true" do
|
62
|
+
let(:pending_handle) { true }
|
63
|
+
|
64
|
+
it "should be true" do
|
65
|
+
expect(subject.pending?).to be true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when not true" do
|
70
|
+
let(:pending_handle) { false }
|
71
|
+
|
72
|
+
it "should be false" do
|
73
|
+
expect(subject.pending?).to be false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#wait" do
|
79
|
+
context 'when pending_handle true' do
|
80
|
+
let(:pending_handle) { true }
|
81
|
+
|
82
|
+
it "should wait until the timeout and then raise an error" do
|
83
|
+
expect {
|
84
|
+
subject.wait(max_wait_timeout: 0.1)
|
85
|
+
}.to raise_error Rdkafka::AbstractHandle::WaitTimeoutError, /test_operation/
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'when pending_handle false' do
|
90
|
+
let(:pending_handle) { false }
|
91
|
+
|
92
|
+
context "without error" do
|
93
|
+
let(:result) { 1 }
|
94
|
+
|
95
|
+
it "should return a result" do
|
96
|
+
wait_result = subject.wait
|
97
|
+
expect(wait_result).to eq(result)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should wait without a timeout" do
|
101
|
+
wait_result = subject.wait(max_wait_timeout: nil)
|
102
|
+
expect(wait_result).to eq(result)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context "with error" do
|
107
|
+
let(:response) { 20 }
|
108
|
+
|
109
|
+
it "should raise an rdkafka error" do
|
110
|
+
expect {
|
111
|
+
subject.wait
|
112
|
+
}.to raise_error Rdkafka::RdkafkaError
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Rdkafka::Admin::CreateAclHandle do
|
6
|
+
# If create acl was successful there is no error object
|
7
|
+
# the error code is set to RD_KAFKA_RESP_ERR_NO_ERRORa
|
8
|
+
# https://github.com/confluentinc/librdkafka/blob/1f9f245ac409f50f724695c628c7a0d54a763b9a/src/rdkafka_error.c#L169
|
9
|
+
let(:response) { Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR }
|
10
|
+
|
11
|
+
subject do
|
12
|
+
Rdkafka::Admin::CreateAclHandle.new.tap do |handle|
|
13
|
+
handle[:pending] = pending_handle
|
14
|
+
handle[:response] = response
|
15
|
+
# If create acl was successful there is no error object and the error_string is set to ""
|
16
|
+
# https://github.com/confluentinc/librdkafka/blob/1f9f245ac409f50f724695c628c7a0d54a763b9a/src/rdkafka_error.c#L178
|
17
|
+
handle[:response_string] = FFI::MemoryPointer.from_string("")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#wait" do
|
22
|
+
let(:pending_handle) { true }
|
23
|
+
|
24
|
+
it "should wait until the timeout and then raise an error" do
|
25
|
+
expect {
|
26
|
+
subject.wait(max_wait_timeout: 0.1)
|
27
|
+
}.to raise_error Rdkafka::Admin::CreateAclHandle::WaitTimeoutError, /create acl/
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when not pending anymore and no error" do
|
31
|
+
let(:pending_handle) { false }
|
32
|
+
|
33
|
+
it "should return a create acl report" do
|
34
|
+
report = subject.wait
|
35
|
+
|
36
|
+
expect(report.rdkafka_response_string).to eq("")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should wait without a timeout" do
|
40
|
+
report = subject.wait(max_wait_timeout: nil)
|
41
|
+
|
42
|
+
expect(report.rdkafka_response_string).to eq("")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#raise_error" do
|
48
|
+
let(:pending_handle) { false }
|
49
|
+
|
50
|
+
it "should raise the appropriate error" do
|
51
|
+
expect {
|
52
|
+
subject.raise_error
|
53
|
+
}.to raise_exception(Rdkafka::RdkafkaError, /Success \(no_error\)/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Rdkafka::Admin::CreateAclReport do
|
6
|
+
subject { Rdkafka::Admin::CreateAclReport.new(
|
7
|
+
rdkafka_response: Rdkafka::Bindings::RD_KAFKA_RESP_ERR_NO_ERROR,
|
8
|
+
rdkafka_response_string: FFI::MemoryPointer.from_string("")
|
9
|
+
)}
|
10
|
+
|
11
|
+
it "should get RD_KAFKA_RESP_ERR_NO_ERROR " do
|
12
|
+
expect(subject.rdkafka_response).to eq(0)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should get empty string" do
|
16
|
+
expect(subject.rdkafka_response_string).to eq("")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Rdkafka::Admin::CreateTopicHandle do
|
4
|
+
let(:response) { 0 }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
Rdkafka::Admin::CreateTopicHandle.new.tap do |handle|
|
8
|
+
handle[:pending] = pending_handle
|
9
|
+
handle[:response] = response
|
10
|
+
handle[:error_string] = FFI::Pointer::NULL
|
11
|
+
handle[:result_name] = FFI::MemoryPointer.from_string("my-test-topic")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#wait" do
|
16
|
+
let(:pending_handle) { true }
|
17
|
+
|
18
|
+
it "should wait until the timeout and then raise an error" do
|
19
|
+
expect {
|
20
|
+
subject.wait(max_wait_timeout: 0.1)
|
21
|
+
}.to raise_error Rdkafka::Admin::CreateTopicHandle::WaitTimeoutError, /create topic/
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when not pending anymore and no error" do
|
25
|
+
let(:pending_handle) { false }
|
26
|
+
|
27
|
+
it "should return a create topic report" do
|
28
|
+
report = subject.wait
|
29
|
+
|
30
|
+
expect(report.error_string).to eq(nil)
|
31
|
+
expect(report.result_name).to eq("my-test-topic")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should wait without a timeout" do
|
35
|
+
report = subject.wait(max_wait_timeout: nil)
|
36
|
+
|
37
|
+
expect(report.error_string).to eq(nil)
|
38
|
+
expect(report.result_name).to eq("my-test-topic")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#raise_error" do
|
44
|
+
let(:pending_handle) { false }
|
45
|
+
|
46
|
+
before { subject[:response] = -1 }
|
47
|
+
|
48
|
+
it "should raise the appropriate error when there is an error" do
|
49
|
+
expect {
|
50
|
+
subject.raise_error
|
51
|
+
}.to raise_exception(Rdkafka::RdkafkaError, /Unknown broker error \(unknown\)/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Rdkafka::Admin::CreateTopicReport do
|
4
|
+
subject { Rdkafka::Admin::CreateTopicReport.new(
|
5
|
+
FFI::MemoryPointer.from_string("error string"),
|
6
|
+
FFI::MemoryPointer.from_string("result name")
|
7
|
+
)}
|
8
|
+
|
9
|
+
it "should get the error string" do
|
10
|
+
expect(subject.error_string).to eq("error string")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get the result name" do
|
14
|
+
expect(subject.result_name).to eq("result name")
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe Rdkafka::Admin::DeleteAclHandle 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(: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::DeleteAclHandle.new.tap do |handle|
|
36
|
+
handle[:pending] = pending_handle
|
37
|
+
handle[:response] = response
|
38
|
+
handle[:response_string] = FFI::MemoryPointer.from_string("")
|
39
|
+
handle[:matching_acls] = delete_acls_array_ptr
|
40
|
+
handle[:matching_acls_count] = 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
after do
|
45
|
+
if delete_acl_ptr != FFI::Pointer::NULL
|
46
|
+
Rdkafka::Bindings.rd_kafka_AclBinding_destroy(delete_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::DeleteAclHandle::WaitTimeoutError, /delete 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 delete acl report" do
|
63
|
+
report = subject.wait
|
64
|
+
|
65
|
+
expect(report.deleted_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.deleted_acls[0].matching_acl_resource_name).to eq(resource_name)
|
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::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_resource_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
|
54
|
+
expect(subject.deleted_acls[0].matching_acl_pattern_type).to eq(Rdkafka::Bindings::RD_KAFKA_RESOURCE_PATTERN_LITERAL)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should get deleted acl principal as User:anonymous" do
|
58
|
+
expect(subject.deleted_acls[0].matching_acl_principal).to eq("User:anonymous")
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should get deleted acl host as * " do
|
62
|
+
expect(subject.deleted_acls[0].matching_acl_host).to eq("*")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should get deleted acl operation as Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ" do
|
66
|
+
expect(subject.deleted_acls[0].matching_acl_operation).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_OPERATION_READ)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should get deleted acl permission_type as Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW" do
|
70
|
+
expect(subject.deleted_acls[0].matching_acl_permission_type).to eq(Rdkafka::Bindings::RD_KAFKA_ACL_PERMISSION_TYPE_ALLOW)
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Rdkafka::Admin::DeleteTopicHandle do
|
4
|
+
let(:response) { 0 }
|
5
|
+
|
6
|
+
subject do
|
7
|
+
Rdkafka::Admin::DeleteTopicHandle.new.tap do |handle|
|
8
|
+
handle[:pending] = pending_handle
|
9
|
+
handle[:response] = response
|
10
|
+
handle[:error_string] = FFI::Pointer::NULL
|
11
|
+
handle[:result_name] = FFI::MemoryPointer.from_string("my-test-topic")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#wait" do
|
16
|
+
let(:pending_handle) { true }
|
17
|
+
|
18
|
+
it "should wait until the timeout and then raise an error" do
|
19
|
+
expect {
|
20
|
+
subject.wait(max_wait_timeout: 0.1)
|
21
|
+
}.to raise_error Rdkafka::Admin::DeleteTopicHandle::WaitTimeoutError, /delete topic/
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when not pending anymore and no error" do
|
25
|
+
let(:pending_handle) { false }
|
26
|
+
|
27
|
+
it "should return a delete topic report" do
|
28
|
+
report = subject.wait
|
29
|
+
|
30
|
+
expect(report.error_string).to eq(nil)
|
31
|
+
expect(report.result_name).to eq("my-test-topic")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should wait without a timeout" do
|
35
|
+
report = subject.wait(max_wait_timeout: nil)
|
36
|
+
|
37
|
+
expect(report.error_string).to eq(nil)
|
38
|
+
expect(report.result_name).to eq("my-test-topic")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#raise_error" do
|
44
|
+
let(:pending_handle) { false }
|
45
|
+
|
46
|
+
before { subject[:response] = -1 }
|
47
|
+
|
48
|
+
it "should raise the appropriate error" do
|
49
|
+
expect {
|
50
|
+
subject.raise_error
|
51
|
+
}.to raise_exception(Rdkafka::RdkafkaError, /Unknown broker error \(unknown\)/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Rdkafka::Admin::DeleteTopicReport do
|
4
|
+
subject { Rdkafka::Admin::DeleteTopicReport.new(
|
5
|
+
FFI::MemoryPointer.from_string("error string"),
|
6
|
+
FFI::MemoryPointer.from_string("result name")
|
7
|
+
)}
|
8
|
+
|
9
|
+
it "should get the error string" do
|
10
|
+
expect(subject.error_string).to eq("error string")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should get the result name" do
|
14
|
+
expect(subject.result_name).to eq("result name")
|
15
|
+
end
|
16
|
+
end
|