posix-spawn 0.3.10 → 0.3.11

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 88d9e42c2e091d60ef6bfaa4bee93671bfa7cdf1
4
- data.tar.gz: 0c34d4025ca8b876345fea00bb45a152b6909c10
3
+ metadata.gz: f593fc74a9f8637ea2c1dbfa897a805d6f87c0fe
4
+ data.tar.gz: 89a1a14ec837e06d68e85af34e56e956a976df30
5
5
  SHA512:
6
- metadata.gz: 6204dd64bc24a24a7ac155f8f7a0f018860b850b94efc68a68aa6b286a0de3a179deccb6f96ae7b1410045dface4de63aca14d235b1322bfac61399d825b65ff
7
- data.tar.gz: 988a0574b69a3accddfbb739c89b3da9949146cf7f316f41e2dc364c4ef5bb3cf7ae69858fe9c0318336e946cfc929a1c77178287e742db5a820044f4d680eee
6
+ metadata.gz: 33b05adfe9baf71faabd10e25e434c03e6aac674b4d9d05a6b79e1f8972a34aeacba3bb7b40598355fc9aa4c455049eeb0b3f6c00f7790d906f1ef01bb1799fe
7
+ data.tar.gz: 75ab91856b7ee41fad74bf2be66096d2667f8fbe888d5c7d67ab364c5033438ceb8e1f1a6b0e9f99cd120da4b65ca9486f2177b1bf4aa51ad7463229102e6dc1
data/Rakefile CHANGED
@@ -14,7 +14,13 @@ end
14
14
  # Ruby Extension
15
15
  # ==========================================================
16
16
 
17
- require 'rake/extensiontask'
17
+ begin
18
+ require 'rake/extensiontask'
19
+ rescue LoadError => boom
20
+ warn "ERROR: The rake-compiler gem dependency is missing."
21
+ warn "Please run `bundle install' and try again."
22
+ raise
23
+ end
18
24
  Rake::ExtensionTask.new('posix_spawn_ext', GEMSPEC) do |ext|
19
25
  ext.ext_dir = 'ext'
20
26
  end
@@ -77,6 +77,9 @@ module POSIX
77
77
  # :max => total Maximum number of bytes of output to allow the
78
78
  # process to generate before aborting with a
79
79
  # MaximumOutputExceeded exception.
80
+ # :pgroup_kill => bool Boolean specifying whether to kill the process
81
+ # group (true) or individual process (false, default).
82
+ # Setting this option true implies :pgroup => true.
80
83
  #
81
84
  # Returns a new Child instance whose underlying process has already
82
85
  # executed to completion. The out, err, and status attributes are
@@ -87,6 +90,10 @@ module POSIX
87
90
  @input = @options.delete(:input)
88
91
  @timeout = @options.delete(:timeout)
89
92
  @max = @options.delete(:max)
93
+ if @options.delete(:pgroup_kill)
94
+ @pgroup_kill = true
95
+ @options[:pgroup] = true
96
+ end
90
97
  @options.delete(:chdir) if @options[:chdir].nil?
91
98
  exec! if !@options.delete(:noexec)
92
99
  end
@@ -128,6 +135,11 @@ module POSIX
128
135
  # Total command execution time (wall-clock time)
129
136
  attr_reader :runtime
130
137
 
138
+ # The pid of the spawned child process. This is unlikely to be a valid
139
+ # current pid since Child#exec! doesn't return until the process finishes
140
+ # and is reaped.
141
+ attr_reader :pid
142
+
131
143
  # Determine if the process did exit with a zero exit status.
132
144
  def success?
133
145
  @status && @status.success?
@@ -139,6 +151,7 @@ module POSIX
139
151
  def exec!
140
152
  # spawn the process and hook up the pipes
141
153
  pid, stdin, stdout, stderr = popen4(@env, *(@argv + [@options]))
154
+ @pid = pid
142
155
 
143
156
  # async read from all streams into buffers
144
157
  read_and_write(@input, stdin, stdout, stderr, @timeout, @max)
@@ -148,8 +161,12 @@ module POSIX
148
161
  rescue Object => boom
149
162
  [stdin, stdout, stderr].each { |fd| fd.close rescue nil }
150
163
  if @status.nil?
151
- ::Process.kill('TERM', pid) rescue nil
152
- @status = waitpid(pid) rescue nil
164
+ if !@pgroup_kill
165
+ ::Process.kill('TERM', pid) rescue nil
166
+ else
167
+ ::Process.kill('-TERM', pid) rescue nil
168
+ end
169
+ @status = waitpid(pid) rescue nil
153
170
  end
154
171
  raise
155
172
  ensure
@@ -1,5 +1,5 @@
1
1
  module POSIX
2
2
  module Spawn
3
- VERSION = '0.3.10'
3
+ VERSION = '0.3.11'
4
4
  end
5
5
  end
@@ -1,10 +1,42 @@
1
1
  # coding: UTF-8
2
-
3
2
  require 'test_helper'
4
3
 
5
4
  class ChildTest < Minitest::Test
6
5
  include POSIX::Spawn
7
6
 
7
+ # Become a new process group.
8
+ def setup
9
+ Process.setpgrp
10
+ end
11
+
12
+ # Kill any orphaned processes in our process group before continuing but
13
+ # ignore the TERM signal we receive.
14
+ def teardown
15
+ trap("TERM") { trap("TERM", "DEFAULT") }
16
+ begin
17
+ Process.kill("-TERM", Process.pid)
18
+ Process.wait
19
+ rescue Errno::ECHILD
20
+ end
21
+ end
22
+
23
+ # verify the process is no longer running and has been reaped.
24
+ def assert_process_reaped(pid)
25
+ Process.kill(0, pid)
26
+ assert false, "Process #{pid} still running"
27
+ rescue Errno::ESRCH
28
+ end
29
+
30
+ # verifies that all processes in the given process group are no longer running
31
+ # and have been reaped. The current ruby test process is excluded.
32
+ # XXX It's weird to use the SUT here but the :pgroup option is useful. Could
33
+ # be a IO.popen under Ruby >= 1.9 since it also supports :pgroup.
34
+ def assert_process_group_reaped(pgid)
35
+ command = "ps axo pgid,pid,args | grep '^#{pgid} ' | grep -v '^#{pgid} #$$'"
36
+ procs = POSIX::Spawn::Child.new(command, :pgroup => true).out
37
+ assert procs.empty?, "Processes in group #{pgid} still running:\n#{procs}"
38
+ end
39
+
8
40
  def test_sanity
9
41
  assert_same POSIX::Spawn::Child, Child
10
42
  end
@@ -56,21 +88,45 @@ class ChildTest < Minitest::Test
56
88
  end
57
89
 
58
90
  def test_max
59
- assert_raises MaximumOutputExceeded do
60
- Child.new('yes', :max => 100_000)
61
- end
91
+ child = Child.build('yes', :max => 100_000)
92
+ assert_raises(MaximumOutputExceeded) { child.exec! }
93
+ assert_process_reaped child.pid
94
+ assert_process_group_reaped Process.pid
95
+ end
96
+
97
+ def test_max_pgroup_kill
98
+ child = Child.build('yes', :max => 100_000, :pgroup_kill => true)
99
+ assert_raises(MaximumOutputExceeded) { child.exec! }
100
+ assert_process_reaped child.pid
101
+ assert_process_group_reaped child.pid
62
102
  end
63
103
 
64
104
  def test_max_with_child_hierarchy
65
- assert_raises MaximumOutputExceeded do
66
- Child.new('/bin/sh', '-c', 'yes', :max => 100_000)
67
- end
105
+ child = Child.build('/bin/sh', '-c', 'true && yes', :max => 100_000)
106
+ assert_raises(MaximumOutputExceeded) { child.exec! }
107
+ assert_process_reaped child.pid
108
+ assert_process_group_reaped Process.pid
109
+ end
110
+
111
+ def test_max_with_child_hierarchy_pgroup_kill
112
+ child = Child.build('/bin/sh', '-c', 'true && yes', :max => 100_000, :pgroup_kill => true)
113
+ assert_raises(MaximumOutputExceeded) { child.exec! }
114
+ assert_process_reaped child.pid
115
+ assert_process_group_reaped child.pid
68
116
  end
69
117
 
70
118
  def test_max_with_stubborn_child
71
- assert_raises MaximumOutputExceeded do
72
- Child.new("trap '' TERM; yes", :max => 100_000)
73
- end
119
+ child = Child.build("trap '' TERM; yes", :max => 100_000)
120
+ assert_raises(MaximumOutputExceeded) { child.exec! }
121
+ assert_process_reaped child.pid
122
+ assert_process_group_reaped Process.pid
123
+ end
124
+
125
+ def test_max_with_stubborn_child_pgroup_kill
126
+ child = Child.build("trap '' TERM; yes", :max => 100_000, :pgroup_kill => true)
127
+ assert_raises(MaximumOutputExceeded) { child.exec! }
128
+ assert_process_reaped child.pid
129
+ assert_process_group_reaped child.pid
74
130
  end
75
131
 
76
132
  def test_max_with_partial_output
@@ -80,6 +136,8 @@ class ChildTest < Minitest::Test
80
136
  p.exec!
81
137
  end
82
138
  assert_output_exceeds_repeated_string("y\n", 100_000, p.out)
139
+ assert_process_reaped p.pid
140
+ assert_process_group_reaped Process.pid
83
141
  end
84
142
 
85
143
  def test_max_with_partial_output_long_lines
@@ -88,28 +146,47 @@ class ChildTest < Minitest::Test
88
146
  p.exec!
89
147
  end
90
148
  assert_output_exceeds_repeated_string("nice to meet you\n", 10_000, p.out)
149
+ assert_process_reaped p.pid
150
+ assert_process_group_reaped Process.pid
91
151
  end
92
152
 
93
153
  def test_timeout
94
154
  start = Time.now
95
- assert_raises TimeoutExceeded do
96
- Child.new('sleep', '1', :timeout => 0.05)
97
- end
155
+ child = Child.build('sleep', '1', :timeout => 0.05)
156
+ assert_raises(TimeoutExceeded) { child.exec! }
157
+ assert_process_reaped child.pid
158
+ assert_process_group_reaped Process.pid
159
+ assert (Time.now-start) <= 0.2
160
+ end
161
+
162
+ def test_timeout_pgroup_kill
163
+ start = Time.now
164
+ child = Child.build('sleep', '1', :timeout => 0.05, :pgroup_kill => true)
165
+ assert_raises(TimeoutExceeded) { child.exec! }
166
+ assert_process_reaped child.pid
167
+ assert_process_group_reaped child.pid
98
168
  assert (Time.now-start) <= 0.2
99
169
  end
100
170
 
101
171
  def test_timeout_with_child_hierarchy
102
- assert_raises TimeoutExceeded do
103
- Child.new('/bin/sh', '-c', 'sleep 1', :timeout => 0.05)
104
- end
172
+ child = Child.build('/bin/sh', '-c', 'true && sleep 1', :timeout => 0.05)
173
+ assert_raises(TimeoutExceeded) { child.exec! }
174
+ assert_process_reaped child.pid
175
+ end
176
+
177
+ def test_timeout_with_child_hierarchy_pgroup_kill
178
+ child = Child.build('/bin/sh', '-c', 'true && sleep 1', :timeout => 0.05, :pgroup_kill => true)
179
+ assert_raises(TimeoutExceeded) { child.exec! }
180
+ assert_process_reaped child.pid
181
+ assert_process_group_reaped child.pid
105
182
  end
106
183
 
107
184
  def test_timeout_with_partial_output
108
185
  start = Time.now
109
- p = Child.build('echo Hello; sleep 1', :timeout => 0.05)
110
- assert_raises TimeoutExceeded do
111
- p.exec!
112
- end
186
+ p = Child.build('echo Hello; sleep 1', :timeout => 0.05, :pgroup_kill => true)
187
+ assert_raises(TimeoutExceeded) { p.exec! }
188
+ assert_process_reaped p.pid
189
+ assert_process_group_reaped Process.pid
113
190
  assert (Time.now-start) <= 0.2
114
191
  assert_equal "Hello\n", p.out
115
192
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: posix-spawn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.3.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Tomayko
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-02-17 00:00:00.000000000 Z
12
+ date: 2015-04-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler