Skip to content

test: add several cases for Ractor #434

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
require:
plugins:
- rubocop-performance
- rubocop-rake
- rubocop-minitest
Expand Down
12 changes: 6 additions & 6 deletions test/prof_stack2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ def run

case mode = ENV.fetch('PROFILE_MODE', :single).to_sym
when :single
execute(client, mode) do |client|
ATTEMPTS.times { |i| client.call('get', "key#{i}") }
execute(client, mode) do |cli|
ATTEMPTS.times { |i| cli.call('get', "key#{i}") }
end
when :transaction
execute(client, mode) do |client|
execute(client, mode) do |cli|
ATTEMPTS.times do |i|
client.multi do |tx|
cli.multi do |tx|
SIZE.times do |j|
n = SIZE * i + j
tx.call('set', "{group:#{i}}:key:#{n}", n)
Expand All @@ -31,9 +31,9 @@ def run
end
end
when :pipeline
execute(client, mode) do |client|
execute(client, mode) do |cli|
ATTEMPTS.times do |i|
client.pipelined do |pi|
cli.pipelined do |pi|
SIZE.times do |j|
n = SIZE * i + j
pi.call('get', "key#{n}")
Expand Down
78 changes: 78 additions & 0 deletions test/test_concurrency.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,84 @@ def test_threading_with_transaction
assert_equal(WANT, @client.call('GET', '{key}1'))
end

def test_ractor
skip('Ractor is not available') unless Object.const_defined?(:Ractor, false)
skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection
skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL
skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1

ractors = Array.new(MAX_THREADS) do |i|
Ractor.new(i) do |i|
c = ::RedisClient.cluster(
nodes: TEST_NODE_URIS,
fixed_hostname: TEST_FIXED_HOSTNAME,
**TEST_GENERIC_OPTIONS
).new_client
c.call('get', "key#{i}")
rescue StandardError => e
e
ensure
c&.close
end
end

ractors.each { |r| assert_equal(WANT, r.take) }
end

def test_ractor_with_pipelining
skip('Ractor is not available') unless Object.const_defined?(:Ractor, false)
skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection
skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL
skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1

ractors = Array.new(MAX_THREADS) do |i|
Ractor.new(i) do |i|
c = ::RedisClient.cluster(
nodes: TEST_NODE_URIS,
fixed_hostname: TEST_FIXED_HOSTNAME,
**TEST_GENERIC_OPTIONS
).new_client
c.pipelined do |pi|
pi.call('get', "key#{i}")
pi.call('echo', 'hi')
end
rescue StandardError => e
e
ensure
c&.close
end
end

ractors.each { |r| assert_equal([WANT, 'hi'], r.take) }
end

def test_ractor_with_transaction
skip('Ractor is not available') unless Object.const_defined?(:Ractor, false)
skip("#{RedisClient.default_driver} is not safe for Ractor") if RedisClient.default_driver != RedisClient::RubyConnection
skip('OpenSSL gem has non-shareable objects') if TEST_REDIS_SSL
skip('test case may get stuck') if RUBY_ENGINE == 'ruby' && RUBY_ENGINE_VERSION.split('.').take(2).join('.').to_f < 3.1

ractors = Array.new(MAX_THREADS) do |i|
Ractor.new(i) do |i|
c = ::RedisClient.cluster(
nodes: TEST_NODE_URIS,
fixed_hostname: TEST_FIXED_HOSTNAME,
**TEST_GENERIC_OPTIONS
).new_client
c.multi(watch: ["key#{i}"]) do |tx|
tx.call('incr', "key#{i}")
tx.call('incr', "key#{i}")
end
rescue StandardError => e
e
ensure
c&.close
end
end

ractors.each { |r| assert_equal([2, 3], r.take) }
end

private

def new_test_client
Expand Down
5 changes: 5 additions & 0 deletions test/testing_constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,9 @@
BENCH_ENVOY_OPTIONS = { port: 7000, protocol: 2 }.freeze
BENCH_REDIS_CLUSTER_PROXY_OPTIONS = { port: 7001, protocol: 2 }.freeze

if Object.const_defined?(:Ractor, false) && Ractor.respond_to?(:make_shareable)
Ractor.make_shareable(TEST_NODE_URIS)
Ractor.make_shareable(TEST_GENERIC_OPTIONS)
end

# rubocop:enable Lint/UnderscorePrefixedVariableName