summaryrefslogtreecommitdiff
path: root/spec/ruby/core/process
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core/process')
-rw-r--r--spec/ruby/core/process/_fork_spec.rb24
-rw-r--r--spec/ruby/core/process/abort_spec.rb4
-rw-r--r--spec/ruby/core/process/argv0_spec.rb25
-rw-r--r--spec/ruby/core/process/clock_getres_spec.rb33
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb152
-rw-r--r--spec/ruby/core/process/constants_spec.rb141
-rw-r--r--spec/ruby/core/process/daemon_spec.rb17
-rw-r--r--spec/ruby/core/process/detach_spec.rb39
-rw-r--r--spec/ruby/core/process/egid_spec.rb43
-rw-r--r--spec/ruby/core/process/euid_spec.rb45
-rw-r--r--spec/ruby/core/process/exec_spec.rb107
-rw-r--r--spec/ruby/core/process/exit_spec.rb6
-rw-r--r--spec/ruby/core/process/fixtures/argv0.rb6
-rw-r--r--spec/ruby/core/process/fixtures/clocks.rb18
-rw-r--r--spec/ruby/core/process/fixtures/common.rb8
-rw-r--r--spec/ruby/core/process/fixtures/in.txt1
-rw-r--r--spec/ruby/core/process/fixtures/kill.rb2
-rw-r--r--spec/ruby/core/process/fixtures/map_fd.rb3
-rw-r--r--spec/ruby/core/process/fork_spec.rb4
-rw-r--r--spec/ruby/core/process/getpgid_spec.rb2
-rw-r--r--spec/ruby/core/process/getpgrp_spec.rb2
-rw-r--r--spec/ruby/core/process/getpriority_spec.rb10
-rw-r--r--spec/ruby/core/process/getrlimit_spec.rb35
-rw-r--r--spec/ruby/core/process/gid/change_privilege_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/eid_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/grant_privilege_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/re_exchange_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/re_exchangeable_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/rid_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/sid_available_spec.rb2
-rw-r--r--spec/ruby/core/process/gid/switch_spec.rb2
-rw-r--r--spec/ruby/core/process/gid_spec.rb6
-rw-r--r--spec/ruby/core/process/groups_spec.rb19
-rw-r--r--spec/ruby/core/process/initgroups_spec.rb30
-rw-r--r--spec/ruby/core/process/kill_spec.rb20
-rw-r--r--spec/ruby/core/process/last_status_spec.rb18
-rw-r--r--spec/ruby/core/process/maxgroups_spec.rb4
-rw-r--r--spec/ruby/core/process/pid_spec.rb4
-rw-r--r--spec/ruby/core/process/ppid_spec.rb20
-rw-r--r--spec/ruby/core/process/set_proctitle_spec.rb2
-rw-r--r--spec/ruby/core/process/setpgid_spec.rb5
-rw-r--r--spec/ruby/core/process/setpgrp_spec.rb2
-rw-r--r--spec/ruby/core/process/setpriority_spec.rb33
-rw-r--r--spec/ruby/core/process/setrlimit_spec.rb57
-rw-r--r--spec/ruby/core/process/setsid_spec.rb39
-rw-r--r--spec/ruby/core/process/spawn_spec.rb408
-rw-r--r--spec/ruby/core/process/status/bit_and_spec.rb39
-rw-r--r--spec/ruby/core/process/status/coredump_spec.rb2
-rw-r--r--spec/ruby/core/process/status/equal_value_spec.rb14
-rw-r--r--spec/ruby/core/process/status/exited_spec.rb9
-rw-r--r--spec/ruby/core/process/status/exitstatus_spec.rb18
-rw-r--r--spec/ruby/core/process/status/inspect_spec.rb2
-rw-r--r--spec/ruby/core/process/status/pid_spec.rb2
-rw-r--r--spec/ruby/core/process/status/right_shift_spec.rb38
-rw-r--r--spec/ruby/core/process/status/signaled_spec.rb8
-rw-r--r--spec/ruby/core/process/status/stopped_spec.rb2
-rw-r--r--spec/ruby/core/process/status/stopsig_spec.rb2
-rw-r--r--spec/ruby/core/process/status/success_spec.rb16
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb26
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb12
-rw-r--r--spec/ruby/core/process/status/to_int_spec.rb2
-rw-r--r--spec/ruby/core/process/status/to_s_spec.rb2
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb100
-rw-r--r--spec/ruby/core/process/sys/getegid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/geteuid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/getgid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/getuid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/issetugid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setegid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/seteuid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setgid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setregid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setresgid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setresuid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setreuid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setrgid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setruid_spec.rb2
-rw-r--r--spec/ruby/core/process/sys/setuid_spec.rb2
-rw-r--r--spec/ruby/core/process/times_spec.rb32
-rw-r--r--spec/ruby/core/process/tms/cstime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/cutime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/stime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/utime_spec.rb17
-rw-r--r--spec/ruby/core/process/uid/change_privilege_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/eid_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/grant_privilege_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/re_exchange_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/re_exchangeable_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/rid_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/sid_available_spec.rb2
-rw-r--r--spec/ruby/core/process/uid/switch_spec.rb2
-rw-r--r--spec/ruby/core/process/uid_spec.rb63
-rw-r--r--spec/ruby/core/process/wait2_spec.rb21
-rw-r--r--spec/ruby/core/process/wait_spec.rb21
-rw-r--r--spec/ruby/core/process/waitall_spec.rb6
-rw-r--r--spec/ruby/core/process/waitpid2_spec.rb2
-rw-r--r--spec/ruby/core/process/waitpid_spec.rb7
-rw-r--r--spec/ruby/core/process/warmup_spec.rb11
98 files changed, 1383 insertions, 598 deletions
diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb
new file mode 100644
index 0000000000..e1f45e2656
--- /dev/null
+++ b/spec/ruby/core/process/_fork_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+
+describe "Process._fork" do
+ it "for #respond_to? returns the same as Process.respond_to?(:fork)" do
+ Process.respond_to?(:_fork).should == Process.respond_to?(:fork)
+ end
+
+ # Using respond_to? in a guard here is OK because the correct semantics
+ # are that _fork is implemented if and only if fork is (see above).
+ guard_not -> { Process.respond_to?(:fork) } do
+ it "raises a NotImplementedError when called" do
+ -> { Process._fork }.should raise_error(NotImplementedError)
+ end
+ end
+
+ guard -> { Process.respond_to?(:fork) } do
+ it "is called by Process#fork" do
+ Process.should_receive(:_fork).once.and_return(42)
+
+ pid = Process.fork {}
+ pid.should equal(42)
+ end
+ end
+end
diff --git a/spec/ruby/core/process/abort_spec.rb b/spec/ruby/core/process/abort_spec.rb
index f7113c8b7e..1b6ad1da43 100644
--- a/spec/ruby/core/process/abort_spec.rb
+++ b/spec/ruby/core/process/abort_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/process/abort', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/process/abort'
describe "Process.abort" do
it_behaves_like :process_abort, :abort, Process
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
new file mode 100644
index 0000000000..f5aba719e9
--- /dev/null
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+describe "Process.argv0" do
+ it "returns a String" do
+ Process.argv0.should be_kind_of(String)
+ end
+
+ it "is the path given as the main script and the same as __FILE__" do
+ script = "fixtures/argv0.rb"
+
+ Dir.chdir(__dir__) do
+ ruby_exe(script).should == "#{script}\n#{script}\nOK"
+ end
+ end
+
+ ruby_bug "#19597", ""..."3.3" do
+ it "returns a frozen object" do
+ Process.argv0.should.frozen?
+ end
+ end
+
+ it "returns every time the same object" do
+ Process.argv0.should.equal?(Process.argv0)
+ end
+end
diff --git a/spec/ruby/core/process/clock_getres_spec.rb b/spec/ruby/core/process/clock_getres_spec.rb
new file mode 100644
index 0000000000..85aa2b25f1
--- /dev/null
+++ b/spec/ruby/core/process/clock_getres_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../spec_helper'
+
+describe "Process.clock_getres" do
+ # These are documented
+
+ it "with :GETTIMEOFDAY_BASED_CLOCK_REALTIME reports 1 microsecond" do
+ Process.clock_getres(:GETTIMEOFDAY_BASED_CLOCK_REALTIME, :nanosecond).should == 1_000
+ end
+
+ it "with :TIME_BASED_CLOCK_REALTIME reports 1 second" do
+ Process.clock_getres(:TIME_BASED_CLOCK_REALTIME, :nanosecond).should == 1_000_000_000
+ end
+
+ platform_is_not :windows do
+ it "with :GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID reports 1 microsecond" do
+ Process.clock_getres(:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID, :nanosecond).should == 1_000
+ end
+ end
+
+ # These are observed
+
+ platform_is :linux, :darwin, :windows do
+ it "with Process::CLOCK_REALTIME reports at least 10 millisecond" do
+ Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond).should <= 10_000_000
+ end
+ end
+
+ platform_is :linux, :darwin, :windows do
+ it "with Process::CLOCK_MONOTONIC reports at least 10 millisecond" do
+ Process.clock_getres(Process::CLOCK_MONOTONIC, :nanosecond).should <= 10_000_000
+ end
+ end
+end
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
new file mode 100644
index 0000000000..6c1a52f21e
--- /dev/null
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -0,0 +1,152 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/clocks'
+
+describe "Process.clock_gettime" do
+ ProcessSpecs.clock_constants.each do |name, value|
+ it "can be called with Process::#{name}" do
+ Process.clock_gettime(value).should be_an_instance_of(Float)
+ end
+ end
+
+ describe 'time units' do
+ it 'handles a fixed set of time units' do
+ [:nanosecond, :microsecond, :millisecond, :second].each do |unit|
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_kind_of(Integer)
+ end
+
+ [:float_microsecond, :float_millisecond, :float_second].each do |unit|
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, unit).should be_an_instance_of(Float)
+ end
+ end
+
+ it 'raises an ArgumentError for an invalid time unit' do
+ -> { Process.clock_gettime(Process::CLOCK_MONOTONIC, :bad) }.should raise_error(ArgumentError)
+ end
+
+ it 'defaults to :float_second' do
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
+
+ t1.should be_an_instance_of(Float)
+ t2.should be_an_instance_of(Float)
+ t2.should be_close(t1, TIME_TOLERANCE)
+ end
+
+ it 'uses the default time unit (:float_second) when passed nil' do
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC, nil)
+ t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC, :float_second)
+
+ t1.should be_an_instance_of(Float)
+ t2.should be_an_instance_of(Float)
+ t2.should be_close(t1, TIME_TOLERANCE)
+ end
+ end
+
+ describe "supports the platform clocks mentioned in the documentation" do
+ it "CLOCK_REALTIME" do
+ Process.clock_gettime(Process::CLOCK_REALTIME).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC).should be_an_instance_of(Float)
+ end
+
+ # These specs need macOS 10.12+ / darwin 16+
+ guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
+ platform_is :linux, :openbsd, :darwin do
+ it "CLOCK_PROCESS_CPUTIME_ID" do
+ Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :linux, :freebsd, :openbsd, :darwin do
+ it "CLOCK_THREAD_CPUTIME_ID" do
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :linux, :darwin do
+ it "CLOCK_MONOTONIC_RAW" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :darwin do
+ it "CLOCK_MONOTONIC_RAW_APPROX" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW_APPROX).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_UPTIME_RAW and CLOCK_UPTIME_RAW_APPROX" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
+ end
+ end
+ end
+
+ platform_is :freebsd do
+ it "CLOCK_VIRTUAL" do
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_PROF" do
+ Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :freebsd, :openbsd do
+ it "CLOCK_UPTIME" do
+ Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ end
+ end
+
+ platform_is :freebsd do
+ it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_SECOND" do
+ Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
+ it "CLOCK_REALTIME_COARSE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_COARSE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
+ it "CLOCK_BOOTTIME" do
+ skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
+ it "CLOCK_REALTIME_ALARM" do
+ skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_BOOTTIME_ALARM" do
+ skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb
index 2fa93ad8bf..57cacadef2 100644
--- a/spec/ruby/core/process/constants_spec.rb
+++ b/spec/ruby/core/process/constants_spec.rb
@@ -1,63 +1,114 @@
+require_relative '../../spec_helper'
describe "Process::Constants" do
platform_is :darwin, :netbsd, :freebsd do
- it "has the correct constant values on BSD-like systems" do
- Process::WNOHANG.should == 1
- Process::WUNTRACED.should == 2
- Process::PRIO_PROCESS.should == 0
- Process::PRIO_PGRP.should == 1
- Process::PRIO_USER.should == 2
- Process::RLIM_INFINITY.should == 9223372036854775807
- Process::RLIMIT_CPU.should == 0
- Process::RLIMIT_FSIZE.should == 1
- Process::RLIMIT_DATA.should == 2
- Process::RLIMIT_STACK.should == 3
- Process::RLIMIT_CORE.should == 4
- Process::RLIMIT_RSS.should == 5
- Process::RLIMIT_MEMLOCK.should == 6
- Process::RLIMIT_NPROC.should == 7
- Process::RLIMIT_NOFILE.should == 8
+ it "are all present on BSD-like systems" do
+ %i[
+ WNOHANG
+ WUNTRACED
+ PRIO_PROCESS
+ PRIO_PGRP
+ PRIO_USER
+ RLIM_INFINITY
+ RLIMIT_CPU
+ RLIMIT_FSIZE
+ RLIMIT_DATA
+ RLIMIT_STACK
+ RLIMIT_CORE
+ RLIMIT_RSS
+ RLIMIT_MEMLOCK
+ RLIMIT_NPROC
+ RLIMIT_NOFILE
+ ].each do |const|
+ Process.const_defined?(const).should be_true
+ Process.const_get(const).should be_an_instance_of(Integer)
+ end
end
end
platform_is :darwin do
- it "has the correct constant values on Darwin" do
- Process::RLIM_SAVED_MAX.should == 9223372036854775807
- Process::RLIM_SAVED_CUR.should == 9223372036854775807
- Process::RLIMIT_AS.should == 5
+ it "are all present on Darwin" do
+ %i[
+ RLIM_SAVED_MAX
+ RLIM_SAVED_CUR
+ RLIMIT_AS
+ ].each do |const|
+ Process.const_defined?(const).should be_true
+ Process.const_get(const).should be_an_instance_of(Integer)
+ end
end
end
platform_is :linux do
- it "has the correct constant values on Linux" do
- Process::WNOHANG.should == 1
- Process::WUNTRACED.should == 2
- Process::PRIO_PROCESS.should == 0
- Process::PRIO_PGRP.should == 1
- Process::PRIO_USER.should == 2
- Process::RLIMIT_CPU.should == 0
- Process::RLIMIT_FSIZE.should == 1
- Process::RLIMIT_DATA.should == 2
- Process::RLIMIT_STACK.should == 3
- Process::RLIMIT_CORE.should == 4
- Process::RLIMIT_RSS.should == 5
- Process::RLIMIT_NPROC.should == 6
- Process::RLIMIT_NOFILE.should == 7
- Process::RLIMIT_MEMLOCK.should == 8
- Process::RLIMIT_AS.should == 9
-
- # These values appear to change according to the platform.
- values = [4294967295, 9223372036854775807, 18446744073709551615]
- values.include?(Process::RLIM_INFINITY).should be_true
- values.include?(Process::RLIM_SAVED_MAX).should be_true
- values.include?(Process::RLIM_SAVED_CUR).should be_true
+ it "are all present on Linux" do
+ %i[
+ WNOHANG
+ WUNTRACED
+ PRIO_PROCESS
+ PRIO_PGRP
+ PRIO_USER
+ RLIMIT_CPU
+ RLIMIT_FSIZE
+ RLIMIT_DATA
+ RLIMIT_STACK
+ RLIMIT_CORE
+ RLIMIT_RSS
+ RLIMIT_NPROC
+ RLIMIT_NOFILE
+ RLIMIT_MEMLOCK
+ RLIMIT_AS
+ RLIM_INFINITY
+ RLIM_SAVED_MAX
+ RLIM_SAVED_CUR
+ ].each do |const|
+ Process.const_defined?(const).should be_true
+ Process.const_get(const).should be_an_instance_of(Integer)
+ end
end
end
platform_is :netbsd, :freebsd do
- it "Process::RLIMIT_SBSIZE" do
- Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal?
- Process::RLIMIT_AS.should == 10
+ it "are all present on NetBSD and FreeBSD" do
+ %i[
+ RLIMIT_SBSIZE
+ RLIMIT_AS
+ ].each do |const|
+ Process.const_defined?(const).should be_true
+ Process.const_get(const).should be_an_instance_of(Integer)
+ end
+ end
+ end
+
+ platform_is :freebsd do
+ it "are all present on FreeBSD" do
+ %i[
+ RLIMIT_NPTS
+ ].each do |const|
+ Process.const_defined?(const).should be_true
+ Process.const_get(const).should be_an_instance_of(Integer)
+ end
+ end
+ end
+
+ platform_is :windows do
+ it "does not define RLIMIT constants" do
+ %i[
+ RLIMIT_CPU
+ RLIMIT_FSIZE
+ RLIMIT_DATA
+ RLIMIT_STACK
+ RLIMIT_CORE
+ RLIMIT_RSS
+ RLIMIT_NPROC
+ RLIMIT_NOFILE
+ RLIMIT_MEMLOCK
+ RLIMIT_AS
+ RLIM_INFINITY
+ RLIM_SAVED_MAX
+ RLIM_SAVED_CUR
+ ].each do |const|
+ Process.const_defined?(const).should be_false
+ end
end
end
end
diff --git a/spec/ruby/core/process/daemon_spec.rb b/spec/ruby/core/process/daemon_spec.rb
index f68ddfe253..20b0d743b9 100644
--- a/spec/ruby/core/process/daemon_spec.rb
+++ b/spec/ruby/core/process/daemon_spec.rb
@@ -1,7 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/common', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
platform_is_not :windows do
+ # macOS 15 is not working this examples
+ return if /darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion`
+
describe :process_daemon_keep_stdio_open_false, shared: true do
it "redirects stdout to /dev/null" do
@daemon.invoke("keep_stdio_open_false_stdout", @object).should == ""
@@ -86,10 +89,6 @@ platform_is_not :windows do
@daemon.invoke("stay_in_dir", [true]).should == @invoke_dir
end
- it "does not change to the root directory if the first argument is non-false" do
- @daemon.invoke("stay_in_dir", [:yes]).should == @invoke_dir
- end
-
describe "when the second argument is not given" do
it_behaves_like :process_daemon_keep_stdio_open_false, nil, [false]
end
@@ -105,17 +104,13 @@ platform_is_not :windows do
describe "when the second argument is true" do
it_behaves_like :process_daemon_keep_stdio_open_true, nil, [false, true]
end
-
- describe "when the second argument is non-false" do
- it_behaves_like :process_daemon_keep_stdio_open_true, nil, [false, :yes]
- end
end
end
platform_is :windows do
describe "Process.daemon" do
it "raises a NotImplementedError" do
- lambda {
+ -> {
Process.daemon
}.should raise_error(NotImplementedError)
end
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index 7a38e290ce..f13bda1f5d 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.detach" do
platform_is_not :windows do
@@ -23,7 +23,7 @@ describe "Process.detach" do
it "reaps the child process's status automatically" do
pid = Process.fork { Process.exit! }
Process.detach(pid).join
- lambda { Process.waitpid(pid) }.should raise_error(Errno::ECHILD)
+ -> { Process.waitpid(pid) }.should raise_error(Errno::ECHILD)
end
end
@@ -42,5 +42,40 @@ describe "Process.detach" do
thr.pid.should == pid
end
+
+ it "tolerates not existing child process pid" do
+ # Use a value that is close to the INT_MAX (pid usually is signed int).
+ # It should (at least) be greater than allowed pid limit value that depends on OS.
+ pid_not_existing = 2.pow(30)
+
+ # Check that there is no a child process with this hardcoded pid.
+ # Command `kill 0 pid`:
+ # - returns "1" if a process exists and
+ # - raises Errno::ESRCH otherwise
+ -> { Process.kill(0, pid_not_existing) }.should raise_error(Errno::ESRCH)
+
+ thr = Process.detach(pid_not_existing)
+ thr.join
+
+ thr.should be_kind_of(Thread)
+ end
+
+ it "calls #to_int to implicitly convert non-Integer pid to Integer" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(100500)
+
+ Process.detach(pid).join
+ end
+
+ it "raises TypeError when pid argument does not have #to_int method" do
+ -> { Process.detach(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises TypeError when #to_int returns non-Integer value" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(:symbol)
+
+ -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)")
+ end
end
end
diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb
index 316343944c..a67b623d5c 100644
--- a/spec/ruby/core/process/egid_spec.rb
+++ b/spec/ruby/core/process/egid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.egid" do
it "returns the effective group ID for this process" do
@@ -15,5 +15,44 @@ describe "Process.egid" do
end
describe "Process.egid=" do
- it "needs to be reviewed for spec completeness"
+
+ platform_is_not :windows do
+ it "raises TypeError if not passed an Integer or String" do
+ -> { Process.egid = Object.new }.should raise_error(TypeError)
+ end
+
+ it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
+ raise unless Process.gid == Process.egid
+
+ require "etc"
+ group = Etc.getgrgid(Process.gid).name
+
+ Process.egid = group
+ Process.egid.should == Process.gid
+ end
+
+ as_user do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
+ -> { Process.egid = 0 }.should raise_error(Errno::EPERM)
+ end
+
+ platform_is :linux do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
+ -> { Process.egid = "root" }.should raise_error(Errno::EPERM)
+ end
+ end
+ end
+
+ as_superuser do
+ context "when ran by a superuser" do
+ it "sets the effective group id for the current process if run by a superuser" do
+ code = <<-RUBY
+ Process.egid = 1
+ puts Process.egid
+ RUBY
+ ruby_exe(code).should == "1\n"
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb
index 1855ef66f5..c1ec4171d0 100644
--- a/spec/ruby/core/process/euid_spec.rb
+++ b/spec/ruby/core/process/euid_spec.rb
@@ -1,8 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.euid" do
it "returns the effective user ID for this process" do
- Process.euid.should be_kind_of(Fixnum)
+ Process.euid.should be_kind_of(Integer)
end
it "also goes by Process::UID.eid" do
@@ -18,40 +18,37 @@ describe "Process.euid=" do
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- lambda { Process.euid = Object.new }.should raise_error(TypeError)
+ -> { Process.euid = Object.new }.should raise_error(TypeError)
+ end
+
+ it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
+ raise unless Process.uid == Process.euid
+
+ require "etc"
+ user = Etc.getpwuid(Process.uid).name
+
+ Process.euid = user
+ Process.euid.should == Process.uid
end
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
- lambda { (Process.euid = 0)}.should raise_error(Errno::EPERM)
+ -> { Process.euid = 0 }.should raise_error(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do
- lambda { Process.euid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.euid = "root" }.should raise_error(Errno::EPERM)
end
end
as_superuser do
describe "if run by a superuser" do
- with_feature :fork do
- it "sets the effective user id for the current process if run by a superuser" do
- read, write = IO.pipe
- pid = Process.fork do
- begin
- read.close
- Process.euid = 1
- write << Process.euid
- write.close
- rescue Exception => e
- write << e << e.backtrace
- end
- Process.exit!
- end
- write.close
- euid = read.gets
- euid.should == "1"
- Process.wait pid
- end
+ it "sets the effective user id for the current process if run by a superuser" do
+ code = <<-RUBY
+ Process.euid = 1
+ puts Process.euid
+ RUBY
+ ruby_exe(code).should == "1\n"
end
end
end
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index b4eddf526e..0f371b39c8 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -1,57 +1,49 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.exec" do
it "raises Errno::ENOENT for an empty string" do
- lambda { Process.exec "" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "" }.should raise_error(Errno::ENOENT)
end
it "raises Errno::ENOENT for a command which does not exist" do
- lambda { Process.exec "bogus-noent-script.sh" }.should raise_error(Errno::ENOENT)
+ -> { Process.exec "bogus-noent-script.sh" }.should raise_error(Errno::ENOENT)
end
it "raises an ArgumentError if the command includes a null byte" do
- lambda { Process.exec "\000" }.should raise_error(ArgumentError)
+ -> { Process.exec "\000" }.should raise_error(ArgumentError)
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises Errno::EACCES when the file does not have execute permissions" do
- lambda { Process.exec __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.exec __FILE__ }.should raise_error(Errno::EACCES)
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- lambda { Process.exec __FILE__ }.should raise_error(SystemCallError) { |e|
+ -> { Process.exec __FILE__ }.should raise_error(SystemCallError) { |e|
[Errno::EACCES, Errno::ENOEXEC].should include(e.class)
}
end
end
end
- platform_is_not :openbsd do
- it "raises Errno::EACCES when passed a directory" do
- lambda { Process.exec File.dirname(__FILE__) }.should raise_error(Errno::EACCES)
- end
- end
-
- platform_is :openbsd do
- it "raises Errno::EISDIR when passed a directory" do
- lambda { Process.exec File.dirname(__FILE__) }.should raise_error(Errno::EISDIR)
- end
+ it "raises Errno::EACCES when passed a directory" do
+ -> { Process.exec __dir__ }.should raise_error(Errno::EACCES)
end
it "runs the specified command, replacing current process" do
- ruby_exe('Process.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('Process.exec "echo hello"; puts "fail"').should == "hello\n"
end
it "sets the current directory when given the :chdir option" do
tmpdir = tmp("")[0..-2]
platform_is_not :windows do
- ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})", escape: true).should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})").should == "#{tmpdir}\n"
end
platform_is :windows do
- ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})", escape: true).tr('\\', '/').should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})").tr('\\', '/').should == "#{tmpdir}\n"
end
end
@@ -81,13 +73,13 @@ describe "Process.exec" do
platform_is_not :windows do
it "subjects the specified command to shell expansion" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"', escape: true)
+ ruby_exe('Process.exec "echo *"')
end
result.chomp.should == @name
end
it "creates an argument array with shell parsing semantics for whitespace" do
- ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
end
end
@@ -95,13 +87,13 @@ describe "Process.exec" do
# There is no shell expansion on Windows
it "does not subject the specified command to shell expansion on Windows" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"', escape: true)
+ ruby_exe('Process.exec "echo *"')
end
result.should == "*\n"
end
it "does not create an argument array with shell parsing semantics for whitespace on Windows" do
- ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
end
end
@@ -113,7 +105,7 @@ describe "Process.exec" do
platform_is :windows do
cmd = '"cmd.exe", "/C", "echo", "*"'
end
- ruby_exe("Process.exec #{cmd}", escape: true).should == "*\n"
+ ruby_exe("Process.exec #{cmd}").should == "*\n"
end
end
@@ -132,29 +124,29 @@ describe "Process.exec" do
end
it "sets environment variables in the child environment" do
- ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")', escape: true).should == "BAR\n"
+ ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")').should == "BAR\n"
end
it "unsets environment variables whose value is nil" do
platform_is_not :windows do
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == "\n"
end
platform_is :windows do
# On Windows, echo-ing a non-existent env var is treated as echo-ing any other string of text
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == var + "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == var + "\n"
end
end
it "coerces environment argument using to_hash" do
- ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")', escape: true).should == "BAR\n"
+ ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")').should == "BAR\n"
end
it "unsets other environment variables when given a true :unsetenv_others option" do
platform_is_not :windows do
- ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)', escape: true).should == "\n"
+ ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)').should == "\n"
end
platform_is :windows do
- ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)', escape: true).should == var + "\n"
+ ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)').should == var + "\n"
end
end
end
@@ -162,26 +154,26 @@ describe "Process.exec" do
describe "with a command array" do
it "uses the first element as the command name and the second as the argv[0] value" do
platform_is_not :windows do
- ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")', escape: true).should == "argv_zero\n"
+ ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")').should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
+ ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")').should == "argv_zero\n"
end
end
it "coerces the argument using to_ary" do
platform_is_not :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")', escape: true).should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")').should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")').should == "argv_zero\n"
end
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- lambda { Process.exec([]) }.should raise_error(ArgumentError)
- lambda { Process.exec([:a]) }.should raise_error(ArgumentError)
- lambda { Process.exec([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.exec([]) }.should raise_error(ArgumentError)
+ -> { Process.exec([:a]) }.should raise_error(ArgumentError)
+ -> { Process.exec([:a, :b, :c]) }.should raise_error(ArgumentError)
end
end
@@ -200,18 +192,49 @@ describe "Process.exec" do
it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do
map_fd_fixture = fixture __FILE__, "map_fd.rb"
cmd = <<-EOC
- f = File.open("#{@name}", "w+")
- child_fd = f.fileno + 1
- File.open("#{@child_fd_file}", "w") { |io| io.print child_fd }
- Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f }
+ f = File.open(#{@name.inspect}, "w+")
+ File.open(#{__FILE__.inspect}, "r") do |io|
+ child_fd = io.fileno
+ File.open(#{@child_fd_file.inspect}, "w") { |io| io.print child_fd }
+ Process.exec "#{ruby_cmd(map_fd_fixture)} \#{child_fd}", { child_fd => f }
+ end
EOC
- ruby_exe(cmd, escape: true)
+ ruby_exe(cmd)
child_fd = IO.read(@child_fd_file).to_i
child_fd.to_i.should > STDERR.fileno
File.read(@name).should == "writing to fd: #{child_fd}"
end
+
+ it "lets the process after exec have specified file descriptor despite close_on_exec" do
+ map_fd_fixture = fixture __FILE__, "map_fd.rb"
+ cmd = <<-EOC
+ f = File.open(#{@name.inspect}, 'w+')
+ puts(f.fileno, f.close_on_exec?)
+ STDOUT.flush
+ Process.exec("#{ruby_cmd(map_fd_fixture)} \#{f.fileno}", f.fileno => f.fileno)
+ EOC
+
+ output = ruby_exe(cmd)
+ child_fd, close_on_exec = output.split
+
+ child_fd.to_i.should > STDERR.fileno
+ close_on_exec.should == 'true'
+ File.read(@name).should == "writing to fd: #{child_fd}"
+ end
+
+ it "sets close_on_exec to false on specified fd even when it fails" do
+ cmd = <<-EOC
+ f = File.open(#{__FILE__.inspect}, 'r')
+ puts(f.close_on_exec?)
+ Process.exec('/', f.fileno => f.fileno) rescue nil
+ puts(f.close_on_exec?)
+ EOC
+
+ output = ruby_exe(cmd)
+ output.split.should == ['true', 'false']
+ end
end
end
end
diff --git a/spec/ruby/core/process/exit_spec.rb b/spec/ruby/core/process/exit_spec.rb
index 7cbd0c363e..4f7dc94407 100644
--- a/spec/ruby/core/process/exit_spec.rb
+++ b/spec/ruby/core/process/exit_spec.rb
@@ -1,10 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/process/exit', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/process/exit'
describe "Process.exit" do
it_behaves_like :process_exit, :exit, Process
end
describe "Process.exit!" do
- it_behaves_like :process_exit!, :exit!, Process
+ it_behaves_like :process_exit!, :exit!, "Process"
end
diff --git a/spec/ruby/core/process/fixtures/argv0.rb b/spec/ruby/core/process/fixtures/argv0.rb
new file mode 100644
index 0000000000..847a3e903e
--- /dev/null
+++ b/spec/ruby/core/process/fixtures/argv0.rb
@@ -0,0 +1,6 @@
+puts Process.argv0
+puts __FILE__
+
+if Process.argv0 == __FILE__
+ print "OK"
+end
diff --git a/spec/ruby/core/process/fixtures/clocks.rb b/spec/ruby/core/process/fixtures/clocks.rb
new file mode 100644
index 0000000000..5757e280be
--- /dev/null
+++ b/spec/ruby/core/process/fixtures/clocks.rb
@@ -0,0 +1,18 @@
+module ProcessSpecs
+ def self.clock_constants
+ clocks = []
+
+ platform_is_not :windows do
+ clocks += Process.constants.select { |c| c.to_s.start_with?('CLOCK_') }
+
+ # These require CAP_WAKE_ALARM and are not documented in
+ # Process#clock_gettime. They return EINVAL if the permission
+ # is not granted.
+ clocks -= [:CLOCK_BOOTTIME_ALARM, :CLOCK_REALTIME_ALARM]
+ end
+
+ clocks.sort.map { |c|
+ [c, Process.const_get(c)]
+ }
+ end
+end
diff --git a/spec/ruby/core/process/fixtures/common.rb b/spec/ruby/core/process/fixtures/common.rb
index bdbf1e654b..f49513d262 100644
--- a/spec/ruby/core/process/fixtures/common.rb
+++ b/spec/ruby/core/process/fixtures/common.rb
@@ -3,11 +3,15 @@ module ProcessSpecs
if defined?(MSpecScript::SYSTEM_RUBY)
context.send(:before, :all) do
@ruby = ::RUBY_EXE
- Object.const_set(:RUBY_EXE, MSpecScript::SYSTEM_RUBY)
+ suppress_warning {
+ Object.const_set(:RUBY_EXE, MSpecScript::SYSTEM_RUBY)
+ }
end
context.send(:after, :all) do
- Object.const_set(:RUBY_EXE, @ruby)
+ suppress_warning {
+ Object.const_set(:RUBY_EXE, @ruby)
+ }
end
end
end
diff --git a/spec/ruby/core/process/fixtures/in.txt b/spec/ruby/core/process/fixtures/in.txt
new file mode 100644
index 0000000000..cf52303bdc
--- /dev/null
+++ b/spec/ruby/core/process/fixtures/in.txt
@@ -0,0 +1 @@
+stdin
diff --git a/spec/ruby/core/process/fixtures/kill.rb b/spec/ruby/core/process/fixtures/kill.rb
index 0b88f8ee1f..b922a043f1 100644
--- a/spec/ruby/core/process/fixtures/kill.rb
+++ b/spec/ruby/core/process/fixtures/kill.rb
@@ -1,5 +1,3 @@
-require 'thread'
-
pid_file = ARGV.shift
scenario = ARGV.shift
diff --git a/spec/ruby/core/process/fixtures/map_fd.rb b/spec/ruby/core/process/fixtures/map_fd.rb
index fc542625b0..3ed887486b 100644
--- a/spec/ruby/core/process/fixtures/map_fd.rb
+++ b/spec/ruby/core/process/fixtures/map_fd.rb
@@ -1,6 +1,7 @@
fd = ARGV.shift.to_i
-f = File.for_fd fd
+f = File.for_fd(fd)
+f.autoclose = false
begin
f.write "writing to fd: #{fd}"
ensure
diff --git a/spec/ruby/core/process/fork_spec.rb b/spec/ruby/core/process/fork_spec.rb
index 2de2231dc5..a4f765247d 100644
--- a/spec/ruby/core/process/fork_spec.rb
+++ b/spec/ruby/core/process/fork_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../../../shared/process/fork', __FILE__)
+require_relative '../../spec_helper'
+require_relative '../../shared/process/fork'
describe "Process.fork" do
it_behaves_like :process_fork, :fork, Process
diff --git a/spec/ruby/core/process/getpgid_spec.rb b/spec/ruby/core/process/getpgid_spec.rb
index b92fb15152..c1dd007b16 100644
--- a/spec/ruby/core/process/getpgid_spec.rb
+++ b/spec/ruby/core/process/getpgid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.getpgid" do
platform_is_not :windows do
diff --git a/spec/ruby/core/process/getpgrp_spec.rb b/spec/ruby/core/process/getpgrp_spec.rb
index 9643a16b2a..e1d1c5f92d 100644
--- a/spec/ruby/core/process/getpgrp_spec.rb
+++ b/spec/ruby/core/process/getpgrp_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
# see setpgrp_spec.rb
diff --git a/spec/ruby/core/process/getpriority_spec.rb b/spec/ruby/core/process/getpriority_spec.rb
index 68307b9bd5..a35e5956a5 100644
--- a/spec/ruby/core/process/getpriority_spec.rb
+++ b/spec/ruby/core/process/getpriority_spec.rb
@@ -1,23 +1,23 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.getpriority" do
platform_is_not :windows do
it "coerces arguments to Integers" do
ret = Process.getpriority mock_int(Process::PRIO_PROCESS), mock_int(0)
- ret.should be_kind_of(Fixnum)
+ ret.should be_kind_of(Integer)
end
it "gets the scheduling priority for a specified process" do
- Process.getpriority(Process::PRIO_PROCESS, 0).should be_kind_of(Fixnum)
+ Process.getpriority(Process::PRIO_PROCESS, 0).should be_kind_of(Integer)
end
it "gets the scheduling priority for a specified process group" do
- Process.getpriority(Process::PRIO_PGRP, 0).should be_kind_of(Fixnum)
+ Process.getpriority(Process::PRIO_PGRP, 0).should be_kind_of(Integer)
end
it "gets the scheduling priority for a specified user" do
- Process.getpriority(Process::PRIO_USER, 0).should be_kind_of(Fixnum)
+ Process.getpriority(Process::PRIO_USER, 0).should be_kind_of(Integer)
end
end
end
diff --git a/spec/ruby/core/process/getrlimit_spec.rb b/spec/ruby/core/process/getrlimit_spec.rb
index 7924d43081..883b8fac48 100644
--- a/spec/ruby/core/process/getrlimit_spec.rb
+++ b/spec/ruby/core/process/getrlimit_spec.rb
@@ -1,8 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
platform_is :aix do
# In AIX, if getrlimit(2) is called multiple times with RLIMIT_DATA,
- # the first call and the subequent calls return slightly different
+ # the first call and the subsequent calls return slightly different
# values of rlim_cur, even if the process does nothing between
# the calls. This behavior causes some of the tests in this spec
# to fail, so call Process.getrlimit(:DATA) once and discard the result.
@@ -11,8 +11,8 @@ platform_is :aix do
Process.getrlimit(:DATA)
end
-platform_is_not :windows do
- describe "Process.getrlimit" do
+describe "Process.getrlimit" do
+ platform_is_not :windows do
it "returns a two-element Array of Integers" do
result = Process.getrlimit Process::RLIMIT_CORE
result.size.should == 2
@@ -36,33 +36,33 @@ platform_is_not :windows do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- lambda { Process.getrlimit(obj) }.should raise_error(TypeError)
+ -> { Process.getrlimit(obj) }.should raise_error(TypeError)
end
end
context "when passed a Symbol" do
- Process.constants.grep(/\ARLIMIT_/) do |fullname|
- short = $'
- it "coerces :#{short} into #{fullname}" do
+ it "coerces the short name into the full RLIMIT_ prefixed name" do
+ Process.constants.grep(/\ARLIMIT_/) do |fullname|
+ short = fullname[/\ARLIMIT_(.+)/, 1]
Process.getrlimit(short.to_sym).should == Process.getrlimit(Process.const_get(fullname))
end
end
it "raises ArgumentError when passed an unknown resource" do
- lambda { Process.getrlimit(:FOO) }.should raise_error(ArgumentError)
+ -> { Process.getrlimit(:FOO) }.should raise_error(ArgumentError)
end
end
context "when passed a String" do
- Process.constants.grep(/\ARLIMIT_/) do |fullname|
- short = $'
- it "coerces '#{short}' into #{fullname}" do
+ it "coerces the short name into the full RLIMIT_ prefixed name" do
+ Process.constants.grep(/\ARLIMIT_/) do |fullname|
+ short = fullname[/\ARLIMIT_(.+)/, 1]
Process.getrlimit(short).should == Process.getrlimit(Process.const_get(fullname))
end
end
it "raises ArgumentError when passed an unknown resource" do
- lambda { Process.getrlimit("FOO") }.should raise_error(ArgumentError)
+ -> { Process.getrlimit("FOO") }.should raise_error(ArgumentError)
end
end
@@ -88,4 +88,13 @@ platform_is_not :windows do
end
end
end
+
+ platform_is :windows do
+ it "is not implemented" do
+ Process.respond_to?(:getrlimit).should be_false
+ -> do
+ Process.getrlimit(nil)
+ end.should raise_error NotImplementedError
+ end
+ end
end
diff --git a/spec/ruby/core/process/gid/change_privilege_spec.rb b/spec/ruby/core/process/gid/change_privilege_spec.rb
index 9670e4970f..4ada277514 100644
--- a/spec/ruby/core/process/gid/change_privilege_spec.rb
+++ b/spec/ruby/core/process/gid/change_privilege_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.change_privilege" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/eid_spec.rb b/spec/ruby/core/process/gid/eid_spec.rb
index 6d6a672fea..3f2186bb6a 100644
--- a/spec/ruby/core/process/gid/eid_spec.rb
+++ b/spec/ruby/core/process/gid/eid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.eid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/grant_privilege_spec.rb b/spec/ruby/core/process/gid/grant_privilege_spec.rb
index 27373c7113..10da7f8a26 100644
--- a/spec/ruby/core/process/gid/grant_privilege_spec.rb
+++ b/spec/ruby/core/process/gid/grant_privilege_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.grant_privilege" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/re_exchange_spec.rb b/spec/ruby/core/process/gid/re_exchange_spec.rb
index 4f3a242680..9642c81c5b 100644
--- a/spec/ruby/core/process/gid/re_exchange_spec.rb
+++ b/spec/ruby/core/process/gid/re_exchange_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.re_exchange" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/re_exchangeable_spec.rb b/spec/ruby/core/process/gid/re_exchangeable_spec.rb
index 1fc5298f26..1c38f903d5 100644
--- a/spec/ruby/core/process/gid/re_exchangeable_spec.rb
+++ b/spec/ruby/core/process/gid/re_exchangeable_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.re_exchangeable?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/rid_spec.rb b/spec/ruby/core/process/gid/rid_spec.rb
index fb5c51e412..ad66c94e72 100644
--- a/spec/ruby/core/process/gid/rid_spec.rb
+++ b/spec/ruby/core/process/gid/rid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.rid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/sid_available_spec.rb b/spec/ruby/core/process/gid/sid_available_spec.rb
index 59b2c3ae1e..8d86b3e9d2 100644
--- a/spec/ruby/core/process/gid/sid_available_spec.rb
+++ b/spec/ruby/core/process/gid/sid_available_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.sid_available?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid/switch_spec.rb b/spec/ruby/core/process/gid/switch_spec.rb
index 7ae6dae9a7..b162f1e782 100644
--- a/spec/ruby/core/process/gid/switch_spec.rb
+++ b/spec/ruby/core/process/gid/switch_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::GID.switch" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/gid_spec.rb b/spec/ruby/core/process/gid_spec.rb
index c39c60a95f..ca935ed520 100644
--- a/spec/ruby/core/process/gid_spec.rb
+++ b/spec/ruby/core/process/gid_spec.rb
@@ -1,10 +1,10 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.gid" do
platform_is_not :windows do
it "returns the correct gid for the user executing this process" do
- current_gid_according_to_unix = `id -gr`.to_i
- Process.gid.should == current_gid_according_to_unix
+ current_gid_according_to_unix = `id -gr`.to_i
+ Process.gid.should == current_gid_according_to_unix
end
end
diff --git a/spec/ruby/core/process/groups_spec.rb b/spec/ruby/core/process/groups_spec.rb
index 2e12aa350c..33e0f9d7b3 100644
--- a/spec/ruby/core/process/groups_spec.rb
+++ b/spec/ruby/core/process/groups_spec.rb
@@ -1,20 +1,24 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.groups" do
platform_is_not :windows do
it "gets an Array of the gids of groups in the supplemental group access list" do
groups = `id -G`.scan(/\d+/).map { |i| i.to_i }
+ # Include the standard `id` command output. On macOS, GNU
+ # coreutils `id` is limited to NGROUPS_MAX groups, because of
+ # the backward compatibility of getgroups(2).
+ (groups |= `/usr/bin/id -G`.scan(/\d+/).map { |i| i.to_i }) rescue nil
gid = Process.gid
- expected = (groups.sort - [gid]).sort
- actual = (Process.groups - [gid]).sort
+ expected = (groups.sort - [gid]).uniq.sort
+ actual = (Process.groups - [gid]).uniq.sort
actual.should == expected
end
end
end
describe "Process.groups=" do
- platform_is_not :windows do
+ platform_is_not :windows, :android do
as_superuser do
it "sets the list of gids of groups in the supplemental group access list" do
groups = Process.groups
@@ -46,16 +50,15 @@ describe "Process.groups=" do
Process.groups.should == [ Process.gid ]
supplementary = groups - [ Process.gid ]
if supplementary.length > 0
- lambda { Process.groups = supplementary }.should raise_error(Errno::EPERM)
+ -> { Process.groups = supplementary }.should raise_error(Errno::EPERM)
end
end
end
platform_is_not :aix do
it "raises Errno::EPERM" do
- groups = Process.groups
- lambda {
- Process.groups = groups
+ -> {
+ Process.groups = [0]
}.should raise_error(Errno::EPERM)
end
end
diff --git a/spec/ruby/core/process/initgroups_spec.rb b/spec/ruby/core/process/initgroups_spec.rb
index 084c52652c..ffc7f282b6 100644
--- a/spec/ruby/core/process/initgroups_spec.rb
+++ b/spec/ruby/core/process/initgroups_spec.rb
@@ -1,19 +1,21 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.initgroups" do
- platform_is_not :windows do
- it "initializes the supplemental group access list" do
- name = `id -un`.strip
- groups = Process.groups
- gid = groups.max.to_i + 1
- augmented_groups = `id -G`.scan(/\d+/).map {|i| i.to_i} << gid
- if Process.uid == 0
- Process.groups = []
- Process.initgroups(name, gid).sort.should == augmented_groups.sort
- Process.groups.sort.should == augmented_groups.sort
- Process.groups = groups
- else
- lambda { Process.initgroups(name, gid) }.should raise_error(Errno::EPERM)
+ platform_is_not :windows, :android do
+ as_user do
+ it "initializes the supplemental group access list" do
+ name = `id -un`.strip
+ groups = Process.groups
+ gid = groups.max.to_i + 1
+ augmented_groups = `id -G`.scan(/\d+/).map {|i| i.to_i} << gid
+ if Process.uid == 0
+ Process.groups = []
+ Process.initgroups(name, gid).sort.should == augmented_groups.sort
+ Process.groups.sort.should == augmented_groups.sort
+ Process.groups = groups
+ else
+ -> { Process.initgroups(name, gid) }.should raise_error(Errno::EPERM)
+ end
end
end
end
diff --git a/spec/ruby/core/process/kill_spec.rb b/spec/ruby/core/process/kill_spec.rb
index 4316daf374..af9c9e6deb 100644
--- a/spec/ruby/core/process/kill_spec.rb
+++ b/spec/ruby/core/process/kill_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/common', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
describe "Process.kill" do
ProcessSpecs.use_system_ruby(self)
@@ -9,28 +9,32 @@ describe "Process.kill" do
end
it "raises an ArgumentError for unknown signals" do
- lambda { Process.kill("FOO", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("FOO", @pid) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if passed a lowercase signal name" do
- lambda { Process.kill("term", @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill("term", @pid) }.should raise_error(ArgumentError)
end
- it "raises an ArgumentError if signal is not a Fixnum or String" do
+ it "raises an ArgumentError if signal is not an Integer or String" do
signal = mock("process kill signal")
signal.should_not_receive(:to_int)
- lambda { Process.kill(signal, @pid) }.should raise_error(ArgumentError)
+ -> { Process.kill(signal, @pid) }.should raise_error(ArgumentError)
end
it "raises Errno::ESRCH if the process does not exist" do
pid = Process.spawn(*ruby_exe, "-e", "sleep 10")
Process.kill("SIGKILL", pid)
Process.wait(pid)
- lambda {
+ -> {
Process.kill("SIGKILL", pid)
}.should raise_error(Errno::ESRCH)
end
+
+ it "checks for existence and permissions to signal a process, but does not actually signal it, when using signal 0" do
+ Process.kill(0, @pid).should == 1
+ end
end
platform_is_not :windows do
@@ -65,7 +69,7 @@ platform_is_not :windows do
@sp.result.should == "signaled"
end
- it "acceps an Integer as a signal value" do
+ it "accepts an Integer as a signal value" do
Process.kill(15, @sp.pid)
@sp.result.should == "signaled"
end
diff --git a/spec/ruby/core/process/last_status_spec.rb b/spec/ruby/core/process/last_status_spec.rb
new file mode 100644
index 0000000000..2372f2aae3
--- /dev/null
+++ b/spec/ruby/core/process/last_status_spec.rb
@@ -0,0 +1,18 @@
+require_relative '../../spec_helper'
+
+describe 'Process#last_status' do
+ it 'returns the status of the last executed child process in the current thread' do
+ pid = Process.wait Process.spawn("exit 0")
+ Process.last_status.pid.should == pid
+ end
+
+ it 'returns nil if no child process has been ever executed in the current thread' do
+ Thread.new do
+ Process.last_status.should == nil
+ end.join
+ end
+
+ it 'raises an ArgumentError if any arguments are provided' do
+ -> { Process.last_status(1) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/process/maxgroups_spec.rb b/spec/ruby/core/process/maxgroups_spec.rb
index 8a40a1aba6..2549a7a971 100644
--- a/spec/ruby/core/process/maxgroups_spec.rb
+++ b/spec/ruby/core/process/maxgroups_spec.rb
@@ -1,9 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
platform_is_not :windows do
describe "Process.maxgroups" do
it "returns the maximum number of gids allowed in the supplemental group access list" do
- Process.maxgroups.should be_kind_of(Fixnum)
+ Process.maxgroups.should be_kind_of(Integer)
end
it "sets the maximum number of gids allowed in the supplemental group access list" do
diff --git a/spec/ruby/core/process/pid_spec.rb b/spec/ruby/core/process/pid_spec.rb
index 114b20f11f..2d008bc4b7 100644
--- a/spec/ruby/core/process/pid_spec.rb
+++ b/spec/ruby/core/process/pid_spec.rb
@@ -1,9 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.pid" do
it "returns the process id of this process" do
pid = Process.pid
- pid.should be_kind_of(Fixnum)
+ pid.should be_kind_of(Integer)
Process.pid.should == pid
end
end
diff --git a/spec/ruby/core/process/ppid_spec.rb b/spec/ruby/core/process/ppid_spec.rb
index ec6ce865ee..47c32a8591 100644
--- a/spec/ruby/core/process/ppid_spec.rb
+++ b/spec/ruby/core/process/ppid_spec.rb
@@ -1,23 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.ppid" do
- with_feature :fork do
+ platform_is_not :windows do
it "returns the process id of the parent of this process" do
-
- read, write = IO.pipe
-
- child_pid = Process.fork {
- read.close
- write << "#{Process.ppid}\n"
- write.close
- exit!
- }
-
- write.close
- pid = read.gets
- read.close
- Process.wait(child_pid)
- pid.to_i.should == Process.pid
+ ruby_exe("puts Process.ppid").should == "#{Process.pid}\n"
end
end
end
diff --git a/spec/ruby/core/process/set_proctitle_spec.rb b/spec/ruby/core/process/set_proctitle_spec.rb
index e004f8efc9..d022f2021c 100644
--- a/spec/ruby/core/process/set_proctitle_spec.rb
+++ b/spec/ruby/core/process/set_proctitle_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
# Note that there's no way to get the current process title defined as a spec
# somewhere. Process.setproctitle explicitly does not change `$0` so the only
diff --git a/spec/ruby/core/process/setpgid_spec.rb b/spec/ruby/core/process/setpgid_spec.rb
index bd1596d0eb..be724e9007 100644
--- a/spec/ruby/core/process/setpgid_spec.rb
+++ b/spec/ruby/core/process/setpgid_spec.rb
@@ -1,7 +1,8 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.setpgid" do
- with_feature :fork do
+ platform_is_not :windows do
+ # Must use fork as setpgid(2) gives EACCESS after execve()
it "sets the process group id of the specified process" do
rd, wr = IO.pipe
diff --git a/spec/ruby/core/process/setpgrp_spec.rb b/spec/ruby/core/process/setpgrp_spec.rb
index 8e72795f96..800668008d 100644
--- a/spec/ruby/core/process/setpgrp_spec.rb
+++ b/spec/ruby/core/process/setpgrp_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
# TODO: put these in the right files.
describe "Process.setpgrp and Process.getpgrp" do
diff --git a/spec/ruby/core/process/setpriority_spec.rb b/spec/ruby/core/process/setpriority_spec.rb
index 7b437a547a..4d60973429 100644
--- a/spec/ruby/core/process/setpriority_spec.rb
+++ b/spec/ruby/core/process/setpriority_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.setpriority" do
platform_is_not :windows do
@@ -29,13 +29,32 @@ describe "Process.setpriority" do
end
as_superuser do
- it "sets the scheduling priority for a specified user" do
- p = Process.getpriority(Process::PRIO_USER, 0)
- Process.setpriority(Process::PRIO_USER, 0, p + 1).should == 0
- Process.getpriority(Process::PRIO_USER, 0).should == (p + 1)
- Process.setpriority(Process::PRIO_USER, 0, p).should == 0
+ guard -> {
+ prio = Process.getpriority(Process::PRIO_USER, 0)
+ # The nice value is a value in the range -20 to 19.
+ # This test tries to change the nice value to +-1, so it cannot run if prio == -20 || prio == 19.
+ if -20 < prio && prio < 19
+ begin
+ # Check if we can lower the nice value or not.
+ #
+ # We are not always able to do it even as a root.
+ # Docker container is not always able to do it depending upon the configuration,
+ # which cannot know from the container itself.
+ Process.setpriority(Process::PRIO_USER, 0, prio - 1)
+ Process.setpriority(Process::PRIO_USER, 0, prio)
+ true
+ rescue Errno::EACCES
+ false
+ end
+ end
+ } do
+ it "sets the scheduling priority for a specified user" do
+ prio = Process.getpriority(Process::PRIO_USER, 0)
+ Process.setpriority(Process::PRIO_USER, 0, prio + 1).should == 0
+ Process.getpriority(Process::PRIO_USER, 0).should == (prio + 1)
+ Process.setpriority(Process::PRIO_USER, 0, prio).should == 0
+ end
end
end
end
-
end
diff --git a/spec/ruby/core/process/setrlimit_spec.rb b/spec/ruby/core/process/setrlimit_spec.rb
index 5d137ca6c1..ba8d1e04ca 100644
--- a/spec/ruby/core/process/setrlimit_spec.rb
+++ b/spec/ruby/core/process/setrlimit_spec.rb
@@ -1,7 +1,7 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
-platform_is_not :windows do
- describe "Process.setrlimit" do
+describe "Process.setrlimit" do
+ platform_is_not :windows do
context "when passed an Object" do
before do
@resource = Process::RLIMIT_CORE
@@ -16,7 +16,7 @@ platform_is_not :windows do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- lambda { Process.setrlimit(obj, @limit, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(obj, @limit, @max) }.should raise_error(TypeError)
end
it "calls #to_int to convert the soft limit to an Integer" do
@@ -27,7 +27,7 @@ platform_is_not :windows do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- lambda { Process.setrlimit(@resource, obj, @max) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, obj, @max) }.should raise_error(TypeError)
end
it "calls #to_int to convert the hard limit to an Integer" do
@@ -38,7 +38,7 @@ platform_is_not :windows do
obj = mock("process getrlimit integer")
obj.should_receive(:to_int).and_return(nil)
- lambda { Process.setrlimit(@resource, @limit, obj) }.should raise_error(TypeError)
+ -> { Process.setrlimit(@resource, @limit, obj) }.should raise_error(TypeError)
end
end
@@ -73,20 +73,18 @@ platform_is_not :windows do
Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces :MEMLOCK into RLIMIT_MEMLOCK" do
Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
end
end
- platform_is_not :solaris do
- it "coerces :NPROC into RLIMIT_NPROC" do
- Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces :NPROC into RLIMIT_NPROC" do
+ Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ end
- it "coerces :RSS into RLIMIT_RSS" do
- Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces :RSS into RLIMIT_RSS" do
+ Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
end
platform_is :netbsd, :freebsd do
@@ -100,7 +98,7 @@ platform_is_not :windows do
Process.setrlimit(:RTPRIO, *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
end
- if defined?(Process::RLIMIT_RTTIME)
+ guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces :RTTIME into RLIMIT_RTTIME" do
Process.setrlimit(:RTTIME, *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
end
@@ -120,7 +118,7 @@ platform_is_not :windows do
end
it "raises ArgumentError when passed an unknown resource" do
- lambda { Process.setrlimit(:FOO, 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit(:FOO, 1, 1) }.should raise_error(ArgumentError)
end
end
@@ -155,20 +153,18 @@ platform_is_not :windows do
Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces 'MEMLOCK' into RLIMIT_MEMLOCK" do
Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
end
end
- platform_is_not :solaris do
- it "coerces 'NPROC' into RLIMIT_NPROC" do
- Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces 'NPROC' into RLIMIT_NPROC" do
+ Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ end
- it "coerces 'RSS' into RLIMIT_RSS" do
- Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces 'RSS' into RLIMIT_RSS" do
+ Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
end
platform_is :netbsd, :freebsd do
@@ -182,7 +178,7 @@ platform_is_not :windows do
Process.setrlimit("RTPRIO", *Process.getrlimit(Process::RLIMIT_RTPRIO)).should be_nil
end
- if defined?(Process::RLIMIT_RTTIME)
+ guard -> { defined?(Process::RLIMIT_RTTIME) } do
it "coerces 'RTTIME' into RLIMIT_RTTIME" do
Process.setrlimit("RTTIME", *Process.getrlimit(Process::RLIMIT_RTTIME)).should be_nil
end
@@ -202,7 +198,7 @@ platform_is_not :windows do
end
it "raises ArgumentError when passed an unknown resource" do
- lambda { Process.setrlimit("FOO", 1, 1) }.should raise_error(ArgumentError)
+ -> { Process.setrlimit("FOO", 1, 1) }.should raise_error(ArgumentError)
end
end
@@ -229,4 +225,13 @@ platform_is_not :windows do
end
end
end
+
+ platform_is :windows do
+ it "is not implemented" do
+ Process.respond_to?(:setrlimit).should be_false
+ -> do
+ Process.setrlimit(nil, nil)
+ end.should raise_error NotImplementedError
+ end
+ end
end
diff --git a/spec/ruby/core/process/setsid_spec.rb b/spec/ruby/core/process/setsid_spec.rb
index 5f060ef218..c83f912066 100644
--- a/spec/ruby/core/process/setsid_spec.rb
+++ b/spec/ruby/core/process/setsid_spec.rb
@@ -1,37 +1,16 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.setsid" do
- with_feature :fork do
+ platform_is_not :windows do
it "establishes this process as a new session and process group leader" do
- read, write = IO.pipe
- read2, write2 = IO.pipe
- pid = Process.fork {
- begin
- read.close
- write2.close
- pgid = Process.setsid
- write << pgid
- write.close
- read2.gets
- rescue Exception => e
- write << e << e.backtrace
- end
- Process.exit!
- }
- write.close
- read2.close
- pgid_child = Integer(read.gets)
- read.close
- platform_is_not :aix, :openbsd do
- # AIX does not allow Process.getsid(pid)
- # if pid is in a different session.
- pgid = Process.getsid(pid)
- pgid_child.should == pgid
- end
- write2.close
- Process.wait pid
+ sid = Process.getsid
- pgid_child.should_not == Process.getsid
+ out = ruby_exe("p Process.getsid; p Process.setsid; p Process.getsid").lines
+ out[0].should == "#{sid}\n"
+ out[1].should == out[2]
+ out[2].should_not == "#{sid}\n"
+
+ sid.should == Process.getsid
end
end
end
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 9e34713757..283a7f033d 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/common', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
newline = "\n"
platform_is :windows do
@@ -7,27 +7,25 @@ platform_is :windows do
end
describe :process_spawn_does_not_close_std_streams, shared: true do
- platform_is_not :windows do
- it "does not close STDIN" do
- code = "STDOUT.puts STDIN.read(0).inspect"
- cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
- ruby_exe(cmd, args: "> #{@output}")
- File.binread(@output).should == %[""#{newline}]
- end
+ it "does not close STDIN" do
+ code = "puts STDIN.read"
+ cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
+ ruby_exe(cmd, args: "< #{fixture(__FILE__, "in.txt")} > #{@name}")
+ File.binread(@name).should == %[stdin#{newline}]
+ end
- it "does not close STDOUT" do
- code = "STDOUT.puts 'hello'"
- cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
- ruby_exe(cmd, args: "> #{@output}")
- File.binread(@output).should == "hello#{newline}"
- end
+ it "does not close STDOUT" do
+ code = "STDOUT.puts 'hello'"
+ cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
+ ruby_exe(cmd, args: "> #{@name}")
+ File.binread(@name).should == "hello#{newline}"
+ end
- it "does not close STDERR" do
- code = "STDERR.puts 'hello'"
- cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
- ruby_exe(cmd, args: "2> #{@output}")
- File.binread(@output).should == "hello#{newline}"
- end
+ it "does not close STDERR" do
+ code = "STDERR.puts 'hello'"
+ cmd = "Process.wait Process.spawn(#{ruby_cmd(code).inspect}, #{@options.inspect})"
+ ruby_exe(cmd, args: "2> #{@name}")
+ File.binread(@name).should =~ /hello#{newline}/
end
end
@@ -47,13 +45,13 @@ describe "Process.spawn" do
end
it "executes the given command" do
- lambda { Process.wait Process.spawn("echo spawn") }.should output_to_fd("spawn\n")
+ -> { Process.wait Process.spawn("echo spawn") }.should output_to_fd("spawn\n")
end
- it "returns the process ID of the new process as a Fixnum" do
+ it "returns the process ID of the new process as an Integer" do
pid = Process.spawn(*ruby_exe, "-e", "exit")
Process.wait pid
- pid.should be_an_instance_of(Fixnum)
+ pid.should be_an_instance_of(Integer)
end
it "returns immediately" do
@@ -69,43 +67,43 @@ describe "Process.spawn" do
describe "with a single argument" do
platform_is_not :windows do
it "subjects the specified command to shell expansion" do
- lambda { Process.wait Process.spawn("echo *") }.should_not output_to_fd("*\n")
+ -> { Process.wait Process.spawn("echo *") }.should_not output_to_fd("*\n")
end
it "creates an argument array with shell parsing semantics for whitespace" do
- lambda { Process.wait Process.spawn("echo a b c d") }.should output_to_fd("a b c d\n")
+ -> { Process.wait Process.spawn("echo a b c d") }.should output_to_fd("a b c d\n")
end
end
platform_is :windows do
# There is no shell expansion on Windows
it "does not subject the specified command to shell expansion on Windows" do
- lambda { Process.wait Process.spawn("echo *") }.should output_to_fd("*\n")
+ -> { Process.wait Process.spawn("echo *") }.should output_to_fd("*\n")
end
it "does not create an argument array with shell parsing semantics for whitespace on Windows" do
- lambda { Process.wait Process.spawn("echo a b c d") }.should output_to_fd("a b c d\n")
+ -> { Process.wait Process.spawn("echo a b c d") }.should output_to_fd("a b c d\n")
end
end
it "calls #to_str to convert the argument to a String" do
o = mock("to_str")
o.should_receive(:to_str).and_return("echo foo")
- lambda { Process.wait Process.spawn(o) }.should output_to_fd("foo\n")
+ -> { Process.wait Process.spawn(o) }.should output_to_fd("foo\n")
end
it "raises an ArgumentError if the command includes a null byte" do
- lambda { Process.spawn "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "\000" }.should raise_error(ArgumentError)
end
it "raises a TypeError if the argument does not respond to #to_str" do
- lambda { Process.spawn :echo }.should raise_error(TypeError)
+ -> { Process.spawn :echo }.should raise_error(TypeError)
end
end
describe "with multiple arguments" do
it "does not subject the arguments to shell expansion" do
- lambda { Process.wait Process.spawn("echo", "*") }.should output_to_fd("*\n")
+ -> { Process.wait Process.spawn("echo", "*") }.should output_to_fd("*\n")
end
it "preserves whitespace in passed arguments" do
@@ -114,36 +112,36 @@ describe "Process.spawn" do
# The echo command on Windows takes quotes literally
out = "\"a b c d\"\n"
end
- lambda { Process.wait Process.spawn("echo", "a b c d") }.should output_to_fd(out)
+ -> { Process.wait Process.spawn("echo", "a b c d") }.should output_to_fd(out)
end
it "calls #to_str to convert the arguments to Strings" do
o = mock("to_str")
o.should_receive(:to_str).and_return("foo")
- lambda { Process.wait Process.spawn("echo", o) }.should output_to_fd("foo\n")
+ -> { Process.wait Process.spawn("echo", o) }.should output_to_fd("foo\n")
end
it "raises an ArgumentError if an argument includes a null byte" do
- lambda { Process.spawn "echo", "\000" }.should raise_error(ArgumentError)
+ -> { Process.spawn "echo", "\000" }.should raise_error(ArgumentError)
end
it "raises a TypeError if an argument does not respond to #to_str" do
- lambda { Process.spawn "echo", :foo }.should raise_error(TypeError)
+ -> { Process.spawn "echo", :foo }.should raise_error(TypeError)
end
end
describe "with a command array" do
it "uses the first element as the command name and the second as the argv[0] value" do
platform_is_not :windows do
- lambda { Process.wait Process.spawn(["/bin/sh", "argv_zero"], "-c", "echo $0") }.should output_to_fd("argv_zero\n")
+ -> { Process.wait Process.spawn(["/bin/sh", "argv_zero"], "-c", "echo $0") }.should output_to_fd("argv_zero\n")
end
platform_is :windows do
- lambda { Process.wait Process.spawn(["cmd.exe", "/C"], "/C", "echo", "argv_zero") }.should output_to_fd("argv_zero\n")
+ -> { Process.wait Process.spawn(["cmd.exe", "/C"], "/C", "echo", "argv_zero") }.should output_to_fd("argv_zero\n")
end
end
it "does not subject the arguments to shell expansion" do
- lambda { Process.wait Process.spawn(["echo", "echo"], "*") }.should output_to_fd("*\n")
+ -> { Process.wait Process.spawn(["echo", "echo"], "*") }.should output_to_fd("*\n")
end
it "preserves whitespace in passed arguments" do
@@ -152,47 +150,47 @@ describe "Process.spawn" do
# The echo command on Windows takes quotes literally
out = "\"a b c d\"\n"
end
- lambda { Process.wait Process.spawn(["echo", "echo"], "a b c d") }.should output_to_fd(out)
+ -> { Process.wait Process.spawn(["echo", "echo"], "a b c d") }.should output_to_fd(out)
end
it "calls #to_ary to convert the argument to an Array" do
o = mock("to_ary")
platform_is_not :windows do
o.should_receive(:to_ary).and_return(["/bin/sh", "argv_zero"])
- lambda { Process.wait Process.spawn(o, "-c", "echo $0") }.should output_to_fd("argv_zero\n")
+ -> { Process.wait Process.spawn(o, "-c", "echo $0") }.should output_to_fd("argv_zero\n")
end
platform_is :windows do
o.should_receive(:to_ary).and_return(["cmd.exe", "/C"])
- lambda { Process.wait Process.spawn(o, "/C", "echo", "argv_zero") }.should output_to_fd("argv_zero\n")
+ -> { Process.wait Process.spawn(o, "/C", "echo", "argv_zero") }.should output_to_fd("argv_zero\n")
end
end
it "calls #to_str to convert the first element to a String" do
o = mock("to_str")
o.should_receive(:to_str).and_return("echo")
- lambda { Process.wait Process.spawn([o, "echo"], "foo") }.should output_to_fd("foo\n")
+ -> { Process.wait Process.spawn([o, "echo"], "foo") }.should output_to_fd("foo\n")
end
it "calls #to_str to convert the second element to a String" do
o = mock("to_str")
o.should_receive(:to_str).and_return("echo")
- lambda { Process.wait Process.spawn(["echo", o], "foo") }.should output_to_fd("foo\n")
+ -> { Process.wait Process.spawn(["echo", o], "foo") }.should output_to_fd("foo\n")
end
it "raises an ArgumentError if the Array does not have exactly two elements" do
- lambda { Process.spawn([]) }.should raise_error(ArgumentError)
- lambda { Process.spawn([:a]) }.should raise_error(ArgumentError)
- lambda { Process.spawn([:a, :b, :c]) }.should raise_error(ArgumentError)
+ -> { Process.spawn([]) }.should raise_error(ArgumentError)
+ -> { Process.spawn([:a]) }.should raise_error(ArgumentError)
+ -> { Process.spawn([:a, :b, :c]) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if the Strings in the Array include a null byte" do
- lambda { Process.spawn ["\000", "echo"] }.should raise_error(ArgumentError)
- lambda { Process.spawn ["echo", "\000"] }.should raise_error(ArgumentError)
+ -> { Process.spawn ["\000", "echo"] }.should raise_error(ArgumentError)
+ -> { Process.spawn ["echo", "\000"] }.should raise_error(ArgumentError)
end
it "raises a TypeError if an element in the Array does not respond to #to_str" do
- lambda { Process.spawn ["echo", :echo] }.should raise_error(TypeError)
- lambda { Process.spawn [:echo, "echo"] }.should raise_error(TypeError)
+ -> { Process.spawn ["echo", :echo] }.should raise_error(TypeError)
+ -> { Process.spawn [:echo, "echo"] }.should raise_error(TypeError)
end
end
@@ -209,13 +207,29 @@ describe "Process.spawn" do
it "unsets environment variables whose value is nil" do
ENV["FOO"] = "BAR"
- Process.wait Process.spawn({"FOO" => nil}, "echo #{@var}>#{@name}")
- expected = "\n"
- platform_is :windows do
- # Windows does not expand the variable if it is unset
- expected = "#{@var}\n"
+ -> do
+ Process.wait Process.spawn({"FOO" => nil}, ruby_cmd("p ENV['FOO']"))
+ end.should output_to_fd("nil\n")
+ end
+
+ platform_is_not :windows do
+ it "uses the passed env['PATH'] to search the executable" do
+ dir = tmp("spawn_path_dir")
+ mkdir_p dir
+ begin
+ exe = 'process-spawn-executable-in-path'
+ path = "#{dir}/#{exe}"
+ File.write(path, "#!/bin/sh\necho $1")
+ File.chmod(0755, path)
+
+ env = { "PATH" => "#{dir}#{File::PATH_SEPARATOR}#{ENV['PATH']}" }
+ Process.wait Process.spawn(env, exe, 'OK', out: @name)
+ $?.should.success?
+ File.read(@name).should == "OK\n"
+ ensure
+ rm_r dir
+ end
end
- File.read(@name).should == expected
end
it "calls #to_hash to convert the environment" do
@@ -240,19 +254,19 @@ describe "Process.spawn" do
end
it "raises an ArgumentError if an environment key includes an equals sign" do
- lambda do
+ -> do
Process.spawn({"FOO=" => "BAR"}, "echo #{@var}>#{@name}")
end.should raise_error(ArgumentError)
end
it "raises an ArgumentError if an environment key includes a null byte" do
- lambda do
+ -> do
Process.spawn({"\000" => "BAR"}, "echo #{@var}>#{@name}")
end.should raise_error(ArgumentError)
end
it "raises an ArgumentError if an environment value includes a null byte" do
- lambda do
+ -> do
Process.spawn({"FOO" => "\000"}, "echo #{@var}>#{@name}")
end.should raise_error(ArgumentError)
end
@@ -296,25 +310,25 @@ describe "Process.spawn" do
platform_is_not :windows do
it "joins the current process group by default" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"))
end.should output_to_fd(Process.getpgid(Process.pid).to_s)
end
it "joins the current process if pgroup: false" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: false)
end.should output_to_fd(Process.getpgid(Process.pid).to_s)
end
it "joins the current process if pgroup: nil" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: nil)
end.should output_to_fd(Process.getpgid(Process.pid).to_s)
end
it "joins a new process group if pgroup: true" do
- process = lambda do
+ process = -> do
Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: true)
end
@@ -323,7 +337,7 @@ describe "Process.spawn" do
end
it "joins a new process group if pgroup: 0" do
- process = lambda do
+ process = -> do
Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: 0)
end
@@ -333,23 +347,33 @@ describe "Process.spawn" do
it "joins the specified process group if pgroup: pgid" do
pgid = Process.getpgid(Process.pid)
- lambda do
- Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: pgid)
- end.should output_to_fd(pgid.to_s)
+ # The process group is not available on all platforms.
+ # See "man proc" - /proc/[pid]/stat - (5) pgrp
+ # In Travis aarch64 environment, the value is 0.
+ #
+ # $ cat /proc/[pid]/stat
+ # 19179 (ruby) S 19160 0 0 ...
+ unless pgid.zero?
+ -> do
+ Process.wait Process.spawn(ruby_cmd("print Process.getpgid(Process.pid)"), pgroup: pgid)
+ end.should output_to_fd(pgid.to_s)
+ else
+ skip "The process group is not available."
+ end
end
it "raises an ArgumentError if given a negative :pgroup option" do
- lambda { Process.spawn("echo", pgroup: -1) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: -1) }.should raise_error(ArgumentError)
end
it "raises a TypeError if given a symbol as :pgroup option" do
- lambda { Process.spawn("echo", pgroup: :true) }.should raise_error(TypeError)
+ -> { Process.spawn("echo", pgroup: :true) }.should raise_error(TypeError)
end
end
platform_is :windows do
it "raises an ArgumentError if given :pgroup option" do
- lambda { Process.spawn("echo", pgroup: false) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", pgroup: false) }.should raise_error(ArgumentError)
end
end
@@ -360,7 +384,7 @@ describe "Process.spawn" do
# :chdir
it "uses the current working directory as its working directory" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Dir.pwd"))
end.should output_to_fd(Dir.pwd)
end
@@ -376,7 +400,7 @@ describe "Process.spawn" do
end
it "changes to the directory passed for :chdir" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Dir.pwd"), chdir: @dir)
end.should output_to_fd(@dir)
end
@@ -385,23 +409,67 @@ describe "Process.spawn" do
dir = mock("spawn_to_path")
dir.should_receive(:to_path).and_return(@dir)
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print Dir.pwd"), chdir: dir)
end.should output_to_fd(@dir)
end
end
+ # chdir
+
+ platform_is :linux do
+ describe "inside Dir.chdir" do
+ def child_pids(pid)
+ `pgrep -P #{pid}`.lines.map { |child| Integer(child) }
+ end
+
+ it "does not create extra process without chdir" do
+ pid = Process.spawn("sleep 10")
+ begin
+ child_pids(pid).size.should == 0
+ ensure
+ Process.kill("TERM", pid)
+ Process.wait(pid)
+ end
+ end
+
+ it "kills extra chdir processes" do
+ pid = nil
+ Dir.chdir("/") do
+ pid = Process.spawn("sleep 10")
+ end
+
+ children = child_pids(pid)
+ children.size.should <= 1
+
+ Process.kill("TERM", pid)
+ Process.wait(pid)
+
+ if children.size > 0
+ # wait a bit for children to die
+ sleep(1)
+
+ children.each do |child|
+ -> do
+ Process.kill("TERM", child)
+ end.should raise_error(Errno::ESRCH)
+ end
+ end
+ end
+ end
+ end
+
# :umask
it "uses the current umask by default" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print File.umask"))
end.should output_to_fd(File.umask.to_s)
end
platform_is_not :windows do
it "sets the umask if given the :umask option" do
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print File.umask"), umask: 146)
end.should output_to_fd("146")
end
@@ -409,9 +477,19 @@ describe "Process.spawn" do
# redirection
- it "redirects STDOUT to the given file descriptior if out: Fixnum" do
+ it 'redirects to the wrapped IO using wrapped_io.to_io if out: wrapped_io' do
+ File.open(@name, 'w') do |file|
+ -> do
+ wrapped_io = mock('wrapped IO')
+ wrapped_io.should_receive(:to_io).and_return(file)
+ Process.wait Process.spawn('echo Hello World', out: wrapped_io)
+ end.should output_to_fd("Hello World\n", file)
+ end
+ end
+
+ it "redirects STDOUT to the given file descriptor if out: Integer" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn("echo glark", out: file.fileno)
end.should output_to_fd("glark\n", file)
end
@@ -419,7 +497,7 @@ describe "Process.spawn" do
it "redirects STDOUT to the given file if out: IO" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn("echo glark", out: file)
end.should output_to_fd("glark\n", file)
end
@@ -435,9 +513,9 @@ describe "Process.spawn" do
File.read(@name).should == "glark\n"
end
- it "redirects STDERR to the given file descriptior if err: Fixnum" do
+ it "redirects STDERR to the given file descriptor if err: Integer" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn("echo glark>&2", err: file.fileno)
end.should output_to_fd("glark\n", file)
end
@@ -445,7 +523,7 @@ describe "Process.spawn" do
it "redirects STDERR to the given file descriptor if err: IO" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn("echo glark>&2", err: file)
end.should output_to_fd("glark\n", file)
end
@@ -458,15 +536,15 @@ describe "Process.spawn" do
it "redirects STDERR to child STDOUT if :err => [:child, :out]" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn("echo glark>&2", :out => file, :err => [:child, :out])
end.should output_to_fd("glark\n", file)
end
end
- it "redirects both STDERR and STDOUT to the given file descriptior" do
+ it "redirects both STDERR and STDOUT to the given file descriptor" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print(:glark); STDOUT.flush; STDERR.print(:bang)"),
[:out, :err] => file.fileno)
end.should output_to_fd("glarkbang", file)
@@ -475,7 +553,7 @@ describe "Process.spawn" do
it "redirects both STDERR and STDOUT to the given IO" do
File.open(@name, 'w') do |file|
- lambda do
+ -> do
Process.wait Process.spawn(ruby_cmd("print(:glark); STDOUT.flush; STDERR.print(:bang)"),
[:out, :err] => file)
end.should output_to_fd("glarkbang", file)
@@ -488,107 +566,147 @@ describe "Process.spawn" do
File.read(@name).should == "glarkbang"
end
- context "when passed close_others: true" do
- before :each do
- @output = tmp("spawn_close_others_true")
- @options = { close_others: true }
- end
-
- after :each do
- rm_r @output
+ platform_is_not :windows, :android do
+ it "closes STDERR in the child if :err => :close" do
+ File.open(@name, 'w') do |file|
+ -> do
+ code = "begin; STDOUT.puts 'out'; STDERR.puts 'hello'; rescue => e; puts 'rescued'; end"
+ Process.wait Process.spawn(ruby_cmd(code), :out => file, :err => :close)
+ end.should output_to_fd("out\nrescued\n", file)
+ end
end
+ end
- it "closes file descriptors >= 3 in the child process" do
- IO.pipe do |r, w|
- begin
- pid = Process.spawn(ruby_cmd("while File.exist? '#{@name}'; sleep 0.1; end"), @options)
- w.close
- lambda { r.read_nonblock(1) }.should raise_error(EOFError)
- ensure
- rm_r @name
- Process.wait(pid) if pid
- end
+ platform_is_not :windows do
+ it "redirects non-default file descriptor to itself" do
+ File.open(@name, 'w') do |file|
+ -> do
+ Process.wait Process.spawn(
+ ruby_cmd("f = IO.new(#{file.fileno}, 'w'); f.print(:bang); f.flush"), file.fileno => file.fileno)
+ end.should output_to_fd("bang", file)
end
end
-
- it_should_behave_like :process_spawn_does_not_close_std_streams
end
- context "when passed close_others: false" do
- before :each do
- @output = tmp("spawn_close_others_false")
- @options = { close_others: false }
- end
+ it "redirects default file descriptor to itself" do
+ -> do
+ Process.wait Process.spawn(
+ ruby_cmd("f = IO.new(#{STDOUT.fileno}, 'w'); f.print(:bang); f.flush"), STDOUT.fileno => STDOUT.fileno)
+ end.should output_to_fd("bang", STDOUT)
+ end
- after :each do
- rm_r @output
- end
+ # :close_others
- it "closes file descriptors >= 3 in the child process because they are set close_on_exec by default" do
- IO.pipe do |r, w|
- begin
- pid = Process.spawn(ruby_cmd("while File.exist? '#{@name}'; sleep 0.1; end"), @options)
+ platform_is_not :windows do
+ context "defaults :close_others to" do
+ it "false" do
+ IO.pipe do |r, w|
+ w.close_on_exec = false
+ code = "io = IO.new(#{w.fileno}); io.puts('inherited'); io.close"
+ pid = Process.spawn(ruby_cmd(code))
w.close
- lambda { r.read_nonblock(1) }.should raise_error(EOFError)
- ensure
- rm_r @name
- Process.wait(pid) if pid
+ Process.wait(pid)
+ r.read.should == "inherited\n"
end
end
end
- platform_is_not :windows do
- it "does not close file descriptors >= 3 in the child process if fds are set close_on_exec=false" do
+ context "when passed close_others: true" do
+ before :each do
+ @options = { close_others: true }
+ end
+
+ it "closes file descriptors >= 3 in the child process even if fds are set close_on_exec=false" do
+ touch @name
IO.pipe do |r, w|
r.close_on_exec = false
w.close_on_exec = false
+
begin
pid = Process.spawn(ruby_cmd("while File.exist? '#{@name}'; sleep 0.1; end"), @options)
w.close
- lambda { r.read_nonblock(1) }.should raise_error(Errno::EAGAIN)
+ r.read(1).should == nil
ensure
rm_r @name
Process.wait(pid) if pid
end
end
end
+
+ it_should_behave_like :process_spawn_does_not_close_std_streams
end
- it_should_behave_like :process_spawn_does_not_close_std_streams
+ context "when passed close_others: false" do
+ before :each do
+ @options = { close_others: false }
+ end
+
+ it "closes file descriptors >= 3 in the child process because they are set close_on_exec by default" do
+ touch @name
+ IO.pipe do |r, w|
+ begin
+ pid = Process.spawn(ruby_cmd("while File.exist? '#{@name}'; sleep 0.1; end"), @options)
+ w.close
+ r.read(1).should == nil
+ ensure
+ rm_r @name
+ Process.wait(pid) if pid
+ end
+ end
+ end
+
+ it "does not close file descriptors >= 3 in the child process if fds are set close_on_exec=false" do
+ IO.pipe do |r, w|
+ r.close_on_exec = false
+ w.close_on_exec = false
+
+ code = "fd = IO.for_fd(#{w.fileno}); fd.autoclose = false; fd.write 'abc'; fd.close"
+ pid = Process.spawn(ruby_cmd(code), @options)
+ begin
+ w.close
+ r.read.should == 'abc'
+ ensure
+ Process.wait(pid)
+ end
+ end
+ end
+
+ it_should_behave_like :process_spawn_does_not_close_std_streams
+ end
end
# error handling
it "raises an ArgumentError if passed no command arguments" do
- lambda { Process.spawn }.should raise_error(ArgumentError)
+ -> { Process.spawn }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if passed env or options but no command arguments" do
- lambda { Process.spawn({}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError if passed env and options but no command arguments" do
- lambda { Process.spawn({}, {}) }.should raise_error(ArgumentError)
+ -> { Process.spawn({}, {}) }.should raise_error(ArgumentError)
end
it "raises an Errno::ENOENT for an empty string" do
- lambda { Process.spawn "" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "" }.should raise_error(Errno::ENOENT)
end
it "raises an Errno::ENOENT if the command does not exist" do
- lambda { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT)
+ -> { Process.spawn "nonesuch" }.should raise_error(Errno::ENOENT)
end
unless File.executable?(__FILE__) # Some FS (e.g. vboxfs) locate all files executable
platform_is_not :windows do
it "raises an Errno::EACCES when the file does not have execute permissions" do
- lambda { Process.spawn __FILE__ }.should raise_error(Errno::EACCES)
+ -> { Process.spawn __FILE__ }.should raise_error(Errno::EACCES)
end
end
platform_is :windows do
it "raises Errno::EACCES or Errno::ENOEXEC when the file is not an executable file" do
- lambda { Process.spawn __FILE__ }.should raise_error(SystemCallError) { |e|
+ -> { Process.spawn __FILE__ }.should raise_error(SystemCallError) { |e|
[Errno::EACCES, Errno::ENOEXEC].should include(e.class)
}
end
@@ -596,20 +714,20 @@ describe "Process.spawn" do
end
it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do
- lambda { Process.spawn File.dirname(__FILE__) }.should raise_error(SystemCallError) { |e|
+ -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e|
[Errno::EACCES, Errno::EISDIR].should include(e.class)
}
end
it "raises an ArgumentError when passed a string key in options" do
- lambda { Process.spawn("echo", "chdir" => Dir.pwd) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", "chdir" => Dir.pwd) }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when passed an unknown option key" do
- lambda { Process.spawn("echo", nonesuch: :foo) }.should raise_error(ArgumentError)
+ -> { Process.spawn("echo", nonesuch: :foo) }.should raise_error(ArgumentError)
end
- platform_is_not :windows do
+ platform_is_not :windows, :aix do
describe "with Integer option keys" do
before :each do
@name = tmp("spawn_fd_map.txt")
@@ -623,13 +741,15 @@ describe "Process.spawn" do
end
it "maps the key to a file descriptor in the child that inherits the file descriptor from the parent specified by the value" do
- child_fd = @io.fileno + 1
- args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s])
- pid = Process.spawn(*args, { child_fd => @io })
- Process.waitpid pid
- @io.rewind
-
- @io.read.should == "writing to fd: #{child_fd}"
+ File.open(__FILE__, "r") do |f|
+ child_fd = f.fileno
+ args = ruby_cmd(fixture(__FILE__, "map_fd.rb"), args: [child_fd.to_s])
+ pid = Process.spawn(*args, { child_fd => @io })
+ Process.waitpid pid
+ @io.rewind
+
+ @io.read.should == "writing to fd: #{child_fd}"
+ end
end
end
end
diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb
index 963d2c6c26..a805364629 100644
--- a/spec/ruby/core/process/status/bit_and_spec.rb
+++ b/spec/ruby/core/process/status/bit_and_spec.rb
@@ -1,5 +1,38 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
-describe "Process::Status#&" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."4.0" do
+
+ describe "Process::Status#&" do
+ it "returns a bitwise and of the integer status of an exited child" do
+ suppress_warning do
+ ruby_exe("exit(29)", exit_status: 29)
+ ($? & 0).should == 0
+ ($? & $?.to_i).should == $?.to_i
+
+ # Actual value is implementation specific
+ platform_is :linux do
+ # 29 == 0b11101
+ ($? & 0b1011100000000).should == 0b1010100000000
+ end
+ end
+ end
+
+ ruby_version_is "3.3"..."4.0" do
+ it "raises an ArgumentError if mask is negative" do
+ suppress_warning do
+ ruby_exe("exit(0)")
+ -> {
+ $? & -1
+ }.should raise_error(ArgumentError, 'negative mask value: -1')
+ end
+ end
+
+ it "shows a deprecation warning" do
+ ruby_exe("exit(0)")
+ -> {
+ $? & 0
+ }.should complain(/warning: Process::Status#& is deprecated and will be removed .*use other Process::Status predicates instead/)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/status/coredump_spec.rb b/spec/ruby/core/process/status/coredump_spec.rb
index 8988cff9e1..fbbaf926f7 100644
--- a/spec/ruby/core/process/status/coredump_spec.rb
+++ b/spec/ruby/core/process/status/coredump_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#coredump?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb
index 1eaaf82273..d8a2be26b8 100644
--- a/spec/ruby/core/process/status/equal_value_spec.rb
+++ b/spec/ruby/core/process/status/equal_value_spec.rb
@@ -1,5 +1,15 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#==" do
- it "needs to be reviewed for spec completeness"
+ it "returns true when compared to the integer status of an exited child" do
+ ruby_exe("exit(29)", exit_status: 29)
+ $?.to_i.should == $?
+ $?.should == $?.to_i
+ end
+
+ it "returns true when compared to the integer status of a terminated child" do
+ ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
+ $?.to_i.should == $?
+ $?.should == $?.to_i
+ end
end
diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb
index 79863360c5..a61292b146 100644
--- a/spec/ruby/core/process/status/exited_spec.rb
+++ b/spec/ruby/core/process/status/exited_spec.rb
@@ -1,9 +1,7 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#exited?" do
-
describe "for a child that exited normally" do
-
before :each do
ruby_exe("exit(0)")
end
@@ -15,9 +13,8 @@ describe "Process::Status#exited?" do
describe "for a terminated child" do
-
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)")
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
@@ -31,7 +28,5 @@ describe "Process::Status#exited?" do
$?.exited?.should be_true
end
end
-
end
-
end
diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb
index 57baf77724..5c86c2b3c8 100644
--- a/spec/ruby/core/process/status/exitstatus_spec.rb
+++ b/spec/ruby/core/process/status/exitstatus_spec.rb
@@ -1,13 +1,25 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#exitstatus" do
-
before :each do
- ruby_exe("exit(42)")
+ ruby_exe("exit(42)", exit_status: 42)
end
it "returns the process exit code" do
$?.exitstatus.should == 42
end
+ describe "for a child that raised SignalException" do
+ before :each do
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
+ end
+
+ platform_is_not :windows do
+ # The exitstatus is not set in these cases. See the termsig_spec
+ # for info on where the signal number (SIGTERM) is available.
+ it "returns nil" do
+ $?.exitstatus.should == nil
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/status/inspect_spec.rb b/spec/ruby/core/process/status/inspect_spec.rb
index f3e7d8c9ab..03f0479f2c 100644
--- a/spec/ruby/core/process/status/inspect_spec.rb
+++ b/spec/ruby/core/process/status/inspect_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#inspect" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/pid_spec.rb b/spec/ruby/core/process/status/pid_spec.rb
index 3389c242ff..9965fc3bdf 100644
--- a/spec/ruby/core/process/status/pid_spec.rb
+++ b/spec/ruby/core/process/status/pid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
platform_is_not :windows do
describe "Process::Status#pid" do
diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb
index 5786d4163c..355aaf4c95 100644
--- a/spec/ruby/core/process/status/right_shift_spec.rb
+++ b/spec/ruby/core/process/status/right_shift_spec.rb
@@ -1,5 +1,37 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
-describe "Process::Status#>>" do
- it "needs to be reviewed for spec completeness"
+ruby_version_is ""..."4.0" do
+
+ describe "Process::Status#>>" do
+ it "returns a right shift of the integer status of an exited child" do
+ suppress_warning do
+ ruby_exe("exit(29)", exit_status: 29)
+ ($? >> 0).should == $?.to_i
+ ($? >> 1).should == $?.to_i >> 1
+
+ # Actual value is implementation specific
+ platform_is :linux do
+ ($? >> 8).should == 29
+ end
+ end
+ end
+
+ ruby_version_is "3.3"..."4.0" do
+ it "raises an ArgumentError if shift value is negative" do
+ suppress_warning do
+ ruby_exe("exit(0)")
+ -> {
+ $? >> -1
+ }.should raise_error(ArgumentError, 'negative shift value: -1')
+ end
+ end
+
+ it "shows a deprecation warning" do
+ ruby_exe("exit(0)")
+ -> {
+ $? >> 0
+ }.should complain(/warning: Process::Status#>> is deprecated and will be removed .*use other Process::Status attributes instead/)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb
index 0f80a525c9..c0de7b8006 100644
--- a/spec/ruby/core/process/status/signaled_spec.rb
+++ b/spec/ruby/core/process/status/signaled_spec.rb
@@ -1,9 +1,7 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#signaled?" do
-
describe "for a cleanly exited child" do
-
before :each do
ruby_exe("exit(0)")
end
@@ -14,9 +12,8 @@ describe "Process::Status#signaled?" do
end
describe "for a terminated child" do
-
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)")
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
@@ -30,6 +27,5 @@ describe "Process::Status#signaled?" do
$?.signaled?.should be_false
end
end
-
end
end
diff --git a/spec/ruby/core/process/status/stopped_spec.rb b/spec/ruby/core/process/status/stopped_spec.rb
index e984cefaf7..bebd441d6f 100644
--- a/spec/ruby/core/process/status/stopped_spec.rb
+++ b/spec/ruby/core/process/status/stopped_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#stopped?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/stopsig_spec.rb b/spec/ruby/core/process/status/stopsig_spec.rb
index 95fc5b0e77..b2a7c5d9e2 100644
--- a/spec/ruby/core/process/status/stopsig_spec.rb
+++ b/spec/ruby/core/process/status/stopsig_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#stopsig" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb
index e589d3f819..3589cc611f 100644
--- a/spec/ruby/core/process/status/success_spec.rb
+++ b/spec/ruby/core/process/status/success_spec.rb
@@ -1,9 +1,7 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#success?" do
-
describe "for a child that exited normally" do
-
before :each do
ruby_exe("exit(0)")
end
@@ -14,9 +12,8 @@ describe "Process::Status#success?" do
end
describe "for a child that exited with a non zero status" do
-
before :each do
- ruby_exe("exit(42)")
+ ruby_exe("exit(42)", exit_status: 42)
end
it "returns false" do
@@ -25,27 +22,20 @@ describe "Process::Status#success?" do
end
describe "for a child that was terminated" do
-
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)")
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
-
it "returns nil" do
$?.success?.should be_nil
end
-
end
platform_is :windows do
-
it "always returns true" do
$?.success?.should be_true
end
-
end
-
end
-
end
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index d4f55e2521..9a22dbea71 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -1,39 +1,43 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#termsig" do
-
describe "for a child that exited normally" do
-
before :each do
ruby_exe("exit(0)")
end
- it "returns true" do
+ it "returns nil" do
$?.termsig.should be_nil
end
end
- describe "for a child that was sent a signal" do
-
+ describe "for a child that raised SignalException" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)")
+ ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM)
end
platform_is_not :windows do
+ it "returns the signal" do
+ $?.termsig.should == Signal.list["TERM"]
+ end
+ end
+ end
+ describe "for a child that was sent a signal" do
+ before :each do
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
+ end
+
+ platform_is_not :windows do
it "returns the signal" do
$?.termsig.should == Signal.list["KILL"]
end
-
end
platform_is :windows do
-
it "always returns nil" do
$?.termsig.should be_nil
end
-
end
-
end
end
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index c45724552e..39f8e2d84c 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -1,5 +1,13 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#to_i" do
- it "needs to be reviewed for spec completeness"
+ it "returns an integer when the child exits" do
+ ruby_exe('exit 48', exit_status: 48)
+ $?.to_i.should be_an_instance_of(Integer)
+ end
+
+ it "returns an integer when the child is signaled" do
+ ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
+ $?.to_i.should be_an_instance_of(Integer)
+ end
end
diff --git a/spec/ruby/core/process/status/to_int_spec.rb b/spec/ruby/core/process/status/to_int_spec.rb
index 8c988d7e19..fb596c1bfb 100644
--- a/spec/ruby/core/process/status/to_int_spec.rb
+++ b/spec/ruby/core/process/status/to_int_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#to_int" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/to_s_spec.rb b/spec/ruby/core/process/status/to_s_spec.rb
index ac87f4712a..5c0d4cd30c 100644
--- a/spec/ruby/core/process/status/to_s_spec.rb
+++ b/spec/ruby/core/process/status/to_s_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Status#to_s" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb
new file mode 100644
index 0000000000..57d56209a9
--- /dev/null
+++ b/spec/ruby/core/process/status/wait_spec.rb
@@ -0,0 +1,100 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/common'
+
+describe "Process::Status.wait" do
+ ProcessSpecs.use_system_ruby(self)
+
+ before :all do
+ begin
+ leaked = Process.waitall
+ # Ruby-space should not see PIDs used by rjit
+ raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
+ rescue NotImplementedError
+ end
+ end
+
+ it "returns a status with pid -1 if there are no child processes" do
+ Process::Status.wait.pid.should == -1
+ end
+
+ platform_is_not :windows do
+ it "returns a status with its child pid" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ status.should be_an_instance_of(Process::Status)
+ status.pid.should == pid
+ end
+
+ it "should not set $? to the Process::Status" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ $?.should_not equal(status)
+ end
+
+ it "should not change the value of $?" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process.wait
+ status = $?
+ Process::Status.wait
+ status.should equal($?)
+ end
+
+ it "waits for any child process if no pid is given" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait.pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ end
+
+ it "waits for a specific child if a pid is given" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ pid2 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(pid2).pid.should == pid2
+ Process::Status.wait(pid1).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ end
+
+ it "coerces the pid to an Integer" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(mock_int(pid1)).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ end
+
+ # This spec is probably system-dependent.
+ it "waits for a child whose process group ID is that of the calling process" do
+ pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true)
+ pid2 = Process.spawn(ruby_cmd('exit'))
+
+ Process::Status.wait(0).pid.should == pid2
+ Process::Status.wait.pid.should == pid1
+ end
+
+ # This spec is probably system-dependent.
+ it "doesn't block if no child is available when WNOHANG is used" do
+ read, write = IO.pipe
+ pid = Process.fork do
+ read.close
+ Signal.trap("TERM") { Process.exit! }
+ write << 1
+ write.close
+ sleep
+ end
+
+ Process::Status.wait(pid, Process::WNOHANG).should be_nil
+
+ # wait for the child to setup its TERM handler
+ write.close
+ read.read(1)
+ read.close
+
+ Process.kill("TERM", pid)
+ Process::Status.wait.pid.should == pid
+ end
+
+ it "always accepts flags=0" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(-1, 0).pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ end
+ end
+end
diff --git a/spec/ruby/core/process/sys/getegid_spec.rb b/spec/ruby/core/process/sys/getegid_spec.rb
index c21b890519..5b8588f147 100644
--- a/spec/ruby/core/process/sys/getegid_spec.rb
+++ b/spec/ruby/core/process/sys/getegid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.getegid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/geteuid_spec.rb b/spec/ruby/core/process/sys/geteuid_spec.rb
index 85c8d6e1bb..0ce7fc5459 100644
--- a/spec/ruby/core/process/sys/geteuid_spec.rb
+++ b/spec/ruby/core/process/sys/geteuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.geteuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/getgid_spec.rb b/spec/ruby/core/process/sys/getgid_spec.rb
index 945d3340f7..05c0fd4c0b 100644
--- a/spec/ruby/core/process/sys/getgid_spec.rb
+++ b/spec/ruby/core/process/sys/getgid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.getgid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/getuid_spec.rb b/spec/ruby/core/process/sys/getuid_spec.rb
index ead6e3044f..56bcef01cc 100644
--- a/spec/ruby/core/process/sys/getuid_spec.rb
+++ b/spec/ruby/core/process/sys/getuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.getuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/issetugid_spec.rb b/spec/ruby/core/process/sys/issetugid_spec.rb
index 2919c351a7..4fc7dc3bc6 100644
--- a/spec/ruby/core/process/sys/issetugid_spec.rb
+++ b/spec/ruby/core/process/sys/issetugid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.issetugid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setegid_spec.rb b/spec/ruby/core/process/sys/setegid_spec.rb
index edc0d59da4..8f20330b94 100644
--- a/spec/ruby/core/process/sys/setegid_spec.rb
+++ b/spec/ruby/core/process/sys/setegid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setegid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/seteuid_spec.rb b/spec/ruby/core/process/sys/seteuid_spec.rb
index 70cc78bec4..57d3a4800d 100644
--- a/spec/ruby/core/process/sys/seteuid_spec.rb
+++ b/spec/ruby/core/process/sys/seteuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.seteuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setgid_spec.rb b/spec/ruby/core/process/sys/setgid_spec.rb
index 25272b1eec..cc712e0102 100644
--- a/spec/ruby/core/process/sys/setgid_spec.rb
+++ b/spec/ruby/core/process/sys/setgid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setgid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setregid_spec.rb b/spec/ruby/core/process/sys/setregid_spec.rb
index 18a5834c80..57d491a707 100644
--- a/spec/ruby/core/process/sys/setregid_spec.rb
+++ b/spec/ruby/core/process/sys/setregid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setregid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setresgid_spec.rb b/spec/ruby/core/process/sys/setresgid_spec.rb
index 9f1736b460..9be06612c1 100644
--- a/spec/ruby/core/process/sys/setresgid_spec.rb
+++ b/spec/ruby/core/process/sys/setresgid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setresgid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setresuid_spec.rb b/spec/ruby/core/process/sys/setresuid_spec.rb
index 94c892bfdf..1092b349cb 100644
--- a/spec/ruby/core/process/sys/setresuid_spec.rb
+++ b/spec/ruby/core/process/sys/setresuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setresuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setreuid_spec.rb b/spec/ruby/core/process/sys/setreuid_spec.rb
index 72a8e61e7a..f3451c63c8 100644
--- a/spec/ruby/core/process/sys/setreuid_spec.rb
+++ b/spec/ruby/core/process/sys/setreuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setreuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setrgid_spec.rb b/spec/ruby/core/process/sys/setrgid_spec.rb
index ae820c98b8..27eea2ed86 100644
--- a/spec/ruby/core/process/sys/setrgid_spec.rb
+++ b/spec/ruby/core/process/sys/setrgid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setrgid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setruid_spec.rb b/spec/ruby/core/process/sys/setruid_spec.rb
index 4f40f6666a..9dbd84bf68 100644
--- a/spec/ruby/core/process/sys/setruid_spec.rb
+++ b/spec/ruby/core/process/sys/setruid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setruid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/sys/setuid_spec.rb b/spec/ruby/core/process/sys/setuid_spec.rb
index 13bf072ad1..e06c3588a5 100644
--- a/spec/ruby/core/process/sys/setuid_spec.rb
+++ b/spec/ruby/core/process/sys/setuid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::Sys.setuid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index 01a5595ef9..d3bff2cda9 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -1,27 +1,19 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.times" do
- it "returns a Struct::Tms" do
- Process.times.should be_kind_of(Struct::Tms)
+ it "returns a Process::Tms" do
+ Process.times.should be_kind_of(Process::Tms)
end
- it "returns current cpu times" do
- t = Process.times
+ # TODO: Intel C Compiler does not work this example
+ # http://rubyci.s3.amazonaws.com/icc-x64/ruby-master/log/20221013T030005Z.fail.html.gz
+ unless RbConfig::CONFIG['CC']&.include?("icx")
+ it "returns current cpu times" do
+ t = Process.times
+ user = t.utime
- # Do busy work for a wall-clock interval.
- start = Time.now
- 1 until (Time.now - start) > 0.5
-
- # Ensure times is larger. NOTE that there is no
- # guarantee of an upper bound since anything may be
- # happening at the OS level, so we ONLY check that at
- # least an interval has elapsed. Also, we are assuming
- # there is a correlation between wall clock time and
- # process time. In practice, there is an observed
- # discrepancy often 10% or greater. In other words,
- # this is a very fuzzy test.
- t2 = Process.times
- diff = (t2.utime + t2.stime) - (t.utime + t.stime)
- diff.should > 0
+ 1 until Process.times.utime > user
+ Process.times.utime.should > user
+ end
end
end
diff --git a/spec/ruby/core/process/tms/cstime_spec.rb b/spec/ruby/core/process/tms/cstime_spec.rb
new file mode 100644
index 0000000000..9c2d9e8632
--- /dev/null
+++ b/spec/ruby/core/process/tms/cstime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#cstime" do
+ it "returns cstime attribute" do
+ cstime = Object.new
+ Process::Tms.new(nil, nil, nil, cstime).cstime.should == cstime
+ end
+end
+
+describe "Process::Tms#cstime=" do
+ it "assigns a value to the cstime attribute" do
+ cstime = Object.new
+ tms = Process::Tms.new
+ tms.cstime = cstime
+ tms.cstime.should == cstime
+ end
+end
diff --git a/spec/ruby/core/process/tms/cutime_spec.rb b/spec/ruby/core/process/tms/cutime_spec.rb
new file mode 100644
index 0000000000..0ac3ff1964
--- /dev/null
+++ b/spec/ruby/core/process/tms/cutime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#cutime" do
+ it "returns cutime attribute" do
+ cutime = Object.new
+ Process::Tms.new(nil, nil, cutime, nil).cutime.should == cutime
+ end
+end
+
+describe "Process::Tms#cutime=" do
+ it "assigns a value to the cutime attribute" do
+ cutime = Object.new
+ tms = Process::Tms.new
+ tms.cutime = cutime
+ tms.cutime.should == cutime
+ end
+end
diff --git a/spec/ruby/core/process/tms/stime_spec.rb b/spec/ruby/core/process/tms/stime_spec.rb
new file mode 100644
index 0000000000..1e8371475f
--- /dev/null
+++ b/spec/ruby/core/process/tms/stime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#stime" do
+ it "returns stime attribute" do
+ stime = Object.new
+ Process::Tms.new(nil, stime, nil, nil).stime.should == stime
+ end
+end
+
+describe "Process::Tms#stime=" do
+ it "assigns a value to the stime attribute" do
+ stime = Object.new
+ tms = Process::Tms.new
+ tms.stime = stime
+ tms.stime.should == stime
+ end
+end
diff --git a/spec/ruby/core/process/tms/utime_spec.rb b/spec/ruby/core/process/tms/utime_spec.rb
new file mode 100644
index 0000000000..403a31e2e6
--- /dev/null
+++ b/spec/ruby/core/process/tms/utime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#utime" do
+ it "returns utime attribute" do
+ utime = Object.new
+ Process::Tms.new(utime, nil, nil, nil).utime.should == utime
+ end
+end
+
+describe "Process::Tms#utime=" do
+ it "assigns a value to the ctime attribute" do
+ utime = Object.new
+ tms = Process::Tms.new
+ tms.utime = utime
+ tms.utime.should == utime
+ end
+end
diff --git a/spec/ruby/core/process/uid/change_privilege_spec.rb b/spec/ruby/core/process/uid/change_privilege_spec.rb
index 91a38bfcdf..e4b552dd94 100644
--- a/spec/ruby/core/process/uid/change_privilege_spec.rb
+++ b/spec/ruby/core/process/uid/change_privilege_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.change_privilege" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/eid_spec.rb b/spec/ruby/core/process/uid/eid_spec.rb
index 39fcd13d93..f0bb9ce762 100644
--- a/spec/ruby/core/process/uid/eid_spec.rb
+++ b/spec/ruby/core/process/uid/eid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.eid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/grant_privilege_spec.rb b/spec/ruby/core/process/uid/grant_privilege_spec.rb
index c4d3443de8..2b8a5c9102 100644
--- a/spec/ruby/core/process/uid/grant_privilege_spec.rb
+++ b/spec/ruby/core/process/uid/grant_privilege_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.grant_privilege" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/re_exchange_spec.rb b/spec/ruby/core/process/uid/re_exchange_spec.rb
index 2f9b0d6a87..c0f10f33c4 100644
--- a/spec/ruby/core/process/uid/re_exchange_spec.rb
+++ b/spec/ruby/core/process/uid/re_exchange_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.re_exchange" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/re_exchangeable_spec.rb b/spec/ruby/core/process/uid/re_exchangeable_spec.rb
index 63f45fa662..8200d7ecb7 100644
--- a/spec/ruby/core/process/uid/re_exchangeable_spec.rb
+++ b/spec/ruby/core/process/uid/re_exchangeable_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.re_exchangeable?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/rid_spec.rb b/spec/ruby/core/process/uid/rid_spec.rb
index cdfe08e3be..e865cbfef6 100644
--- a/spec/ruby/core/process/uid/rid_spec.rb
+++ b/spec/ruby/core/process/uid/rid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.rid" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/sid_available_spec.rb b/spec/ruby/core/process/uid/sid_available_spec.rb
index 5d51366dd4..be7912eb68 100644
--- a/spec/ruby/core/process/uid/sid_available_spec.rb
+++ b/spec/ruby/core/process/uid/sid_available_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.sid_available?" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid/switch_spec.rb b/spec/ruby/core/process/uid/switch_spec.rb
index 6747ee4f43..4191b97db4 100644
--- a/spec/ruby/core/process/uid/switch_spec.rb
+++ b/spec/ruby/core/process/uid/switch_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../../spec_helper', __FILE__)
+require_relative '../../../spec_helper'
describe "Process::UID.switch" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/uid_spec.rb b/spec/ruby/core/process/uid_spec.rb
index 1b561f47e0..a068b1a2c1 100644
--- a/spec/ruby/core/process/uid_spec.rb
+++ b/spec/ruby/core/process/uid_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.uid" do
platform_is_not :windows do
@@ -18,67 +18,40 @@ describe "Process.uid" do
end
describe "Process.uid=" do
-
platform_is_not :windows do
it "raises TypeError if not passed an Integer" do
- lambda { Process.uid = Object.new }.should raise_error(TypeError)
+ -> { Process.uid = Object.new }.should raise_error(TypeError)
end
as_user do
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id" do
- lambda { (Process.uid = 0)}.should raise_error(Errno::EPERM)
+ -> { (Process.uid = 0)}.should raise_error(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non privileged user trying to set the superuser id from username" do
- lambda { Process.uid = "root" }.should raise_error(Errno::EPERM)
+ -> { Process.uid = "root" }.should raise_error(Errno::EPERM)
end
end
as_superuser do
describe "if run by a superuser" do
- with_feature :fork do
- it "sets the real user id for the current process" do
- read, write = IO.pipe
- pid = Process.fork do
- begin
- read.close
- Process.uid = 1
- write << Process.uid
- write.close
- rescue Exception => e
- write << e << e.backtrace
- end
- Process.exit!
- end
- write.close
- uid = read.gets
- uid.should == "1"
- Process.wait pid
- end
+ it "sets the real user id for the current process" do
+ code = <<-RUBY
+ Process.uid = 1
+ puts Process.uid
+ RUBY
+ ruby_exe(code).should == "1\n"
+ end
- it "sets the real user id if preceded by Process.euid=id" do
- read, write = IO.pipe
- pid = Process.fork do
- begin
- read.close
- Process.euid = 1
- Process.uid = 1
- write << Process.uid
- write.close
- rescue Exception => e
- write << e << e.backtrace
- end
- Process.exit!
- end
- write.close
- uid = read.gets
- uid.should == "1"
- Process.wait pid
- end
+ it "sets the real user id if preceded by Process.euid=id" do
+ code = <<-RUBY
+ Process.euid = 1
+ Process.uid = 1
+ puts Process.uid
+ RUBY
+ ruby_exe(code).should == "1\n"
end
end
end
end
-
- it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index d1f3a47b7f..8ba429dc96 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -1,14 +1,18 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.wait2" do
before :all do
# HACK: this kludge is temporarily necessary because some
# misbehaving spec somewhere else does not clear processes
+ # Note: background processes are unavoidable with RJIT,
+ # but we shouldn't reap them from Ruby-space
begin
Process.wait(-1, Process::WNOHANG)
$stderr.puts "Leaked process before wait2 specs! Waiting for it"
leaked = Process.waitall
- $stderr.puts "leaked before wait2 specs: #{leaked}"
+ $stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
+ # Ruby-space should not see PIDs used by rjit
+ leaked.should be_empty
rescue Errno::ECHILD # No child processes
rescue NotImplementedError
end
@@ -26,7 +30,16 @@ describe "Process.wait2" do
end
it "raises a StandardError if no child processes exist" do
- lambda { Process.wait2 }.should raise_error(Errno::ECHILD)
- lambda { Process.wait2 }.should raise_error(StandardError)
+ -> { Process.wait2 }.should raise_error(Errno::ECHILD)
+ -> { Process.wait2 }.should raise_error(StandardError)
+ end
+
+ it "returns nil if the child process is still running when given the WNOHANG flag" do
+ IO.popen(ruby_cmd('STDIN.getbyte'), "w") do |io|
+ pid, status = Process.wait2(io.pid, Process::WNOHANG)
+ pid.should be_nil
+ status.should be_nil
+ io.write('a')
+ end
end
end
diff --git a/spec/ruby/core/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb
index 8111621695..385acc9928 100644
--- a/spec/ruby/core/process/wait_spec.rb
+++ b/spec/ruby/core/process/wait_spec.rb
@@ -1,5 +1,5 @@
-require File.expand_path('../../../spec_helper', __FILE__)
-require File.expand_path('../fixtures/common', __FILE__)
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
describe "Process.wait" do
ProcessSpecs.use_system_ruby(self)
@@ -7,17 +7,18 @@ describe "Process.wait" do
before :all do
begin
leaked = Process.waitall
- puts "leaked before wait specs: #{leaked}" unless leaked.empty?
+ # Ruby-space should not see PIDs used by rjit
+ raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
rescue NotImplementedError
end
end
it "raises an Errno::ECHILD if there are no child processes" do
- lambda { Process.wait }.should raise_error(Errno::ECHILD)
+ -> { Process.wait }.should raise_error(Errno::ECHILD)
end
platform_is_not :windows do
- it "returns its childs pid" do
+ it "returns its child pid" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait.should == pid
end
@@ -32,7 +33,7 @@ describe "Process.wait" do
it "waits for any child process if no pid is given" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait.should == pid
- lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
end
it "waits for a specific child if a pid is given" do
@@ -40,14 +41,14 @@ describe "Process.wait" do
pid2 = Process.spawn(ruby_cmd('exit'))
Process.wait(pid2).should == pid2
Process.wait(pid1).should == pid1
- lambda { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- lambda { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
end
it "coerces the pid to an Integer" do
pid1 = Process.spawn(ruby_cmd('exit'))
Process.wait(mock_int(pid1)).should == pid1
- lambda { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
end
# This spec is probably system-dependent.
@@ -84,7 +85,7 @@ describe "Process.wait" do
it "always accepts flags=0" do
pid = Process.spawn(ruby_cmd('exit'))
Process.wait(-1, 0).should == pid
- lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/waitall_spec.rb b/spec/ruby/core/process/waitall_spec.rb
index e1fc38d2bc..6cf4e32bc9 100644
--- a/spec/ruby/core/process/waitall_spec.rb
+++ b/spec/ruby/core/process/waitall_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.waitall" do
before :all do
@@ -13,7 +13,7 @@ describe "Process.waitall" do
end
it "takes no arguments" do
- lambda { Process.waitall(0) }.should raise_error(ArgumentError)
+ -> { Process.waitall(0) }.should raise_error(ArgumentError)
end
platform_is_not :windows do
@@ -24,7 +24,7 @@ describe "Process.waitall" do
pids << Process.fork { Process.exit! 0 }
Process.waitall
pids.each { |pid|
- lambda { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
}
end
diff --git a/spec/ruby/core/process/waitpid2_spec.rb b/spec/ruby/core/process/waitpid2_spec.rb
index 303c59fda3..45513af667 100644
--- a/spec/ruby/core/process/waitpid2_spec.rb
+++ b/spec/ruby/core/process/waitpid2_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.waitpid2" do
it "needs to be reviewed for spec completeness"
diff --git a/spec/ruby/core/process/waitpid_spec.rb b/spec/ruby/core/process/waitpid_spec.rb
index c95e8d59dd..a02147b663 100644
--- a/spec/ruby/core/process/waitpid_spec.rb
+++ b/spec/ruby/core/process/waitpid_spec.rb
@@ -1,10 +1,9 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
describe "Process.waitpid" do
- it "needs to be reviewed for spec completeness"
-
it "returns nil when the process has not yet completed and WNOHANG is specified" do
- pid = spawn("sleep 5")
+ cmd = platform_is(:windows) ? "timeout" : "sleep"
+ pid = spawn("#{cmd} 5")
begin
Process.waitpid(pid, Process::WNOHANG).should == nil
Process.kill("KILL", pid)
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
new file mode 100644
index 0000000000..b562d52d22
--- /dev/null
+++ b/spec/ruby/core/process/warmup_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "Process.warmup" do
+ ruby_version_is "3.3" do
+ # The behavior is entirely implementation specific.
+ # Other implementations are free to just make it a noop
+ it "is implemented" do
+ Process.warmup.should == true
+ end
+ end
+end