right_popen 1.1.3 → 3.0.1
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.
- checksums.yaml +7 -0
- data/README.rdoc +2 -0
- data/lib/right_popen.rb +35 -31
- data/lib/right_popen/linux/popen3_async.rb +26 -10
- data/lib/right_popen/linux/process.rb +21 -25
- data/lib/right_popen/{linux/popen3_sync.rb → popen3_sync.rb} +2 -1
- data/lib/right_popen/process_base.rb +20 -16
- data/lib/right_popen/process_status.rb +3 -0
- data/lib/right_popen/safe_output_buffer.rb +3 -0
- data/lib/right_popen/target_proxy.rb +12 -8
- data/right_popen.gemspec +57 -31
- metadata +39 -128
- data/Rakefile +0 -127
- data/lib/right_popen/linux/accumulator.rb +0 -127
- data/lib/right_popen/linux/utilities.rb +0 -94
- data/lib/right_popen/version.rb +0 -28
- data/spec/background.rb +0 -28
- data/spec/increment.rb +0 -2
- data/spec/print_env.rb +0 -2
- data/spec/produce_mixed_output.rb +0 -12
- data/spec/produce_output.rb +0 -2
- data/spec/produce_status.rb +0 -1
- data/spec/produce_stderr_only.rb +0 -5
- data/spec/produce_stdout_only.rb +0 -5
- data/spec/right_popen/linux/accumulator_spec.rb +0 -267
- data/spec/right_popen/linux/utilities_spec.rb +0 -178
- data/spec/right_popen/safe_output_buffer_spec.rb +0 -26
- data/spec/right_popen_spec.rb +0 -331
- data/spec/runner.rb +0 -217
- data/spec/sleeper.rb +0 -35
- data/spec/spec_helper.rb +0 -26
- data/spec/stdout.rb +0 -28
- data/spec/writer.rb +0 -34
@@ -1,178 +0,0 @@
|
|
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 unused_input; 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,26 +0,0 @@
|
|
1
|
-
require ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', 'spec_helper'))
|
2
|
-
require ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', 'lib', 'right_popen', 'safe_output_buffer'))
|
3
|
-
|
4
|
-
describe RightScale::RightPopen::SafeOutputBuffer do
|
5
|
-
|
6
|
-
context 'given a default buffer' do
|
7
|
-
subject { described_class.new }
|
8
|
-
|
9
|
-
it 'should limit line count and length' do
|
10
|
-
(described_class::DEFAULT_MAX_LINE_COUNT * 2).times do |line_index|
|
11
|
-
data = 'x' * rand(described_class::DEFAULT_MAX_LINE_LENGTH * 3)
|
12
|
-
subject.safe_buffer_data(data).should be_true
|
13
|
-
end
|
14
|
-
subject.buffer.size.should == described_class::DEFAULT_MAX_LINE_COUNT
|
15
|
-
subject.buffer.first.should == described_class::ELLIPSIS
|
16
|
-
subject.buffer.last.should_not == described_class::ELLIPSIS
|
17
|
-
subject.buffer.each do |line|
|
18
|
-
(line.length <= described_class::DEFAULT_MAX_LINE_LENGTH).should be_true
|
19
|
-
end
|
20
|
-
text = subject.display_text
|
21
|
-
text.should_not be_empty
|
22
|
-
text.lines.count.should == subject.buffer.size
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
data/spec/right_popen_spec.rb
DELETED
@@ -1,331 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
|
2
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'runner'))
|
3
|
-
|
4
|
-
require 'stringio'
|
5
|
-
require 'tmpdir'
|
6
|
-
|
7
|
-
describe 'RightScale::RightPopen' do
|
8
|
-
def is_windows?
|
9
|
-
return !!(RUBY_PLATFORM =~ /mswin|mingw/)
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:runner) { ::RightScale::RightPopen::Runner.new }
|
13
|
-
|
14
|
-
it "should correctly handle many small processes [async]" do
|
15
|
-
pending 'Set environment variable TEST_STRESS to enable' unless ENV['TEST_STRESS']
|
16
|
-
run_count = 100
|
17
|
-
command = is_windows? ? ['cmd.exe', '/c', 'exit 0'] : ['sh', '-c', 'exit 0']
|
18
|
-
@completed = 0
|
19
|
-
@started = 0
|
20
|
-
run_cmd = Proc.new do
|
21
|
-
runner.do_right_popen3_async(command, runner_options={}, popen3_options={}) do |runner_status|
|
22
|
-
@completed += 1
|
23
|
-
runner_status.status.exitstatus.should == 0
|
24
|
-
runner_status.output_text.should == ''
|
25
|
-
runner_status.error_text.should == ''
|
26
|
-
runner_status.pid.should > 0
|
27
|
-
end
|
28
|
-
@started += 1
|
29
|
-
if @started < run_count
|
30
|
-
EM.next_tick { run_cmd.call }
|
31
|
-
end
|
32
|
-
end
|
33
|
-
EM.run do
|
34
|
-
EM.next_tick { run_cmd.call }
|
35
|
-
|
36
|
-
EM::PeriodicTimer.new(1) do
|
37
|
-
if @completed >= run_count
|
38
|
-
EM.stop
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
[:sync, :async].each do |synchronicity|
|
45
|
-
|
46
|
-
context synchronicity do
|
47
|
-
|
48
|
-
it "should redirect output" do
|
49
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
|
50
|
-
runner_status = runner.run_right_popen3(synchronicity, command)
|
51
|
-
runner_status.should_not be_nil
|
52
|
-
runner_status.status.should_not be_nil
|
53
|
-
runner_status.status.exitstatus.should == 0
|
54
|
-
runner_status.output_text.should == STANDARD_MESSAGE + "\n"
|
55
|
-
runner_status.error_text.should == ERROR_MESSAGE + "\n"
|
56
|
-
runner_status.pid.should > 0
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should return the right status" do
|
60
|
-
ruby = `which ruby`.chomp # which is assumed to be on the PATH for the Windows case
|
61
|
-
command = [
|
62
|
-
ruby,
|
63
|
-
File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb')),
|
64
|
-
EXIT_STATUS
|
65
|
-
]
|
66
|
-
status = runner.run_right_popen3(synchronicity, command)
|
67
|
-
status.status.exitstatus.should == EXIT_STATUS
|
68
|
-
status.output_text.should == ''
|
69
|
-
status.error_text.should == ''
|
70
|
-
status.pid.should > 0
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should close all IO handlers, except STDIN, STDOUT and STDERR" do
|
74
|
-
GC.start
|
75
|
-
command = [
|
76
|
-
RUBY_CMD,
|
77
|
-
File.expand_path(File.join(File.dirname(__FILE__), 'produce_status.rb')),
|
78
|
-
EXIT_STATUS
|
79
|
-
]
|
80
|
-
status = runner.run_right_popen3(synchronicity, command)
|
81
|
-
status.status.exitstatus.should == EXIT_STATUS
|
82
|
-
useless_handlers = 0
|
83
|
-
ObjectSpace.each_object(IO) do |io|
|
84
|
-
if ![STDIN, STDOUT, STDERR].include?(io)
|
85
|
-
useless_handlers += 1 unless io.closed?
|
86
|
-
end
|
87
|
-
end
|
88
|
-
useless_handlers.should == 0
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should preserve the integrity of stdout when stderr is unavailable" do
|
92
|
-
count = LARGE_OUTPUT_COUNTER
|
93
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stdout_only.rb'))}\" #{count}"
|
94
|
-
status = runner.run_right_popen3(synchronicity, command)
|
95
|
-
status.status.exitstatus.should == 0
|
96
|
-
|
97
|
-
results = ''
|
98
|
-
count.times do |i|
|
99
|
-
results << "stdout #{i}\n"
|
100
|
-
end
|
101
|
-
status.output_text.should == results
|
102
|
-
status.error_text.should == ''
|
103
|
-
status.pid.should > 0
|
104
|
-
end
|
105
|
-
|
106
|
-
it "should preserve the integrity of stderr when stdout is unavailable" do
|
107
|
-
count = LARGE_OUTPUT_COUNTER
|
108
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_stderr_only.rb'))}\" #{count}"
|
109
|
-
status = runner.run_right_popen3(synchronicity, command)
|
110
|
-
status.status.exitstatus.should == 0
|
111
|
-
|
112
|
-
results = ''
|
113
|
-
count.times do |i|
|
114
|
-
results << "stderr #{i}\n"
|
115
|
-
end
|
116
|
-
status.error_text.should == results
|
117
|
-
status.output_text.should == ''
|
118
|
-
status.pid.should > 0
|
119
|
-
end
|
120
|
-
|
121
|
-
it "should preserve interleaved output when yielding CPU on consumer thread" do
|
122
|
-
lines = 11
|
123
|
-
exit_code = 42
|
124
|
-
repeats = 5
|
125
|
-
force_yield = 0.1
|
126
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{lines} #{exit_code}"
|
127
|
-
actual_output = StringIO.new
|
128
|
-
actual_error = StringIO.new
|
129
|
-
puts
|
130
|
-
stats = runner.run_right_popen3(synchronicity, command, :repeats=>repeats, :force_yield=>force_yield) do |status|
|
131
|
-
status.status.exitstatus.should == exit_code
|
132
|
-
status.pid.should > 0
|
133
|
-
actual_output << status.output_text
|
134
|
-
actual_error << status.error_text
|
135
|
-
end
|
136
|
-
puts
|
137
|
-
stats.size.should == repeats
|
138
|
-
|
139
|
-
expected_output = StringIO.new
|
140
|
-
repeats.times do
|
141
|
-
lines.times do |i|
|
142
|
-
expected_output << "stdout #{i}\n"
|
143
|
-
end
|
144
|
-
end
|
145
|
-
actual_output.string.should == expected_output.string
|
146
|
-
|
147
|
-
expected_error = StringIO.new
|
148
|
-
repeats.times do
|
149
|
-
lines.times do |i|
|
150
|
-
(expected_error << "stderr #{i}\n") if 0 == i % 10
|
151
|
-
end
|
152
|
-
end
|
153
|
-
actual_error.string.should == expected_error.string
|
154
|
-
end
|
155
|
-
|
156
|
-
it "should preserve interleaved output when process is spewing rapidly" do
|
157
|
-
lines = LARGE_OUTPUT_COUNTER
|
158
|
-
exit_code = 99
|
159
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{lines} #{exit_code}"
|
160
|
-
status = runner.run_right_popen3(synchronicity, command, :timeout=>10)
|
161
|
-
status.status.exitstatus.should == exit_code
|
162
|
-
|
163
|
-
expected_output = StringIO.new
|
164
|
-
lines.times do |i|
|
165
|
-
expected_output << "stdout #{i}\n"
|
166
|
-
end
|
167
|
-
status.output_text.should == expected_output.string
|
168
|
-
|
169
|
-
expected_error = StringIO.new
|
170
|
-
lines.times do |i|
|
171
|
-
(expected_error << "stderr #{i}\n") if 0 == i % 10
|
172
|
-
end
|
173
|
-
status.error_text.should == expected_error.string
|
174
|
-
status.pid.should > 0
|
175
|
-
end
|
176
|
-
|
177
|
-
it "should setup environment variables" do
|
178
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
|
179
|
-
status = runner.run_right_popen3(synchronicity, command)
|
180
|
-
status.status.exitstatus.should == 0
|
181
|
-
status.output_text.should_not include('_test_')
|
182
|
-
status = runner.run_right_popen3(synchronicity, command, :env=>{ :__test__ => '42' })
|
183
|
-
status.status.exitstatus.should == 0
|
184
|
-
status.output_text.should match(/^__test__=42$/)
|
185
|
-
status.pid.should > 0
|
186
|
-
end
|
187
|
-
|
188
|
-
it "should restore environment variables" do
|
189
|
-
begin
|
190
|
-
ENV['__test__'] = '41'
|
191
|
-
old_envs = {}
|
192
|
-
ENV.each { |k, v| old_envs[k] = v }
|
193
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
|
194
|
-
status = runner.run_right_popen3(synchronicity, command, :env=>{ :__test__ => '42' })
|
195
|
-
status.status.exitstatus.should == 0
|
196
|
-
status.output_text.should match(/^__test__=42$/)
|
197
|
-
ENV.each { |k, v| old_envs[k].should == v }
|
198
|
-
old_envs.each { |k, v| ENV[k].should == v }
|
199
|
-
status.pid.should > 0
|
200
|
-
ensure
|
201
|
-
ENV.delete('__test__')
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
if is_windows?
|
206
|
-
# FIX: this behavior is currently specific to Windows but should probably be
|
207
|
-
# implemented for Linux.
|
208
|
-
it "should merge the PATH variable instead of overriding it" do
|
209
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
|
210
|
-
status = runner.run_right_popen3(synchronicity, command, :env=>{ 'PATH' => "c:/bogus\\bin" })
|
211
|
-
status.status.exitstatus.should == 0
|
212
|
-
status.output_text.should include('c:\\bogus\\bin;')
|
213
|
-
status.pid.should > 0
|
214
|
-
end
|
215
|
-
else
|
216
|
-
it "should allow running bash command lines starting with a built-in command" do
|
217
|
-
command = "for i in 1 2 3 4 5; do echo $i;done"
|
218
|
-
status = runner.run_right_popen3(synchronicity, command)
|
219
|
-
status.status.exitstatus.should == 0
|
220
|
-
status.output_text.should == "1\n2\n3\n4\n5\n"
|
221
|
-
status.pid.should > 0
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should support running background processes" do
|
225
|
-
command = "(sleep 20)&"
|
226
|
-
now = Time.now
|
227
|
-
status = runner.run_right_popen3(synchronicity, command)
|
228
|
-
finished = Time.now
|
229
|
-
(finished - now).should < 20
|
230
|
-
status.did_timeout.should be_false
|
231
|
-
status.status.exitstatus.should == 0
|
232
|
-
status.output_text.should == ""
|
233
|
-
status.pid.should > 0
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
it "should support raw command arguments" do
|
238
|
-
command = is_windows? ? ["cmd.exe", "/c", "echo", "*"] : ["echo", "*"]
|
239
|
-
status = runner.run_right_popen3(synchronicity, command)
|
240
|
-
status.status.exitstatus.should == 0
|
241
|
-
status.output_text.should == "*\n"
|
242
|
-
status.pid.should > 0
|
243
|
-
end
|
244
|
-
|
245
|
-
it "should run repeatedly without leaking resources" do
|
246
|
-
pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
|
247
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
|
248
|
-
stats = runner.run_right_popen3(synchronicity, command, :repeats=>REPEAT_TEST_COUNTER)
|
249
|
-
stats.each do |status|
|
250
|
-
status.status.exitstatus.should == 0
|
251
|
-
status.output_text.should == STANDARD_MESSAGE + "\n"
|
252
|
-
status.error_text.should == ERROR_MESSAGE + "\n"
|
253
|
-
status.pid.should > 0
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
it "should pass input to child process" do
|
258
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
|
259
|
-
status = runner.run_right_popen3(synchronicity, command, :input=>"42\n")
|
260
|
-
status.status.exitstatus.should == 0
|
261
|
-
status.output_text.should == "43\n"
|
262
|
-
status.error_text.should be_empty
|
263
|
-
status.pid.should > 0
|
264
|
-
end
|
265
|
-
|
266
|
-
it "should run long child process without any watches by default" do
|
267
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'sleeper.rb'))}\""
|
268
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :timeout=>nil)
|
269
|
-
runner_status.status.exitstatus.should == 0
|
270
|
-
runner_status.did_timeout.should be_false
|
271
|
-
runner_status.output_text.should == "To sleep... 0\nTo sleep... 1\nTo sleep... 2\nTo sleep... 3\nThe sleeper must awaken.\n"
|
272
|
-
runner_status.error_text.should == "Perchance to dream... 0\nPerchance to dream... 1\nPerchance to dream... 2\nPerchance to dream... 3\n"
|
273
|
-
end
|
274
|
-
|
275
|
-
it "should interrupt watched child process when timeout expires" do
|
276
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'sleeper.rb'))}\" 10"
|
277
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :expect_timeout=>true, :timeout=>0.1)
|
278
|
-
runner_status.status.success?.should be_false
|
279
|
-
runner_status.did_timeout.should be_true
|
280
|
-
runner_status.output_text.should_not be_empty
|
281
|
-
runner_status.error_text.should_not be_empty
|
282
|
-
end
|
283
|
-
|
284
|
-
it "should allow watched child to write files up to size limit" do
|
285
|
-
::Dir.mktmpdir do |watched_dir|
|
286
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'writer.rb'))}\" \"#{watched_dir}\""
|
287
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :size_limit_bytes=>1000, :watch_directory=>watched_dir, :timeout=>10)
|
288
|
-
runner_status.status.success?.should be_true
|
289
|
-
runner_status.did_size_limit.should be_false
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
it "should interrupt watched child at size limit" do
|
294
|
-
::Dir.mktmpdir do |watched_dir|
|
295
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'writer.rb'))}\" \"#{watched_dir}\""
|
296
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :expect_size_limit=>true, :size_limit_bytes=>100, :watch_directory=>watched_dir, :timeout=>10)
|
297
|
-
runner_status.status.success?.should be_false
|
298
|
-
runner_status.did_size_limit.should be_true
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
it "should handle child processes that close stdout but keep running" do
|
303
|
-
pending 'not implemented for windows' if is_windows? && :sync != synchronicity
|
304
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'stdout.rb'))}\""
|
305
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :expect_timeout=>true, :timeout=>2)
|
306
|
-
runner_status.output_text.should be_empty
|
307
|
-
runner_status.error_text.should == "Closing stdout\n"
|
308
|
-
runner_status.did_timeout.should be_true
|
309
|
-
end
|
310
|
-
|
311
|
-
it "should handle child processes that spawn long running background processes" do
|
312
|
-
pending 'not implemented for windows' if is_windows?
|
313
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'background.rb'))}\""
|
314
|
-
status = runner.run_right_popen3(synchronicity, command)
|
315
|
-
status.status.exitstatus.should == 0
|
316
|
-
status.did_timeout.should be_false
|
317
|
-
status.output_text.should be_empty
|
318
|
-
status.error_text.should be_empty
|
319
|
-
end
|
320
|
-
|
321
|
-
it "should run long child process without any watches by default" do
|
322
|
-
command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'sleeper.rb'))}\""
|
323
|
-
runner_status = runner.run_right_popen3(synchronicity, command, :timeout=>nil)
|
324
|
-
runner_status.status.exitstatus.should == 0
|
325
|
-
runner_status.did_timeout.should be_false
|
326
|
-
runner_status.output_text.should == "To sleep... 0\nTo sleep... 1\nTo sleep... 2\nTo sleep... 3\nThe sleeper must awaken.\n"
|
327
|
-
runner_status.error_text.should == "Perchance to dream... 0\nPerchance to dream... 1\nPerchance to dream... 2\nPerchance to dream... 3\n"
|
328
|
-
end
|
329
|
-
end
|
330
|
-
end
|
331
|
-
end
|