right_popen 1.0.11 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,178 @@
1
+ #-- -*- mode: ruby; encoding: utf-8 -*-
2
+ # Copyright: Copyright (c) 2011 RightScale, Inc.
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # 'Software'), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
25
+
26
+ module RightScale::RightPopen
27
+ describe Utilities do
28
+ describe :run do
29
+ it 'should collect stdout and stderr' do
30
+ out, err = Utilities::run("echo foo; echo bar >&2")
31
+ out.should == "foo\n"
32
+ err.should == "bar\n"
33
+ end
34
+
35
+ it 'should handle utilities that expect input' do
36
+ out, err = Utilities::run("echo foo; read; echo bar >&2")
37
+ out.should == "foo\n"
38
+ err.should == "bar\n"
39
+ end
40
+
41
+ it 'should raise an error if the command fails' do
42
+ lambda { Utilities::run("false") }.should raise_exception(/Command "false" failed with exit status 1/)
43
+ end
44
+
45
+ it 'should raise an error if the command gets killed' do
46
+ lambda { Utilities::run("kill $$") }.should raise_exception(/Command ".*" failed due to SIGTERM/)
47
+ end
48
+
49
+ it 'should not invoke the shell when inappropriate' do
50
+ out, err = Utilities::run(["echo", "foo;", "echo", "bar", ">&2"])
51
+ out.should == "foo; echo bar >&2\n"
52
+ err.should be_empty
53
+ end
54
+ end
55
+
56
+ describe :run_collecting_output do
57
+ it 'should work' do
58
+ status, out, err = Utilities::run_collecting_output("echo foo; echo bar >&2")
59
+ status.should be_success
60
+ out.should == "foo\n"
61
+ err.should == "bar\n"
62
+ end
63
+
64
+ it 'should handle the command failing gracefully' do
65
+ status, out, err = Utilities::run_collecting_output("false")
66
+ status.should_not be_success
67
+ status.exitstatus.should == 1
68
+ out.should be_empty
69
+ err.should be_empty
70
+ end
71
+
72
+ it 'should handle the command self terminating gracefully' do
73
+ status, out, err = Utilities::run_collecting_output("kill $$")
74
+ status.should_not be_success
75
+ status.exitstatus.should be_nil
76
+ status.termsig.should == 15
77
+ out.should be_empty
78
+ err.should be_empty
79
+ end
80
+
81
+ it 'should not invoke the shell when inappropriate' do
82
+ status, out, err = Utilities::run_collecting_output(["echo", "foo;", "read", "foo", ";", "echo", "bar", ">&2"])
83
+ status.should be_success
84
+ out.should == "foo; read foo ; echo bar >&2\n"
85
+ err.should be_empty
86
+ end
87
+ end
88
+
89
+ describe :run_with_stdin_collecting_output do
90
+ it 'should work even if subprocess ignores stdin' do
91
+ status, out, err = Utilities::run_with_stdin_collecting_output("echo foo; echo bar >&2", "foo")
92
+ status.should be_success
93
+ out.should == "foo\n"
94
+ err.should == "bar\n"
95
+ end
96
+
97
+ it 'should handle utilities that expect input' do
98
+ status, out, err = Utilities::run_with_stdin_collecting_output("echo foo; read foo; echo $foo >&2", "blotz")
99
+ status.should be_success
100
+ out.should == "foo\n"
101
+ err.should == "blotz\n"
102
+ end
103
+
104
+ it 'should handle the command failing gracefully' do
105
+ status, out, err = Utilities::run_with_stdin_collecting_output("false", "blotz")
106
+ status.should_not be_success
107
+ status.exitstatus.should == 1
108
+ out.should be_empty
109
+ err.should be_empty
110
+ end
111
+
112
+ it 'should handle the command self terminating gracefully' do
113
+ status, out, err = Utilities::run_with_stdin_collecting_output("kill $$", "blotz")
114
+ status.should_not be_success
115
+ status.exitstatus.should be_nil
116
+ status.termsig.should == 15
117
+ out.should be_empty
118
+ err.should be_empty
119
+ end
120
+
121
+ it 'should not invoke the shell when inappropriate' do
122
+ status, out, err = Utilities::run_with_stdin_collecting_output(["echo", "foo;", "read", "foo", ";", "echo", "bar", ">&2"], "blotz")
123
+ status.should be_success
124
+ out.should == "foo; read foo ; echo bar >&2\n"
125
+ err.should be_empty
126
+ end
127
+ end
128
+
129
+ describe :run_with_blocks do
130
+ it 'should work even if subprocess ignores stdin' do
131
+ status = Utilities::run_with_blocks("echo foo; echo bar >&2",
132
+ lambda { "foo" },
133
+ lambda { |b| b.should == "foo\n" },
134
+ lambda { |b| b.should == "bar\n" })
135
+ status.should be_success
136
+ end
137
+
138
+ it 'should handle interaction' do
139
+ output_counter = 0
140
+ seen = {}
141
+ in_block = lambda {
142
+ if seen[output_counter]
143
+ ""
144
+ else
145
+ seen[output_counter] = true
146
+ "foo\n"
147
+ end
148
+ }
149
+ status = Utilities::run_with_blocks("for x in 1 2 3; do read var; echo $var; done; echo bar >&2",
150
+ in_block,
151
+ lambda { |b| output_counter += 1; b.should == "foo\n" },
152
+ lambda { |b| b.should == "bar\n" })
153
+ status.should be_success
154
+ output_counter.should == 3
155
+ end
156
+
157
+ it 'should handle the command failing gracefully' do
158
+ status = Utilities::run_with_blocks("echo foo; echo bar >&2; false",
159
+ lambda { "blotz" }, nil, nil)
160
+ status.should_not be_success
161
+ status.exitstatus.should == 1
162
+ end
163
+
164
+ it 'should handle the command self terminating gracefully' do
165
+ status = Utilities::run_with_blocks("echo foo; echo bar >&2; kill $$",
166
+ lambda { "blotz" }, nil, nil)
167
+ status.should_not be_success
168
+ status.exitstatus.should be_nil
169
+ status.termsig.should == 15
170
+ end
171
+
172
+ it 'should not invoke the shell when inappropriate' do
173
+ status, out, err = Utilities::run_with_blocks(["echo", "foo;", "read", "foo", ";", "echo", "bar", ">&2"], nil, lambda {|b| b.should == "foo; read foo ; echo bar >&2\n"}, nil)
174
+ status.should be_success
175
+ end
176
+ end
177
+ end
178
+ end
@@ -1,298 +1,230 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'runner'))
2
3
 
3
- describe 'RightScale::popen3' do
4
-
5
- module RightPopenSpec
6
- class Runner
7
- class RunnerStatus
8
- def initialize(command, block)
9
- @output_text = ""
10
- @error_text = ""
11
- @status = nil
12
- @did_timeout = false
13
- @callback = block
14
- @pid = nil
15
- EM.next_tick do
16
- @timeout = EM::Timer.new(2) do
17
- puts "\n** Failed to run #{command.inspect}: Timeout"
18
- @did_timeout = true
19
- @callback.call(self)
20
- end
21
- end
22
- end
23
-
24
- attr_accessor :output_text, :error_text, :status, :did_timeout, :pid
4
+ module RightScale
5
+ describe 'popen3' do
6
+ def is_windows?
7
+ return !!(RUBY_PLATFORM =~ /mswin/)
8
+ end
25
9
 
26
- def on_read_stdout(data)
27
- @output_text << data
28
- end
10
+ it 'should redirect output' do
11
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
12
+ runner = Runner.new
13
+ status = runner.run_right_popen(command)
14
+ status.status.exitstatus.should == 0
15
+ status.output_text.should == STANDARD_MESSAGE + "\n"
16
+ status.error_text.should == ERROR_MESSAGE + "\n"
17
+ status.pid.should > 0
18
+ end
29
19
 
30
- def on_read_stderr(data)
31
- @error_text << data
32
- end
20
+ it 'should return the right status' do
21
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb'))}\" #{EXIT_STATUS}"
22
+ runner = Runner.new
23
+ status = runner.run_right_popen(command)
24
+ status.status.exitstatus.should == EXIT_STATUS
25
+ status.output_text.should == ''
26
+ status.error_text.should == ''
27
+ status.pid.should > 0
28
+ end
33
29
 
34
- def on_pid(pid)
35
- raise "PID already set!" unless @pid.nil?
36
- @pid = pid
30
+ it 'should correctly handle many small processes' do
31
+ pending 'Set environment variable TEST_STRESS to enable' unless ENV['TEST_STRESS']
32
+ TO_RUN = 100
33
+ command = is_windows? ? "cmd.exe /c exit 0" : "exit 0"
34
+ runner = Runner.new
35
+ @completed = 0
36
+ @started = 0
37
+ run_cmd = Proc.new do
38
+ runner.do_right_popen(command) do |status|
39
+ @completed += 1
40
+ status.status.exitstatus.should == 0
41
+ status.output_text.should == ''
42
+ status.error_text.should == ''
43
+ status.pid.should > 0
37
44
  end
38
-
39
- def on_exit(status)
40
- @timeout.cancel if @timeout
41
- @status = status
42
- @callback.call(self)
45
+ @started += 1
46
+ if @started < TO_RUN
47
+ EM.next_tick { run_cmd.call }
43
48
  end
44
49
  end
50
+ EM.run do
51
+ EM.next_tick { run_cmd.call }
45
52
 
46
- def initialize
47
- @count = 0
48
- @done = false
49
- @last_exception = nil
50
- @last_iteration = 0
51
- end
52
-
53
- def do_right_popen(command, env=nil, input=nil, &callback)
54
- status = RunnerStatus.new(command, callback)
55
- RightScale.popen3(:command => command,
56
- :input => input,
57
- :target => status,
58
- :environment => env,
59
- :stdout_handler => :on_read_stdout,
60
- :stderr_handler => :on_read_stderr,
61
- :pid_handler => :on_pid,
62
- :exit_handler => :on_exit)
63
- status
64
- end
65
-
66
- def run_right_popen(command, env=nil, input=nil, count=1)
67
- begin
68
- @iterations = 0
69
- EM.run do
70
- EM.next_tick do
71
- do_right_popen(command, env, input) do |status|
72
- maybe_continue(status)
73
- end
74
- end
53
+ EM::PeriodicTimer.new(1) do
54
+ if @completed >= TO_RUN
55
+ EM.stop
75
56
  end
76
- @status
77
- rescue Exception => e
78
- puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
79
- raise e
80
- end
81
- end
82
-
83
- def maybe_continue(status)
84
- @iterations += 1
85
- if @iterations < @count
86
- do_right_popen(command, env, input) {|status| maybe_continue(status)}
87
- else
88
- @status = status
89
- EM.stop
90
57
  end
91
58
  end
92
59
  end
93
- end
94
60
 
95
- def is_windows?
96
- return !!(RUBY_PLATFORM =~ /mswin/)
97
- end
98
-
99
- it 'should redirect output' do
100
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
101
- runner = RightPopenSpec::Runner.new
102
- status = runner.run_right_popen(command)
103
- status.status.exitstatus.should == 0
104
- status.output_text.should == STANDARD_MESSAGE + "\n"
105
- status.error_text.should == ERROR_MESSAGE + "\n"
106
- status.pid.should > 0
107
- end
108
-
109
- it 'should return the right status' do
110
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb'))}\" #{EXIT_STATUS}"
111
- runner = RightPopenSpec::Runner.new
112
- status = runner.run_right_popen(command)
113
- status.status.exitstatus.should == EXIT_STATUS
114
- status.output_text.should == ''
115
- status.error_text.should == ''
116
- status.pid.should > 0
117
- end
118
-
119
- it 'should correctly handle many small processes' do
120
- pending 'Set environment variable TEST_STRESS to enable' unless ENV['TEST_STRESS']
121
- TO_RUN = 100
122
- command = is_windows? ? "cmd.exe /c exit 0" : "exit 0"
123
- runner = RightPopenSpec::Runner.new
124
- @completed = 0
125
- @started = 0
126
- run_cmd = Proc.new do
127
- runner.do_right_popen(command) do |status|
128
- @completed += 1
129
- status.status.exitstatus.should == 0
130
- status.output_text.should == ''
131
- status.error_text.should == ''
132
- status.pid.should > 0
133
- end
134
- @started += 1
135
- if @started < TO_RUN
136
- EM.next_tick { run_cmd.call }
137
- end
138
- end
139
- EM.run do
140
- EM.next_tick { run_cmd.call }
61
+ it 'should preserve the integrity of stdout when stderr is unavailable' do
62
+ count = LARGE_OUTPUT_COUNTER
63
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stdout_only.rb'))}\" #{count}"
64
+ runner = Runner.new
65
+ status = runner.run_right_popen(command)
66
+ status.status.exitstatus.should == 0
141
67
 
142
- EM::PeriodicTimer.new(1) do
143
- if @completed >= TO_RUN
144
- EM.stop
145
- end
68
+ results = ''
69
+ count.times do |i|
70
+ results << "stdout #{i}\n"
146
71
  end
72
+ status.output_text.should == results
73
+ status.error_text.should == ''
74
+ status.pid.should > 0
147
75
  end
148
- end
149
-
150
- it 'should preserve the integrity of stdout when stderr is unavailable' do
151
- count = LARGE_OUTPUT_COUNTER
152
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stdout_only.rb'))}\" #{count}"
153
- runner = RightPopenSpec::Runner.new
154
- status = runner.run_right_popen(command)
155
- status.status.exitstatus.should == 0
156
-
157
- results = ''
158
- count.times do |i|
159
- results << "stdout #{i}\n"
160
- end
161
- status.output_text.should == results
162
- status.error_text.should == ''
163
- status.pid.should > 0
164
- end
165
76
 
166
- it 'should preserve the integrity of stderr when stdout is unavailable' do
167
- count = LARGE_OUTPUT_COUNTER
168
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stderr_only.rb'))}\" #{count}"
169
- runner = RightPopenSpec::Runner.new
170
- status = runner.run_right_popen(command)
171
- status.status.exitstatus.should == 0
77
+ it 'should preserve the integrity of stderr when stdout is unavailable' do
78
+ count = LARGE_OUTPUT_COUNTER
79
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stderr_only.rb'))}\" #{count}"
80
+ runner = Runner.new
81
+ status = runner.run_right_popen(command)
82
+ status.status.exitstatus.should == 0
172
83
 
173
- results = ''
174
- count.times do |i|
175
- results << "stderr #{i}\n"
84
+ results = ''
85
+ count.times do |i|
86
+ results << "stderr #{i}\n"
87
+ end
88
+ status.error_text.should == results
89
+ status.output_text.should == ''
90
+ status.pid.should > 0
176
91
  end
177
- status.error_text.should == results
178
- status.output_text.should == ''
179
- status.pid.should > 0
180
- end
181
92
 
182
- it 'should preserve the integrity of stdout and stderr despite interleaving' do
183
- count = LARGE_OUTPUT_COUNTER
184
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{count}"
185
- runner = RightPopenSpec::Runner.new
186
- status = runner.run_right_popen(command)
187
- status.status.exitstatus.should == 99
93
+ it 'should preserve the integrity of stdout and stderr despite interleaving' do
94
+ count = LARGE_OUTPUT_COUNTER
95
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{count}"
96
+ runner = Runner.new
97
+ status = runner.run_right_popen(command)
98
+ status.status.exitstatus.should == 99
188
99
 
189
- results = ''
190
- count.times do |i|
191
- results << "stdout #{i}\n"
192
- end
193
- status.output_text.should == results
100
+ results = ''
101
+ count.times do |i|
102
+ results << "stdout #{i}\n"
103
+ end
104
+ status.output_text.should == results
194
105
 
195
- results = ''
196
- count.times do |i|
197
- (results << "stderr #{i}\n") if 0 == i % 10
106
+ results = ''
107
+ count.times do |i|
108
+ (results << "stderr #{i}\n") if 0 == i % 10
109
+ end
110
+ status.error_text.should == results
111
+ status.pid.should > 0
198
112
  end
199
- status.error_text.should == results
200
- status.pid.should > 0
201
- end
202
113
 
203
- it 'should setup environment variables' do
204
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
205
- runner = RightPopenSpec::Runner.new
206
- status = runner.run_right_popen(command)
207
- status.status.exitstatus.should == 0
208
- status.output_text.should_not include('_test_')
209
- status = runner.run_right_popen(command, :__test__ => '42')
210
- status.status.exitstatus.should == 0
211
- status.output_text.should match(/^__test__=42$/)
212
- status.pid.should > 0
213
- end
214
-
215
- it 'should restore environment variables' do
216
- begin
217
- ENV['__test__'] = '41'
218
- old_envs = {}
219
- ENV.each { |k, v| old_envs[k] = v }
114
+ it 'should setup environment variables' do
220
115
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
221
- runner = RightPopenSpec::Runner.new
116
+ runner = Runner.new
117
+ status = runner.run_right_popen(command)
118
+ status.status.exitstatus.should == 0
119
+ status.output_text.should_not include('_test_')
222
120
  status = runner.run_right_popen(command, :__test__ => '42')
223
121
  status.status.exitstatus.should == 0
224
122
  status.output_text.should match(/^__test__=42$/)
225
- ENV.each { |k, v| old_envs[k].should == v }
226
- old_envs.each { |k, v| ENV[k].should == v }
227
123
  status.pid.should > 0
228
- ensure
229
- ENV.delete('__test__')
230
124
  end
231
- end
232
125
 
233
- if is_windows?
234
- # FIX: this behavior is currently specific to Windows but should probably be
235
- # implemented for Linux.
236
- it 'should merge the PATH variable instead of overriding it' do
237
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
238
- runner = RightPopenSpec::Runner.new
239
- status = runner.run_right_popen(command, 'PATH' => "c:/bogus\\bin")
240
- status.status.exitstatus.should == 0
241
- status.output_text.should include('PATH=c:\\bogus\\bin;')
242
- status.pid.should > 0
126
+ it 'should restore environment variables' do
127
+ begin
128
+ ENV['__test__'] = '41'
129
+ old_envs = {}
130
+ ENV.each { |k, v| old_envs[k] = v }
131
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
132
+ runner = Runner.new
133
+ status = runner.run_right_popen(command, :__test__ => '42')
134
+ status.status.exitstatus.should == 0
135
+ status.output_text.should match(/^__test__=42$/)
136
+ ENV.each { |k, v| old_envs[k].should == v }
137
+ old_envs.each { |k, v| ENV[k].should == v }
138
+ status.pid.should > 0
139
+ ensure
140
+ ENV.delete('__test__')
141
+ end
142
+ end
143
+
144
+ if is_windows?
145
+ # FIX: this behavior is currently specific to Windows but should probably be
146
+ # implemented for Linux.
147
+ it 'should merge the PATH variable instead of overriding it' do
148
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
149
+ runner = Runner.new
150
+ status = runner.run_right_popen(command, 'PATH' => "c:/bogus\\bin")
151
+ status.status.exitstatus.should == 0
152
+ status.output_text.should include('c:\\bogus\\bin;')
153
+ status.pid.should > 0
154
+ end
155
+ else
156
+ it 'should allow running bash command lines starting with a built-in command' do
157
+ command = "for i in 1 2 3 4 5; do echo $i;done"
158
+ runner = Runner.new
159
+ status = runner.run_right_popen(command)
160
+ status.status.exitstatus.should == 0
161
+ status.output_text.should == "1\n2\n3\n4\n5\n"
162
+ status.pid.should > 0
163
+ end
164
+
165
+ it 'should support running background processes' do
166
+ command = "(sleep 20)&"
167
+ now = Time.now
168
+ runner = Runner.new
169
+ status = runner.run_right_popen(command)
170
+ finished = Time.now
171
+ (finished - now).should < 20
172
+ status.did_timeout.should be_false
173
+ status.status.exitstatus.should == 0
174
+ status.output_text.should == ""
175
+ status.pid.should > 0
176
+ end
243
177
  end
244
- else
245
- it 'should allow running bash command lines starting with a built-in command' do
246
- command = "for i in 1 2 3 4 5; do echo $i;done"
247
- runner = RightPopenSpec::Runner.new
178
+
179
+ it 'should support raw command arguments' do
180
+ command = is_windows? ? ["cmd.exe", "/c", "echo", "*"] : ["echo", "*"]
181
+ runner = Runner.new
248
182
  status = runner.run_right_popen(command)
249
183
  status.status.exitstatus.should == 0
250
- status.output_text.should == "1\n2\n3\n4\n5\n"
184
+ status.output_text.should == "*\n"
251
185
  status.pid.should > 0
252
186
  end
253
187
 
254
- it 'should support running background processes' do
255
- command = "(sleep 20)&"
256
- now = Time.now
257
- runner = RightPopenSpec::Runner.new
258
- status = runner.run_right_popen(command)
259
- finished = Time.now
260
- (finished - now).should < 20
261
- status.did_timeout.should be_false
188
+ it 'should run repeatedly without leaking resources' do
189
+ pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
190
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
191
+ runner = Runner.new
192
+ status = runner.run_right_popen(command, nil, nil, REPEAT_TEST_COUNTER)
262
193
  status.status.exitstatus.should == 0
263
- status.output_text.should == ""
194
+ status.output_text.should == STANDARD_MESSAGE + "\n"
195
+ status.error_text.should == ERROR_MESSAGE + "\n"
264
196
  status.pid.should > 0
265
197
  end
266
- end
267
198
 
268
- it 'should support raw command arguments' do
269
- command = is_windows? ? ["cmd.exe", "/c", "echo", "*"] : ["echo", "*"]
270
- runner = RightPopenSpec::Runner.new
271
- status = runner.run_right_popen(command)
272
- status.status.exitstatus.should == 0
273
- status.output_text.should == "*\n"
274
- status.pid.should > 0
275
- end
199
+ it 'should pass input to child process' do
200
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
201
+ runner = Runner.new
202
+ status = runner.run_right_popen(command, nil, "42\n")
203
+ status.status.exitstatus.should == 0
204
+ status.output_text.should == "43\n"
205
+ status.error_text.should be_empty
206
+ status.pid.should > 0
207
+ end
276
208
 
277
- it 'should run repeatedly without leaking resources' do
278
- pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
279
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
280
- runner = RightPopenSpec::Runner.new
281
- status = runner.run_right_popen(command, nil, nil, REPEAT_TEST_COUNTER)
282
- status.status.exitstatus.should == 0
283
- status.output_text.should == STANDARD_MESSAGE + "\n"
284
- status.error_text.should == ERROR_MESSAGE + "\n"
285
- status.pid.should > 0
286
- end
209
+ it 'should handle child processes that close stdout but keep running' do
210
+ pending 'not implemented for windows' if is_windows?
211
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'stdout.rb'))}\""
212
+ runner = Runner.new
213
+ status = runner.run_right_popen(command, nil, nil)
214
+ status.did_timeout.should be_true
215
+ status.output_text.should be_empty
216
+ status.error_text.should == "Closing stdout\n"
217
+ end
287
218
 
288
- it 'should pass input to child process' do
289
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
290
- runner = RightPopenSpec::Runner.new
291
- status = runner.run_right_popen(command, nil, "42\n")
292
- status.status.exitstatus.should == 0
293
- status.output_text.should == "43\n"
294
- status.error_text.should be_empty
295
- status.pid.should > 0
219
+ it 'should handle child processes that spawn long running background processes' do
220
+ pending 'not implemented for windows' if is_windows?
221
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'background.rb'))}\""
222
+ runner = Runner.new
223
+ status = runner.run_right_popen(command, nil, nil)
224
+ status.status.exitstatus.should == 0
225
+ status.did_timeout.should be_false
226
+ status.output_text.should be_empty
227
+ status.error_text.should be_empty
228
+ end
296
229
  end
297
-
298
230
  end