right_popen 1.0.20-x86-mswin32-60 → 1.0.21-x86-mswin32-60

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.
@@ -23,6 +23,6 @@
23
23
 
24
24
  module RightScale
25
25
  module RightPopen
26
- VERSION = "1.0.20"
26
+ VERSION = "1.0.21"
27
27
  end
28
28
  end
Binary file
@@ -1,8 +1,9 @@
1
1
  count = ARGV[0] ? ARGV[0].to_i : 1
2
+ exit_code = ARGV[1] ? ARGV[1].to_i : 0
2
3
 
3
4
  count.times do |i|
4
5
  $stderr.puts "stderr #{i}" if 0 == i % 10
5
6
  $stdout.puts "stdout #{i}"
6
7
  end
7
8
 
8
- exit 99
9
+ exit exit_code
@@ -1,5 +1,6 @@
1
1
  require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
2
2
  require File.expand_path(File.join(File.dirname(__FILE__), 'runner'))
3
+ require 'stringio'
3
4
 
4
5
  module RightScale
5
6
  describe 'popen3' do
@@ -105,24 +106,62 @@ module RightScale
105
106
  status.pid.should > 0
106
107
  end
107
108
 
108
- it 'should preserve the integrity of stdout and stderr despite interleaving' do
109
- count = LARGE_OUTPUT_COUNTER
110
- command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{count}"
109
+ it 'should preserve interleaved output when yielding CPU on consumer thread' do
110
+ lines = 11
111
+ exit_code = 42
112
+ repeats = 5
113
+ force_yield = 0.1
114
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{lines} #{exit_code}"
115
+ runner = Runner.new
116
+ actual_output = StringIO.new
117
+ actual_error = StringIO.new
118
+ puts
119
+ stats = runner.run_right_popen(command, :repeats=>repeats, :force_yield=>force_yield) do |status|
120
+ status.status.exitstatus.should == exit_code
121
+ status.pid.should > 0
122
+ actual_output << status.output_text
123
+ actual_error << status.error_text
124
+ print '+'
125
+ end
126
+ puts
127
+ stats.size.should == repeats
128
+
129
+ expected_output = StringIO.new
130
+ repeats.times do
131
+ lines.times do |i|
132
+ expected_output << "stdout #{i}\n"
133
+ end
134
+ end
135
+ actual_output.string.should == expected_output.string
136
+
137
+ expected_error = StringIO.new
138
+ repeats.times do
139
+ lines.times do |i|
140
+ (expected_error << "stderr #{i}\n") if 0 == i % 10
141
+ end
142
+ end
143
+ actual_error.string.should == expected_error.string
144
+ end
145
+
146
+ it 'should preserve interleaved output when process is spewing rapidly' do
147
+ lines = LARGE_OUTPUT_COUNTER
148
+ exit_code = 99
149
+ command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_mixed_output.rb'))}\" #{lines} #{exit_code}"
111
150
  runner = Runner.new
112
151
  status = runner.run_right_popen(command)
113
- status.status.exitstatus.should == 99
152
+ status.status.exitstatus.should == exit_code
114
153
 
115
- results = ''
116
- count.times do |i|
117
- results << "stdout #{i}\n"
154
+ expected_output = StringIO.new
155
+ lines.times do |i|
156
+ expected_output << "stdout #{i}\n"
118
157
  end
119
- status.output_text.should == results
158
+ status.output_text.should == expected_output.string
120
159
 
121
- results = ''
122
- count.times do |i|
123
- (results << "stderr #{i}\n") if 0 == i % 10
160
+ expected_error = StringIO.new
161
+ lines.times do |i|
162
+ (expected_error << "stderr #{i}\n") if 0 == i % 10
124
163
  end
125
- status.error_text.should == results
164
+ status.error_text.should == expected_error.string
126
165
  status.pid.should > 0
127
166
  end
128
167
 
@@ -132,7 +171,7 @@ module RightScale
132
171
  status = runner.run_right_popen(command)
133
172
  status.status.exitstatus.should == 0
134
173
  status.output_text.should_not include('_test_')
135
- status = runner.run_right_popen(command, :__test__ => '42')
174
+ status = runner.run_right_popen(command, :env=>{ :__test__ => '42' })
136
175
  status.status.exitstatus.should == 0
137
176
  status.output_text.should match(/^__test__=42$/)
138
177
  status.pid.should > 0
@@ -145,7 +184,7 @@ module RightScale
145
184
  ENV.each { |k, v| old_envs[k] = v }
146
185
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
147
186
  runner = Runner.new
148
- status = runner.run_right_popen(command, :__test__ => '42')
187
+ status = runner.run_right_popen(command, :env=>{ :__test__ => '42' })
149
188
  status.status.exitstatus.should == 0
150
189
  status.output_text.should match(/^__test__=42$/)
151
190
  ENV.each { |k, v| old_envs[k].should == v }
@@ -162,7 +201,7 @@ module RightScale
162
201
  it 'should merge the PATH variable instead of overriding it' do
163
202
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'print_env.rb'))}\""
164
203
  runner = Runner.new
165
- status = runner.run_right_popen(command, 'PATH' => "c:/bogus\\bin")
204
+ status = runner.run_right_popen(command, :env=>{ 'PATH' => "c:/bogus\\bin" })
166
205
  status.status.exitstatus.should == 0
167
206
  status.output_text.should include('c:\\bogus\\bin;')
168
207
  status.pid.should > 0
@@ -204,17 +243,19 @@ module RightScale
204
243
  pending 'Set environment variable TEST_LEAK to enable' unless ENV['TEST_LEAK']
205
244
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'produce_output.rb'))}\" \"#{STANDARD_MESSAGE}\" \"#{ERROR_MESSAGE}\""
206
245
  runner = Runner.new
207
- status = runner.run_right_popen(command, nil, nil, REPEAT_TEST_COUNTER)
208
- status.status.exitstatus.should == 0
209
- status.output_text.should == STANDARD_MESSAGE + "\n"
210
- status.error_text.should == ERROR_MESSAGE + "\n"
211
- status.pid.should > 0
246
+ stats = runner.run_right_popen(command, :repeats=>REPEAT_TEST_COUNTER)
247
+ stats.each do |status|
248
+ status.status.exitstatus.should == 0
249
+ status.output_text.should == STANDARD_MESSAGE + "\n"
250
+ status.error_text.should == ERROR_MESSAGE + "\n"
251
+ status.pid.should > 0
252
+ end
212
253
  end
213
254
 
214
255
  it 'should pass input to child process' do
215
256
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'increment.rb'))}\""
216
257
  runner = Runner.new
217
- status = runner.run_right_popen(command, nil, "42\n")
258
+ status = runner.run_right_popen(command, :input=>"42\n")
218
259
  status.status.exitstatus.should == 0
219
260
  status.output_text.should == "43\n"
220
261
  status.error_text.should be_empty
@@ -225,7 +266,7 @@ module RightScale
225
266
  pending 'not implemented for windows' if is_windows?
226
267
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'stdout.rb'))}\""
227
268
  runner = Runner.new
228
- status = runner.run_right_popen(command, nil, nil)
269
+ status = runner.run_right_popen(command, :expect_timeout=>true, :timeout=>2)
229
270
  status.did_timeout.should be_true
230
271
  status.output_text.should be_empty
231
272
  status.error_text.should == "Closing stdout\n"
@@ -235,7 +276,7 @@ module RightScale
235
276
  pending 'not implemented for windows' if is_windows?
236
277
  command = "\"#{RUBY_CMD}\" \"#{File.expand_path(File.join(File.dirname(__FILE__), 'background.rb'))}\""
237
278
  runner = Runner.new
238
- status = runner.run_right_popen(command, nil, nil)
279
+ status = runner.run_right_popen(command)
239
280
  status.status.exitstatus.should == 0
240
281
  status.did_timeout.should be_false
241
282
  status.output_text.should be_empty
@@ -24,18 +24,20 @@
24
24
  module RightScale
25
25
  class Runner
26
26
  class RunnerStatus
27
- def initialize(command, block)
27
+ def initialize(command, options={}, &callback)
28
+ options = {:force_yield=>nil, :timeout=>nil, :expect_timeout=>false}.merge(options)
28
29
  @output_text = ""
29
30
  @error_text = ""
30
31
  @status = nil
31
32
  @did_timeout = false
32
- @callback = block
33
+ @callback = callback
33
34
  @pid = nil
35
+ @force_yield = options[:force_yield]
34
36
  EM.next_tick do
35
- @timeout = EM::Timer.new(2) do
36
- puts "\n** Failed to run #{command.inspect}: Timeout"
37
+ @timeout = EM::Timer.new(options[:timeout] || 2) do
38
+ puts "\n** Failed to run #{command.inspect}: Timeout" unless options[:expect_timeout]
37
39
  @did_timeout = true
38
- @callback.call(self)
40
+ @callback.call(self) if options[:expect_timeout]
39
41
  end
40
42
  end
41
43
  end
@@ -43,10 +45,12 @@ module RightScale
43
45
  attr_accessor :output_text, :error_text, :status, :did_timeout, :pid
44
46
 
45
47
  def on_read_stdout(data)
48
+ sleep @force_yield if @force_yield
46
49
  @output_text << data
47
50
  end
48
51
 
49
52
  def on_read_stderr(data)
53
+ sleep @force_yield if @force_yield
50
54
  @error_text << data
51
55
  end
52
56
 
@@ -69,42 +73,51 @@ module RightScale
69
73
  @last_iteration = 0
70
74
  end
71
75
 
72
- def do_right_popen(command, env=nil, input=nil, &callback)
73
- status = RunnerStatus.new(command, callback)
76
+ def do_right_popen(command, options={}, &callback)
77
+ options = {:env=>nil, :input=>nil, :timeout=>nil, :force_yield=>nil, :expect_timeout=>false}.merge(options)
78
+ status = RunnerStatus.new(command, options, &callback)
74
79
  RightScale.popen3(:command => command,
75
- :input => input,
76
- :target => status,
77
- :environment => env,
78
- :stdout_handler => :on_read_stdout,
79
- :stderr_handler => :on_read_stderr,
80
- :pid_handler => :on_pid,
81
- :exit_handler => :on_exit)
80
+ :input => options[:input],
81
+ :target => status,
82
+ :environment => options[:env],
83
+ :stdout_handler => :on_read_stdout,
84
+ :stderr_handler => :on_read_stderr,
85
+ :pid_handler => :on_pid,
86
+ :exit_handler => :on_exit)
82
87
  status
83
88
  end
84
89
 
85
- def run_right_popen(command, env=nil, input=nil, count=1)
90
+ def run_right_popen(command, options={}, &callback)
91
+ options = {:repeats=>1, :env=>nil, :input=>nil, :timeout=>nil, :force_yield=>nil, :expect_timeout=>false}.merge(options)
86
92
  begin
87
93
  @iterations = 0
94
+ @repeats = options[:repeats]
95
+ @stats = []
88
96
  EM.run do
89
- EM.next_tick do
90
- do_right_popen(command, env, input) do |status|
91
- maybe_continue(status)
97
+ EM.defer do
98
+ do_right_popen(command, options) do |status|
99
+ maybe_continue(status, command, options, &callback)
92
100
  end
93
101
  end
94
102
  end
95
- @status
103
+ @stats.size < 2 ? @stats.first : @stats
96
104
  rescue Exception => e
97
105
  puts "\n** Failed: #{e.message} FROM\n#{e.backtrace.join("\n")}"
98
106
  raise e
99
107
  end
100
108
  end
101
109
 
102
- def maybe_continue(status)
110
+ def maybe_continue(status, command, options, &callback)
103
111
  @iterations += 1
104
- if @iterations < @count
105
- do_right_popen(command, env, input) {|status| maybe_continue(status)}
112
+ @stats << status
113
+ callback.call(status) if callback
114
+ if @iterations < @repeats
115
+ EM.defer do
116
+ do_right_popen(command, options) do |status|
117
+ maybe_continue(status, command, options, &callback)
118
+ end
119
+ end
106
120
  else
107
- @status = status
108
121
  EM.stop
109
122
  end
110
123
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_popen
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 61
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 20
10
- version: 1.0.20
9
+ - 21
10
+ version: 1.0.21
11
11
  platform: x86-mswin32-60
12
12
  authors:
13
13
  - Scott Messier
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-03-07 00:00:00 -08:00
20
+ date: 2012-04-25 00:00:00 -07:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency