Skip to content

Instantly share code, notes, and snippets.

@clicube
Last active December 14, 2015 20:18
Show Gist options
  • Save clicube/5142446 to your computer and use it in GitHub Desktop.
Save clicube/5142446 to your computer and use it in GitHub Desktop.
Process::Process class
module Process
class ProcessError < StandardError; end
class Process
attr_reader :pid
def initialize(*args, &block)
raise ArgumentError.new("block must be given") unless block_given?
@parent_pid = ::Process.pid
@pid = fork{ block.call *args }
@watching_thread = ::Process.detach(@pid) # avoid to be a zombie
end
def signal sig
::Process.kill sig, @pid
true
rescue Errno::ESRCH
false
end
def exist?
signal 0
end
def kill
signal :KILL
end
def term
signal :TERM
end
def child?
@parent_pid == ::Process.pid
end
def alive?
if @watching_thread.alive?
true
elsif child?
false
else
exist?
end
end
def join limit=nil
raise ProcessError.new("not a child process") unless child?
retval = limit ? @watching_thread.join(limit) : @watching_thread.join
retval ? self : nil
end
alias :wait :join
def value
raise ProcessError.new("not a child process") unless child?
@watching_thread.value
end
end
end
require 'test/unit'
require 'timeout'
require_relative 'process'
class TestProcess < Test::Unit::TestCase
def test_process_initialize
assert_nothing_raised{
Process::Process.new{ :nop }
}
assert_raise(ArgumentError){
Process::Process.new
}
end
def test_process_block_is_processed
pout, pin = IO.pipe
p = Process::Process.new{ pin.write "a" }
buf = nil
assert_nothing_raised(TimeoutError){
timeout(1){ buf = pout.read(1) }
}
assert_equal "a", buf
end
def test_process_pid
p = Process::Process.new{ :nop }
assert p.pid.is_a? Integer
assert p.pid > 1
assert_not_equal Process.pid, p.pid
end
def test_process_signal_and_exist?
p = Process::Process.new{ sleep 1 }
assert_equal true, p.exist?
retval = p.signal :TERM
assert_equal true, retval
sleep 0.1
assert_equal false, p.exist?
retval = p.signal :TERM
assert_equal false, retval
end
def test_process_term
p = Process::Process.new{ sleep 1 }
retval = p.term
assert_equal true, retval
sleep 0.1
assert_equal false, p.exist?
retval = p.term
assert_equal false, retval
end
def test_process_kill
p = Process::Process.new{ sleep 1 }
retval = p.kill
assert_equal true, retval
sleep 0.1
assert_equal false, p.exist?
retval = p.kill
assert_equal false, retval
end
def test_process_child?
p = Process::Process.new{ sleep 1 }
assert_equal true, p.child?
pout, pin = IO.pipe
fork{ pin.write( p.child? ? "T" : "F" ) }
result = nil
timeout(1){ result = pout.read(1) }
assert_equal "F", result
end
def test_process_alive?
p = Process::Process.new{ sleep 1 }
assert_equal true, p.alive?
p.term
sleep 0.1
assert_equal false, p.alive?
p = Process::Process.new{ sleep 1 }
pout, pin = IO.pipe
fork{ pin.write( p.alive? ? "T" : "F" ) }
result = nil
timeout(1){ result = pout.read(1) }
assert_equal "T", result
p.term
sleep 0.1
fork{ pin.write( p.alive? ? "T" : "F" ) }
result = nil
timeout(1){ result = pout.read(1) }
assert_equal "F", result
end
def test_process_join
p = Process::Process.new{ sleep 1 }
assert_raise(TimeoutError){
timeout(0.1){ p.join }
}
p = Process::Process.new{ sleep 0.1 }
retval = nil
timeout(1){ retval = p.join }
assert_equal p, retval
p = Process::Process.new{ :nop }
retval = nil
timeout(1){ retval = p.join }
assert_equal p, retval
p = Process::Process.new{ sleep 2 }
retval = true
timeout(1){ retval = p.join(0) }
assert_equal nil, retval
p = Process::Process.new{ sleep 1 }
pout, pin = IO.pipe
fork do
result = "P"
begin
p.join
rescue Process::ProcessError
result = "E"
rescue
end
pin.write result
end
result = nil
timeout(1){ result = pout.read(1) }
assert_equal "E", result
end
def test_process_value
p = Process::Process.new{ sleep 1 }
assert_raise(TimeoutError){
timeout(0.1){ p.value }
}
p = Process::Process.new{ sleep 0.1; exit 0}
retval = nil
timeout(1){ retval = p.value }
assert retval.is_a? Process::Status
assert_equal true, retval.success?
p = Process::Process.new{ sleep 0.1; exit 1}
retval = nil
timeout(1){ retval = p.value }
assert retval.is_a? Process::Status
assert_equal false, retval.success?
p = Process::Process.new{ sleep 1 }
pout, pin = IO.pipe
fork do
result = "P"
begin
p.value
rescue Process::ProcessError
result = "E"
rescue
end
pin.write result
end
result = nil
timeout(1){ result = pout.read(1) }
assert_equal "E", result
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment