aboutsummaryrefslogtreecommitdiffstats
path: root/spec/rubyspec/core/process/fixtures
diff options
context:
space:
mode:
authoreregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-05-07 12:04:49 +0000
committereregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2017-05-07 12:04:49 +0000
commita3736e97a6ca517c2cd7d3d93a8f2ef86e39e5b5 (patch)
tree9eef7f720314ebaff56845a74e203770e62284e4 /spec/rubyspec/core/process/fixtures
parent52df1d0d3370919711c0577aaa42d1a864709885 (diff)
downloadruby-a3736e97a6ca517c2cd7d3d93a8f2ef86e39e5b5.tar.gz
Add in-tree mspec and ruby/spec
* For easier modifications of ruby/spec by MRI developers. * .gitignore: track changes under spec. * spec/mspec, spec/rubyspec: add in-tree mspec and ruby/spec. These files can therefore be updated like any other file in MRI. Instructions are provided in spec/README. [Feature #13156] [ruby-core:79246] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58595 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'spec/rubyspec/core/process/fixtures')
-rw-r--r--spec/rubyspec/core/process/fixtures/common.rb79
-rw-r--r--spec/rubyspec/core/process/fixtures/daemon.rb111
-rw-r--r--spec/rubyspec/core/process/fixtures/env.rb1
-rw-r--r--spec/rubyspec/core/process/fixtures/kill.rb49
-rw-r--r--spec/rubyspec/core/process/fixtures/map_fd.rb8
-rw-r--r--spec/rubyspec/core/process/fixtures/print.rb1
6 files changed, 249 insertions, 0 deletions
diff --git a/spec/rubyspec/core/process/fixtures/common.rb b/spec/rubyspec/core/process/fixtures/common.rb
new file mode 100644
index 0000000000..abfd05bb18
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/common.rb
@@ -0,0 +1,79 @@
+module ProcessSpecs
+ class Daemonizer
+ attr_reader :input, :data
+
+ def initialize
+ # Fast feedback for implementations without Process.daemon
+ raise NotImplementedError, "Process.daemon is not implemented" unless Process.respond_to? :daemon
+
+ @script = fixture __FILE__, "daemon.rb"
+ @input = tmp("process_daemon_input_file")
+ @data = tmp("process_daemon_data_file")
+ @args = []
+ end
+
+ def wait_for_daemon
+ sleep 0.001 until File.exist?(@data) and File.size?(@data)
+ end
+
+ def invoke(behavior, arguments=[])
+ args = Marshal.dump(arguments).unpack("H*")
+ args << @input << @data << behavior
+
+ ruby_exe @script, args: args
+
+ wait_for_daemon
+
+ return unless File.exist? @data
+
+ File.open(@data, "rb") { |f| return f.read.chomp }
+ end
+ end
+
+ class Signalizer
+ attr_reader :pid_file, :pid
+
+ def initialize(scenario=nil)
+ platform_is :windows do
+ fail "not supported on windows"
+ end
+ @script = fixture __FILE__, "kill.rb"
+ @pid = nil
+ @pid_file = tmp("process_kill_signal_file")
+ rm_r @pid_file
+
+ @thread = Thread.new do
+ Thread.current.abort_on_exception = true
+ args = [@pid_file]
+ args << scenario if scenario
+ args << RUBY_EXE.inspect if scenario
+ @result = ruby_exe @script, args: args
+ end
+ Thread.pass while @thread.status and !File.exist?(@pid_file)
+ while @thread.status && (@pid.nil? || @pid == 0)
+ @pid = IO.read(@pid_file).chomp.to_i
+ end
+ end
+
+ def wait_on_result
+ # Ensure the process exits
+ begin
+ Process.kill :TERM, pid if pid
+ rescue Errno::ESRCH
+ # Ignore the process not existing
+ end
+
+ @thread.join
+ end
+
+ def cleanup
+ wait_on_result
+ rm_r pid_file
+ end
+
+ def result
+ wait_on_result
+ @result.chomp if @result
+ end
+ end
+end
diff --git a/spec/rubyspec/core/process/fixtures/daemon.rb b/spec/rubyspec/core/process/fixtures/daemon.rb
new file mode 100644
index 0000000000..772df2d09e
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/daemon.rb
@@ -0,0 +1,111 @@
+module ProcessSpecs
+ class Daemon
+ def initialize(argv)
+ args, @input, @data, @behavior = argv
+ @args = Marshal.load [args].pack("H*")
+ @no_at_exit = false
+ end
+
+ def run
+ send @behavior
+
+ # Exit without running any at_exit handlers
+ exit!(0) if @no_at_exit
+ end
+
+ def write(data)
+ File.open(@data, "wb") { |f| f.puts data }
+ end
+
+ def daemonizing_at_exit
+ at_exit do
+ write "running at_exit"
+ end
+
+ @no_at_exit = true
+ Process.daemon
+ write "not running at_exit"
+ end
+
+ def return_value
+ write Process.daemon.to_s
+ end
+
+ def pid
+ parent = Process.pid
+ Process.daemon
+ daemon = Process.pid
+ write "#{parent}:#{daemon}"
+ end
+
+ def process_group
+ parent = Process.getpgrp
+ Process.daemon
+ daemon = Process.getpgrp
+ write "#{parent}:#{daemon}"
+ end
+
+ def daemon_at_exit
+ at_exit do
+ write "running at_exit"
+ end
+
+ Process.daemon
+ end
+
+ def stay_in_dir
+ Process.daemon(*@args)
+ write Dir.pwd
+ end
+
+ def keep_stdio_open_false_stdout
+ Process.daemon(*@args)
+ $stdout.write "writing to stdout"
+ write ""
+ end
+
+ def keep_stdio_open_false_stderr
+ Process.daemon(*@args)
+ $stderr.write "writing to stderr"
+ write ""
+ end
+
+ def keep_stdio_open_false_stdin
+ Process.daemon(*@args)
+
+ # Reading from /dev/null will return right away. If STDIN were not
+ # /dev/null, reading would block and the spec would hang. This is not a
+ # perfect way to spec the behavior but it works.
+ write $stdin.read
+ end
+
+ def keep_stdio_open_true_stdout
+ $stdout.reopen @data
+ Process.daemon(*@args)
+ $stdout.write "writing to stdout"
+ end
+
+ def keep_stdio_open_true_stderr
+ $stderr.reopen @data
+ Process.daemon(*@args)
+ $stderr.write "writing to stderr"
+ end
+
+ def keep_stdio_open_true_stdin
+ File.open(@input, "w") { |f| f.puts "reading from stdin" }
+
+ $stdin.reopen @input, "r"
+ Process.daemon(*@args)
+ write $stdin.read
+ end
+
+ def keep_stdio_open_files
+ file = File.open @input, "w"
+
+ Process.daemon(*@args)
+ write file.closed?
+ end
+ end
+end
+
+ProcessSpecs::Daemon.new(ARGV).run
diff --git a/spec/rubyspec/core/process/fixtures/env.rb b/spec/rubyspec/core/process/fixtures/env.rb
new file mode 100644
index 0000000000..2d626caf26
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/env.rb
@@ -0,0 +1 @@
+File.write ARGV[0], ENV["FOO"]
diff --git a/spec/rubyspec/core/process/fixtures/kill.rb b/spec/rubyspec/core/process/fixtures/kill.rb
new file mode 100644
index 0000000000..dfebc5b3c3
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/kill.rb
@@ -0,0 +1,49 @@
+require 'thread'
+
+pid_file = ARGV.shift
+scenario = ARGV.shift
+ruby_exe = ARGV.shift
+
+# We must do this first otherwise there will be a race with the process that
+# creates this process and the TERM signal below could go to that process
+# instead, which will likely abort the specs process.
+Process.setsid if scenario && Process.respond_to?(:setsid)
+
+signaled = false
+mutex = Mutex.new
+
+Signal.trap(:TERM) do
+ if mutex.try_lock
+ unless signaled
+ signaled = true
+ STDOUT.puts "signaled"
+ STDOUT.flush
+ end
+ end
+end
+
+File.open(pid_file, "wb") { |f| f.puts Process.pid }
+
+if scenario
+ # We are sending a signal to ourselves or the process group
+ process = Process.respond_to?(:getpgid) ? "Process.getpgid(Process.pid)" : "Process.pid"
+
+ case scenario
+ when "self"
+ signal = %["SIGTERM"]
+ process = "0"
+ when "group_numeric"
+ signal = %[-Signal.list["TERM"]]
+ when "group_short_string"
+ signal = %["-TERM"]
+ when "group_full_string"
+ signal = %["-SIGTERM"]
+ else
+ raise "unknown scenario: #{scenario.inspect}"
+ end
+
+ cmd = %[#{ruby_exe} -e 'Process.kill(#{signal}, #{process})']
+ Thread.new { system cmd }.join
+end
+
+sleep 0.1 until signaled
diff --git a/spec/rubyspec/core/process/fixtures/map_fd.rb b/spec/rubyspec/core/process/fixtures/map_fd.rb
new file mode 100644
index 0000000000..fc542625b0
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/map_fd.rb
@@ -0,0 +1,8 @@
+fd = ARGV.shift.to_i
+
+f = File.for_fd fd
+begin
+ f.write "writing to fd: #{fd}"
+ensure
+ f.close
+end
diff --git a/spec/rubyspec/core/process/fixtures/print.rb b/spec/rubyspec/core/process/fixtures/print.rb
new file mode 100644
index 0000000000..3697f7dc93
--- /dev/null
+++ b/spec/rubyspec/core/process/fixtures/print.rb
@@ -0,0 +1 @@
+print :glark