summaryrefslogtreecommitdiff
path: root/test/ruby/test_ractor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/ruby/test_ractor.rb')
-rw-r--r--test/ruby/test_ractor.rb186
1 files changed, 160 insertions, 26 deletions
diff --git a/test/ruby/test_ractor.rb b/test/ruby/test_ractor.rb
index e61c6beffc..6ae511217a 100644
--- a/test/ruby/test_ractor.rb
+++ b/test/ruby/test_ractor.rb
@@ -3,38 +3,19 @@ require 'test/unit'
class TestRactor < Test::Unit::TestCase
def test_shareability_of_iseq_proc
- y = nil.instance_eval do
+ assert_raise Ractor::IsolationError do
foo = []
- proc { foo }
+ Ractor.shareable_proc{ foo }
end
- assert_unshareable(y, /unshareable object \[\] from variable 'foo'/)
-
- y = [].instance_eval { proc { self } }
- assert_unshareable(y, /Proc's self is not shareable/)
-
- y = [].freeze.instance_eval { proc { self } }
- assert_make_shareable(y)
- end
-
- def test_shareability_of_curried_proc
- x = nil.instance_eval do
- foo = []
- proc { foo }.curry
- end
- assert_unshareable(x, /unshareable object \[\] from variable 'foo'/)
-
- x = nil.instance_eval do
- foo = 123
- proc { foo }.curry
- end
- assert_make_shareable(x)
end
def test_shareability_of_method_proc
+ # TODO: fix with Ractor.shareable_proc/lambda
+=begin
str = +""
x = str.instance_exec { proc { to_s } }
- assert_unshareable(x, /Proc's self is not shareable/)
+ assert_unshareable(x, /Proc\'s self is not shareable/)
x = str.instance_exec { method(:to_s) }
assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
@@ -58,6 +39,7 @@ class TestRactor < Test::Unit::TestCase
x = str.instance_exec { method(:itself).to_proc }
assert_unshareable(x, "can not make shareable object for #<Method: String(Kernel)#itself()>", exception: Ractor::Error)
+=end
end
def test_shareability_error_uses_inspect
@@ -65,7 +47,7 @@ class TestRactor < Test::Unit::TestCase
def x.to_s
raise "this should not be called"
end
- assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()>", exception: Ractor::Error)
+ assert_unshareable(x, "can not make shareable object for #<Method: String#to_s()> because it refers unshareable objects", exception: Ractor::Error)
end
def test_default_thread_group
@@ -74,11 +56,163 @@ class TestRactor < Test::Unit::TestCase
Warning[:experimental] = false
main_ractor_id = Thread.current.group.object_id
- ractor_id = Ractor.new { Thread.current.group.object_id }.take
+ ractor_id = Ractor.new { Thread.current.group.object_id }.value
refute_equal main_ractor_id, ractor_id
end;
end
+ def test_class_instance_variables
+ assert_ractor(<<~'RUBY')
+ # Once we're in multi-ractor mode, the codepaths
+ # for class instance variables are a bit different.
+ Ractor.new {}.value
+
+ class TestClass
+ @a = 1
+ @b = 2
+ @c = 3
+ @d = 4
+ end
+
+ assert_equal 4, TestClass.remove_instance_variable(:@d)
+ assert_nil TestClass.instance_variable_get(:@d)
+ assert_equal 4, TestClass.instance_variable_set(:@d, 4)
+ assert_equal 4, TestClass.instance_variable_get(:@d)
+ RUBY
+ end
+
+ def test_struct_instance_variables
+ assert_ractor(<<~'RUBY')
+ StructIvar = Struct.new(:member) do
+ def initialize(*)
+ super
+ @ivar = "ivar"
+ end
+ attr_reader :ivar
+ end
+ obj = StructIvar.new("member")
+ obj_copy = Ractor.new { Ractor.receive }.send(obj).value
+ assert_equal obj.ivar, obj_copy.ivar
+ refute_same obj.ivar, obj_copy.ivar
+ assert_equal obj.member, obj_copy.member
+ refute_same obj.member, obj_copy.member
+ RUBY
+ end
+
+ def test_move_nested_hash_during_gc_with_yjit
+ assert_ractor(<<~'RUBY', args: [{ "RUBY_YJIT_ENABLE" => "1" }])
+ GC.stress = true
+ hash = { foo: { bar: "hello" }, baz: { qux: "there" } }
+ result = Ractor.new { Ractor.receive }.send(hash, move: true).value
+ assert_equal "hello", result[:foo][:bar]
+ assert_equal "there", result[:baz][:qux]
+ RUBY
+ end
+
+ def test_fork_raise_isolation_error
+ assert_ractor(<<~'RUBY')
+ ractor = Ractor.new do
+ Process.fork
+ rescue Ractor::IsolationError => e
+ e
+ end
+ assert_equal Ractor::IsolationError, ractor.value.class
+ RUBY
+ end if Process.respond_to?(:fork)
+
+ def test_require_raises_and_no_ractor_belonging_issue
+ assert_ractor(<<~'RUBY')
+ require "tempfile"
+ f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
+ f.write("raise 'uh oh'")
+ f.flush
+ err_msg = Ractor.new(f.path) do |path|
+ begin
+ require path
+ rescue RuntimeError => e
+ e.message # had confirm belonging issue here
+ else
+ nil
+ end
+ end.value
+ assert_equal "uh oh", err_msg
+ RUBY
+ end
+
+ def test_require_non_string
+ assert_ractor(<<~'RUBY')
+ require "tempfile"
+ require "pathname"
+ f = Tempfile.new(["file_to_require_from_ractor", ".rb"])
+ f.write("")
+ f.flush
+ result = Ractor.new(f.path) do |path|
+ require Pathname.new(path)
+ "success"
+ end.value
+ assert_equal "success", result
+ RUBY
+ end
+
+ # [Bug #21398]
+ def test_port_receive_dnt_with_port_send
+ omit 'unstable on windows and macos-14' if RUBY_PLATFORM =~ /mswin|mingw|darwin/
+ assert_ractor(<<~'RUBY', timeout: 90)
+ THREADS = 10
+ JOBS_PER_THREAD = 50
+ ARRAY_SIZE = 20_000
+ def ractor_job(job_count, array_size)
+ port = Ractor::Port.new
+ workers = (1..4).map do |i|
+ Ractor.new(port) do |job_port|
+ while job = Ractor.receive
+ result = job.map { |x| x * 2 }.sum
+ job_port.send result
+ end
+ end
+ end
+ jobs = Array.new(job_count) { Array.new(array_size) { rand(1000) } }
+ jobs.each_with_index do |job, i|
+ w_idx = i % 4
+ workers[w_idx].send(job)
+ end
+ results = []
+ jobs.size.times do
+ result = port.receive # dnt receive
+ results << result
+ end
+ results
+ end
+ threads = []
+ # creates 40 ractors (THREADSx4)
+ THREADS.times do
+ threads << Thread.new do
+ ractor_job(JOBS_PER_THREAD, ARRAY_SIZE)
+ end
+ end
+ threads.each(&:join)
+ RUBY
+ end
+
+ # [Bug #20146]
+ def test_max_cpu_1
+ assert_ractor(<<~'RUBY', args: [{ "RUBY_MAX_CPU" => "1" }])
+ assert_equal :ok, Ractor.new { :ok }.value
+ RUBY
+ end
+
+ def test_symbol_proc_is_shareable
+ pr = :symbol.to_proc
+ assert_make_shareable(pr)
+ end
+
+ # [Bug #21775]
+ def test_ifunc_proc_not_shareable
+ h = Hash.new { self }
+ pr = h.to_proc
+ assert_unshareable(pr, /not supported yet/, exception: RuntimeError)
+ end
+
def assert_make_shareable(obj)
refute Ractor.shareable?(obj), "object was already shareable"
Ractor.make_shareable(obj)