2019-09-27 07:20:48 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2018-09-29 20:50:43 -04:00
|
|
|
require_relative "abstract_unit"
|
2019-09-27 07:20:48 -04:00
|
|
|
|
|
|
|
class ForkTrackerTest < ActiveSupport::TestCase
|
|
|
|
def test_object_fork
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
2019-09-30 17:01:50 -04:00
|
|
|
assert_not respond_to?(:fork)
|
2019-09-27 07:20:48 -04:00
|
|
|
pid = fork do
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
|
|
|
|
write.close
|
|
|
|
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
|
|
|
|
assert_not called
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_object_fork_without_block
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
if pid = fork
|
|
|
|
write.close
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
assert_not called
|
|
|
|
else
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_process_fork
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
pid = Process.fork do
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
|
|
|
|
write.close
|
|
|
|
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
assert_not called
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_process_fork_without_block
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
if pid = Process.fork
|
|
|
|
write.close
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
assert_not called
|
|
|
|
else
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_kernel_fork
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
pid = Kernel.fork do
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
|
|
|
|
write.close
|
|
|
|
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
assert_not called
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_kernel_fork_without_block
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
if pid = Kernel.fork
|
|
|
|
write.close
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
assert_not called
|
|
|
|
else
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
|
|
|
|
|
|
|
def test_check
|
|
|
|
count = 0
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork { count += 1 }
|
|
|
|
|
|
|
|
assert_no_difference -> { count } do
|
|
|
|
3.times { ActiveSupport::ForkTracker.check! }
|
|
|
|
end
|
|
|
|
|
|
|
|
Process.stub(:pid, Process.pid + 1) do
|
|
|
|
assert_difference -> { count }, +1 do
|
|
|
|
3.times { ActiveSupport::ForkTracker.check! }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
assert_difference -> { count }, +1 do
|
|
|
|
3.times { ActiveSupport::ForkTracker.check! }
|
|
|
|
end
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
2019-09-30 17:03:53 -04:00
|
|
|
|
|
|
|
def test_basic_object_with_kernel_fork
|
|
|
|
read, write = IO.pipe
|
|
|
|
called = false
|
|
|
|
|
|
|
|
handler = ActiveSupport::ForkTracker.after_fork do
|
|
|
|
called = true
|
|
|
|
write.write "forked"
|
|
|
|
end
|
|
|
|
|
|
|
|
klass = Class.new(BasicObject) do
|
|
|
|
include ::Kernel
|
|
|
|
def fark(&block)
|
|
|
|
fork(&block)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
object = klass.new
|
|
|
|
assert_not object.respond_to?(:fork)
|
|
|
|
pid = object.fark do
|
|
|
|
read.close
|
|
|
|
write.close
|
|
|
|
exit!
|
|
|
|
end
|
|
|
|
|
|
|
|
write.close
|
|
|
|
|
|
|
|
Process.waitpid(pid)
|
|
|
|
assert_equal "forked", read.read
|
|
|
|
read.close
|
|
|
|
|
|
|
|
assert_not called
|
|
|
|
ensure
|
|
|
|
ActiveSupport::ForkTracker.unregister(handler)
|
|
|
|
end
|
2019-10-06 17:41:37 -04:00
|
|
|
end if Process.respond_to?(:fork)
|