childprocess 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.document +6 -6
  3. data/.gitignore +28 -28
  4. data/.rspec +1 -1
  5. data/.travis.yml +51 -52
  6. data/CHANGELOG.md +61 -56
  7. data/Gemfile +18 -18
  8. data/LICENSE +20 -20
  9. data/README.md +212 -200
  10. data/Rakefile +61 -61
  11. data/appveyor.yml +54 -60
  12. data/childprocess.gemspec +30 -29
  13. data/ext/mkrf_conf.rb +24 -24
  14. data/lib/childprocess.rb +210 -210
  15. data/lib/childprocess/abstract_io.rb +36 -36
  16. data/lib/childprocess/abstract_process.rb +192 -192
  17. data/lib/childprocess/errors.rb +37 -37
  18. data/lib/childprocess/jruby.rb +56 -56
  19. data/lib/childprocess/jruby/io.rb +16 -16
  20. data/lib/childprocess/jruby/process.rb +184 -184
  21. data/lib/childprocess/jruby/pump.rb +53 -53
  22. data/lib/childprocess/tools/generator.rb +145 -145
  23. data/lib/childprocess/unix.rb +9 -9
  24. data/lib/childprocess/unix/fork_exec_process.rb +70 -70
  25. data/lib/childprocess/unix/io.rb +21 -21
  26. data/lib/childprocess/unix/lib.rb +186 -186
  27. data/lib/childprocess/unix/platform/i386-linux.rb +12 -12
  28. data/lib/childprocess/unix/platform/i386-solaris.rb +11 -11
  29. data/lib/childprocess/unix/platform/x86_64-linux.rb +12 -12
  30. data/lib/childprocess/unix/platform/x86_64-macosx.rb +11 -11
  31. data/lib/childprocess/unix/posix_spawn_process.rb +134 -134
  32. data/lib/childprocess/unix/process.rb +89 -89
  33. data/lib/childprocess/version.rb +3 -3
  34. data/lib/childprocess/windows.rb +33 -33
  35. data/lib/childprocess/windows/handle.rb +91 -91
  36. data/lib/childprocess/windows/io.rb +25 -25
  37. data/lib/childprocess/windows/lib.rb +416 -416
  38. data/lib/childprocess/windows/process.rb +130 -130
  39. data/lib/childprocess/windows/process_builder.rb +178 -178
  40. data/lib/childprocess/windows/structs.rb +148 -148
  41. data/spec/abstract_io_spec.rb +12 -12
  42. data/spec/childprocess_spec.rb +447 -447
  43. data/spec/io_spec.rb +228 -228
  44. data/spec/jruby_spec.rb +24 -24
  45. data/spec/pid_behavior.rb +12 -12
  46. data/spec/platform_detection_spec.rb +86 -86
  47. data/spec/spec_helper.rb +270 -270
  48. data/spec/unix_spec.rb +57 -57
  49. data/spec/windows_spec.rb +23 -23
  50. metadata +12 -10
@@ -1,24 +1,24 @@
1
- require File.expand_path('../spec_helper', __FILE__)
2
- require "pid_behavior"
3
-
4
- if ChildProcess.jruby? && !ChildProcess.windows?
5
- describe ChildProcess::JRuby::IO do
6
- let(:io) { ChildProcess::JRuby::IO.new }
7
-
8
- it "raises an ArgumentError if given IO does not respond to :to_outputstream" do
9
- expect { io.stdout = nil }.to raise_error(ArgumentError)
10
- end
11
- end
12
-
13
- describe ChildProcess::JRuby::Process do
14
- if ChildProcess.unix?
15
- it_behaves_like "a platform that provides the child's pid"
16
- else
17
- it "raises an error when trying to access the child's pid" do
18
- process = exit_with(0)
19
- process.start
20
- expect { process.pid }.to raise_error(NotImplementedError)
21
- end
22
- end
23
- end
24
- end
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require "pid_behavior"
3
+
4
+ if ChildProcess.jruby? && !ChildProcess.windows?
5
+ describe ChildProcess::JRuby::IO do
6
+ let(:io) { ChildProcess::JRuby::IO.new }
7
+
8
+ it "raises an ArgumentError if given IO does not respond to :to_outputstream" do
9
+ expect { io.stdout = nil }.to raise_error(ArgumentError)
10
+ end
11
+ end
12
+
13
+ describe ChildProcess::JRuby::Process do
14
+ if ChildProcess.unix?
15
+ it_behaves_like "a platform that provides the child's pid"
16
+ else
17
+ it "raises an error when trying to access the child's pid" do
18
+ process = exit_with(0)
19
+ process.start
20
+ expect { process.pid }.to raise_error(NotImplementedError)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,12 +1,12 @@
1
- require File.expand_path('../spec_helper', __FILE__)
2
-
3
- shared_examples_for "a platform that provides the child's pid" do
4
- it "knows the child's pid" do
5
- Tempfile.open("pid-spec") do |file|
6
- process = write_pid(file.path).start
7
- process.wait
8
-
9
- expect(process.pid).to eq rewind_and_read(file).chomp.to_i
10
- end
11
- end
12
- end
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ shared_examples_for "a platform that provides the child's pid" do
4
+ it "knows the child's pid" do
5
+ Tempfile.open("pid-spec") do |file|
6
+ process = write_pid(file.path).start
7
+ process.wait
8
+
9
+ expect(process.pid).to eq rewind_and_read(file).chomp.to_i
10
+ end
11
+ end
12
+ end
@@ -1,86 +1,86 @@
1
- require File.expand_path('../spec_helper', __FILE__)
2
-
3
- # Q: Should platform detection concern be extracted from ChildProcess?
4
- describe ChildProcess do
5
-
6
- describe ".arch" do
7
- subject { described_class.arch }
8
-
9
- before(:each) { described_class.instance_variable_set(:@arch, nil) }
10
-
11
- after(:each) { described_class.instance_variable_set(:@arch, nil) }
12
-
13
- shared_examples 'expected_arch_for_host_cpu' do |host_cpu, expected_arch|
14
- context "when host_cpu is '#{host_cpu}'" do
15
- before :each do
16
- allow(RbConfig::CONFIG).
17
- to receive(:[]).
18
- with('host_cpu').
19
- and_return(expected_arch)
20
- end
21
-
22
- it { is_expected.to eq expected_arch }
23
- end
24
- end
25
-
26
- # Normal cases: not macosx - depends only on host_cpu
27
- context "when os is *not* 'macosx'" do
28
- before :each do
29
- allow(described_class).to receive(:os).and_return(:not_macosx)
30
- end
31
-
32
- [
33
- { host_cpu: 'i386', expected_arch: 'i386' },
34
- { host_cpu: 'i486', expected_arch: 'i386' },
35
- { host_cpu: 'i586', expected_arch: 'i386' },
36
- { host_cpu: 'i686', expected_arch: 'i386' },
37
- { host_cpu: 'amd64', expected_arch: 'x86_64' },
38
- { host_cpu: 'x86_64', expected_arch: 'x86_64' },
39
- { host_cpu: 'ppc', expected_arch: 'powerpc' },
40
- { host_cpu: 'powerpc', expected_arch: 'powerpc' },
41
- { host_cpu: 'unknown', expected_arch: 'unknown' },
42
- ].each do |args|
43
- include_context 'expected_arch_for_host_cpu', args.values
44
- end
45
- end
46
-
47
- # Special cases: macosx - when host_cpu is i686, have to re-check
48
- context "when os is 'macosx'" do
49
- before :each do
50
- allow(described_class).to receive(:os).and_return(:macosx)
51
- end
52
-
53
- context "when host_cpu is 'i686' " do
54
- shared_examples 'expected_arch_on_macosx_i686' do |is_64, expected_arch|
55
- context "when Ruby is #{is_64 ? 64 : 32}-bit" do
56
- before :each do
57
- allow(described_class).
58
- to receive(:is_64_bit?).
59
- and_return(is_64)
60
- end
61
-
62
- include_context 'expected_arch_for_host_cpu', 'i686', expected_arch
63
- end
64
- end
65
-
66
- [
67
- { is_64: true, expected_arch: 'x86_64' },
68
- { is_64: false, expected_arch: 'i386' }
69
- ].each do |args|
70
- include_context 'expected_arch_on_macosx_i686', args.values
71
- end
72
- end
73
-
74
- [
75
- { host_cpu: 'amd64', expected_arch: 'x86_64' },
76
- { host_cpu: 'x86_64', expected_arch: 'x86_64' },
77
- { host_cpu: 'ppc', expected_arch: 'powerpc' },
78
- { host_cpu: 'powerpc', expected_arch: 'powerpc' },
79
- { host_cpu: 'unknown', expected_arch: 'unknown' },
80
- ].each do |args|
81
- include_context 'expected_arch_for_host_cpu', args.values
82
- end
83
- end
84
- end
85
-
86
- end
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ # Q: Should platform detection concern be extracted from ChildProcess?
4
+ describe ChildProcess do
5
+
6
+ describe ".arch" do
7
+ subject { described_class.arch }
8
+
9
+ before(:each) { described_class.instance_variable_set(:@arch, nil) }
10
+
11
+ after(:each) { described_class.instance_variable_set(:@arch, nil) }
12
+
13
+ shared_examples 'expected_arch_for_host_cpu' do |host_cpu, expected_arch|
14
+ context "when host_cpu is '#{host_cpu}'" do
15
+ before :each do
16
+ allow(RbConfig::CONFIG).
17
+ to receive(:[]).
18
+ with('host_cpu').
19
+ and_return(expected_arch)
20
+ end
21
+
22
+ it { is_expected.to eq expected_arch }
23
+ end
24
+ end
25
+
26
+ # Normal cases: not macosx - depends only on host_cpu
27
+ context "when os is *not* 'macosx'" do
28
+ before :each do
29
+ allow(described_class).to receive(:os).and_return(:not_macosx)
30
+ end
31
+
32
+ [
33
+ { host_cpu: 'i386', expected_arch: 'i386' },
34
+ { host_cpu: 'i486', expected_arch: 'i386' },
35
+ { host_cpu: 'i586', expected_arch: 'i386' },
36
+ { host_cpu: 'i686', expected_arch: 'i386' },
37
+ { host_cpu: 'amd64', expected_arch: 'x86_64' },
38
+ { host_cpu: 'x86_64', expected_arch: 'x86_64' },
39
+ { host_cpu: 'ppc', expected_arch: 'powerpc' },
40
+ { host_cpu: 'powerpc', expected_arch: 'powerpc' },
41
+ { host_cpu: 'unknown', expected_arch: 'unknown' },
42
+ ].each do |args|
43
+ include_context 'expected_arch_for_host_cpu', args.values
44
+ end
45
+ end
46
+
47
+ # Special cases: macosx - when host_cpu is i686, have to re-check
48
+ context "when os is 'macosx'" do
49
+ before :each do
50
+ allow(described_class).to receive(:os).and_return(:macosx)
51
+ end
52
+
53
+ context "when host_cpu is 'i686' " do
54
+ shared_examples 'expected_arch_on_macosx_i686' do |is_64, expected_arch|
55
+ context "when Ruby is #{is_64 ? 64 : 32}-bit" do
56
+ before :each do
57
+ allow(described_class).
58
+ to receive(:is_64_bit?).
59
+ and_return(is_64)
60
+ end
61
+
62
+ include_context 'expected_arch_for_host_cpu', 'i686', expected_arch
63
+ end
64
+ end
65
+
66
+ [
67
+ { is_64: true, expected_arch: 'x86_64' },
68
+ { is_64: false, expected_arch: 'i386' }
69
+ ].each do |args|
70
+ include_context 'expected_arch_on_macosx_i686', args.values
71
+ end
72
+ end
73
+
74
+ [
75
+ { host_cpu: 'amd64', expected_arch: 'x86_64' },
76
+ { host_cpu: 'x86_64', expected_arch: 'x86_64' },
77
+ { host_cpu: 'ppc', expected_arch: 'powerpc' },
78
+ { host_cpu: 'powerpc', expected_arch: 'powerpc' },
79
+ { host_cpu: 'unknown', expected_arch: 'unknown' },
80
+ ].each do |args|
81
+ include_context 'expected_arch_for_host_cpu', args.values
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -1,270 +1,270 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
-
4
- unless defined?(JRUBY_VERSION)
5
- require 'coveralls'
6
- Coveralls.wear!
7
- end
8
-
9
- require 'childprocess'
10
- require 'rspec'
11
- require 'tempfile'
12
- require 'socket'
13
- require 'stringio'
14
- require 'ostruct'
15
-
16
- module ChildProcessSpecHelper
17
- RUBY = defined?(Gem) ? Gem.ruby : 'ruby'
18
-
19
- def ruby_process(*args)
20
- @process = ChildProcess.build(RUBY , *args)
21
- end
22
-
23
- def windows_process(*args)
24
- @process = ChildProcess.build("powershell", *args)
25
- end
26
-
27
- def sleeping_ruby(seconds = nil)
28
- if seconds
29
- ruby_process("-e", "sleep #{seconds}")
30
- else
31
- ruby_process("-e", "sleep")
32
- end
33
- end
34
-
35
- def invalid_process
36
- @process = ChildProcess.build("unlikelytoexist")
37
- end
38
-
39
- def ignored(signal)
40
- code = <<-RUBY
41
- trap(#{signal.inspect}, "IGNORE")
42
- sleep
43
- RUBY
44
-
45
- ruby_process tmp_script(code)
46
- end
47
-
48
- def write_env(path)
49
- if ChildProcess.os == :windows
50
- ps_env_file_path = File.expand_path(File.dirname(__FILE__))
51
- args = ['-File', "#{ps_env_file_path}/get_env.ps1", path]
52
- windows_process(*args)
53
- else
54
- code = <<-RUBY
55
- File.open(#{path.inspect}, "w") { |f| f << ENV.inspect }
56
- RUBY
57
- ruby_process tmp_script(code)
58
- end
59
- end
60
-
61
- def write_argv(path, *args)
62
- code = <<-RUBY
63
- File.open(#{path.inspect}, "w") { |f| f << ARGV.inspect }
64
- RUBY
65
-
66
- ruby_process(tmp_script(code), *args)
67
- end
68
-
69
- def write_pid(path)
70
- code = <<-RUBY
71
- File.open(#{path.inspect}, "w") { |f| f << Process.pid }
72
- RUBY
73
-
74
- ruby_process tmp_script(code)
75
- end
76
-
77
- def write_pid_in_sleepy_grand_child(path)
78
- code = <<-RUBY
79
- system "ruby", "-e", 'File.open(#{path.inspect}, "w") { |f| f << Process.pid; f.flush }; sleep'
80
- RUBY
81
-
82
- ruby_process tmp_script(code)
83
- end
84
-
85
- def exit_with(exit_code)
86
- ruby_process(tmp_script("exit(#{exit_code})"))
87
- end
88
-
89
- def with_env(hash)
90
- hash.each { |k,v| ENV[k] = v }
91
- begin
92
- yield
93
- ensure
94
- hash.each_key { |k| ENV[k] = nil }
95
- end
96
- end
97
-
98
- def tmp_script(code)
99
- # use an ivar to avoid GC
100
- @tf = Tempfile.new("childprocess-temp")
101
- @tf << code
102
- @tf.close
103
-
104
- puts code if $DEBUG
105
-
106
- @tf.path
107
- end
108
-
109
- def cat
110
- if ChildProcess.os == :windows
111
- ruby(<<-CODE)
112
- STDIN.sync = STDOUT.sync = true
113
- IO.copy_stream(STDIN, STDOUT)
114
- CODE
115
- else
116
- ChildProcess.build("cat")
117
- end
118
- end
119
-
120
- def echo
121
- if ChildProcess.os == :windows
122
- ruby(<<-CODE)
123
- STDIN.sync = true
124
- STDOUT.sync = true
125
-
126
- puts "hello"
127
- CODE
128
- else
129
- ChildProcess.build("echo", "hello")
130
- end
131
- end
132
-
133
- def ruby(code)
134
- ruby_process(tmp_script(code))
135
- end
136
-
137
- def with_executable_at(path, &blk)
138
- if ChildProcess.os == :windows
139
- path << ".cmd"
140
- content = "#{RUBY} -e 'sleep 10' \n @echo foo"
141
- else
142
- content = "#!/bin/sh\nsleep 10\necho foo"
143
- end
144
-
145
- File.open(path, 'w', 0744) { |io| io << content }
146
- proc = ChildProcess.build(path)
147
-
148
- begin
149
- yield proc
150
- ensure
151
- proc.stop if proc.alive?
152
- File.delete path
153
- end
154
- end
155
-
156
- def exit_timeout
157
- 10
158
- end
159
-
160
- def random_free_port
161
- server = TCPServer.new('127.0.0.1', 0)
162
- port = server.addr[1]
163
- server.close
164
-
165
- port
166
- end
167
-
168
- def with_tmpdir(&blk)
169
- name = "#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}"
170
- FileUtils.mkdir_p(name)
171
-
172
- begin
173
- yield File.expand_path(name)
174
- ensure
175
- FileUtils.rm_rf name
176
- end
177
- end
178
-
179
- def wait_until(timeout = 10, &blk)
180
- end_time = Time.now + timeout
181
- last_exception = nil
182
-
183
- until Time.now >= end_time
184
- begin
185
- result = yield
186
- return result if result
187
- rescue RSpec::Expectations::ExpectationNotMetError => ex
188
- last_exception = ex
189
- end
190
-
191
- sleep 0.01
192
- end
193
-
194
- msg = "timed out after #{timeout} seconds"
195
- msg << ":\n#{last_exception.message}" if last_exception
196
-
197
- raise msg
198
- end
199
-
200
- def can_bind?(host, port)
201
- TCPServer.new(host, port).close
202
- true
203
- rescue
204
- false
205
- end
206
-
207
- def rewind_and_read(io)
208
- io.rewind
209
- io.read
210
- end
211
-
212
- def alive?(pid)
213
- if ChildProcess.windows?
214
- ChildProcess::Windows::Lib.alive?(pid)
215
- else
216
- begin
217
- Process.getpgid pid
218
- true
219
- rescue Errno::ESRCH
220
- false
221
- end
222
- end
223
- end
224
-
225
- def capture_std
226
- orig_out = STDOUT.clone
227
- orig_err = STDERR.clone
228
-
229
- out = Tempfile.new 'captured-stdout'
230
- err = Tempfile.new 'captured-stderr'
231
- out.sync = true
232
- err.sync = true
233
-
234
- STDOUT.reopen out
235
- STDERR.reopen err
236
-
237
- yield
238
-
239
- OpenStruct.new stdout: rewind_and_read(out), stderr: rewind_and_read(err)
240
- ensure
241
- STDOUT.reopen orig_out
242
- STDERR.reopen orig_err
243
- end
244
-
245
- def generate_log_messages
246
- ChildProcess.logger.level = Logger::DEBUG
247
-
248
- process = exit_with(0).start
249
- process.wait
250
- process.poll_for_exit(0.1)
251
- end
252
-
253
- end # ChildProcessSpecHelper
254
-
255
- Thread.abort_on_exception = true
256
-
257
- RSpec.configure do |c|
258
- c.include(ChildProcessSpecHelper)
259
- c.after(:each) {
260
- defined?(@process) && @process.alive? && @process.stop
261
- }
262
-
263
- if ChildProcess.jruby? && ChildProcess.new("true").instance_of?(ChildProcess::JRuby::Process)
264
- c.filter_run_excluding :process_builder => false
265
- end
266
-
267
- if ChildProcess.linux? && ChildProcess.posix_spawn?
268
- c.filter_run_excluding :posix_spawn_on_linux => false
269
- end
270
- end
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+
4
+ unless defined?(JRUBY_VERSION)
5
+ require 'coveralls'
6
+ Coveralls.wear!
7
+ end
8
+
9
+ require 'childprocess'
10
+ require 'rspec'
11
+ require 'tempfile'
12
+ require 'socket'
13
+ require 'stringio'
14
+ require 'ostruct'
15
+
16
+ module ChildProcessSpecHelper
17
+ RUBY = defined?(Gem) ? Gem.ruby : 'ruby'
18
+
19
+ def ruby_process(*args)
20
+ @process = ChildProcess.build(RUBY , *args)
21
+ end
22
+
23
+ def windows_process(*args)
24
+ @process = ChildProcess.build("powershell", *args)
25
+ end
26
+
27
+ def sleeping_ruby(seconds = nil)
28
+ if seconds
29
+ ruby_process("-e", "sleep #{seconds}")
30
+ else
31
+ ruby_process("-e", "sleep")
32
+ end
33
+ end
34
+
35
+ def invalid_process
36
+ @process = ChildProcess.build("unlikelytoexist")
37
+ end
38
+
39
+ def ignored(signal)
40
+ code = <<-RUBY
41
+ trap(#{signal.inspect}, "IGNORE")
42
+ sleep
43
+ RUBY
44
+
45
+ ruby_process tmp_script(code)
46
+ end
47
+
48
+ def write_env(path)
49
+ if ChildProcess.os == :windows
50
+ ps_env_file_path = File.expand_path(File.dirname(__FILE__))
51
+ args = ['-File', "#{ps_env_file_path}/get_env.ps1", path]
52
+ windows_process(*args)
53
+ else
54
+ code = <<-RUBY
55
+ File.open(#{path.inspect}, "w") { |f| f << ENV.inspect }
56
+ RUBY
57
+ ruby_process tmp_script(code)
58
+ end
59
+ end
60
+
61
+ def write_argv(path, *args)
62
+ code = <<-RUBY
63
+ File.open(#{path.inspect}, "w") { |f| f << ARGV.inspect }
64
+ RUBY
65
+
66
+ ruby_process(tmp_script(code), *args)
67
+ end
68
+
69
+ def write_pid(path)
70
+ code = <<-RUBY
71
+ File.open(#{path.inspect}, "w") { |f| f << Process.pid }
72
+ RUBY
73
+
74
+ ruby_process tmp_script(code)
75
+ end
76
+
77
+ def write_pid_in_sleepy_grand_child(path)
78
+ code = <<-RUBY
79
+ system "ruby", "-e", 'File.open(#{path.inspect}, "w") { |f| f << Process.pid; f.flush }; sleep'
80
+ RUBY
81
+
82
+ ruby_process tmp_script(code)
83
+ end
84
+
85
+ def exit_with(exit_code)
86
+ ruby_process(tmp_script("exit(#{exit_code})"))
87
+ end
88
+
89
+ def with_env(hash)
90
+ hash.each { |k,v| ENV[k] = v }
91
+ begin
92
+ yield
93
+ ensure
94
+ hash.each_key { |k| ENV[k] = nil }
95
+ end
96
+ end
97
+
98
+ def tmp_script(code)
99
+ # use an ivar to avoid GC
100
+ @tf = Tempfile.new("childprocess-temp")
101
+ @tf << code
102
+ @tf.close
103
+
104
+ puts code if $DEBUG
105
+
106
+ @tf.path
107
+ end
108
+
109
+ def cat
110
+ if ChildProcess.os == :windows
111
+ ruby(<<-CODE)
112
+ STDIN.sync = STDOUT.sync = true
113
+ IO.copy_stream(STDIN, STDOUT)
114
+ CODE
115
+ else
116
+ ChildProcess.build("cat")
117
+ end
118
+ end
119
+
120
+ def echo
121
+ if ChildProcess.os == :windows
122
+ ruby(<<-CODE)
123
+ STDIN.sync = true
124
+ STDOUT.sync = true
125
+
126
+ puts "hello"
127
+ CODE
128
+ else
129
+ ChildProcess.build("echo", "hello")
130
+ end
131
+ end
132
+
133
+ def ruby(code)
134
+ ruby_process(tmp_script(code))
135
+ end
136
+
137
+ def with_executable_at(path, &blk)
138
+ if ChildProcess.os == :windows
139
+ path << ".cmd"
140
+ content = "#{RUBY} -e 'sleep 10' \n @echo foo"
141
+ else
142
+ content = "#!/bin/sh\nsleep 10\necho foo"
143
+ end
144
+
145
+ File.open(path, 'w', 0744) { |io| io << content }
146
+ proc = ChildProcess.build(path)
147
+
148
+ begin
149
+ yield proc
150
+ ensure
151
+ proc.stop if proc.alive?
152
+ File.delete path
153
+ end
154
+ end
155
+
156
+ def exit_timeout
157
+ 10
158
+ end
159
+
160
+ def random_free_port
161
+ server = TCPServer.new('127.0.0.1', 0)
162
+ port = server.addr[1]
163
+ server.close
164
+
165
+ port
166
+ end
167
+
168
+ def with_tmpdir(&blk)
169
+ name = "#{Time.now.strftime("%Y%m%d")}-#{$$}-#{rand(0x100000000).to_s(36)}"
170
+ FileUtils.mkdir_p(name)
171
+
172
+ begin
173
+ yield File.expand_path(name)
174
+ ensure
175
+ FileUtils.rm_rf name
176
+ end
177
+ end
178
+
179
+ def wait_until(timeout = 10, &blk)
180
+ end_time = Time.now + timeout
181
+ last_exception = nil
182
+
183
+ until Time.now >= end_time
184
+ begin
185
+ result = yield
186
+ return result if result
187
+ rescue RSpec::Expectations::ExpectationNotMetError => ex
188
+ last_exception = ex
189
+ end
190
+
191
+ sleep 0.01
192
+ end
193
+
194
+ msg = "timed out after #{timeout} seconds"
195
+ msg << ":\n#{last_exception.message}" if last_exception
196
+
197
+ raise msg
198
+ end
199
+
200
+ def can_bind?(host, port)
201
+ TCPServer.new(host, port).close
202
+ true
203
+ rescue
204
+ false
205
+ end
206
+
207
+ def rewind_and_read(io)
208
+ io.rewind
209
+ io.read
210
+ end
211
+
212
+ def alive?(pid)
213
+ if ChildProcess.windows?
214
+ ChildProcess::Windows::Lib.alive?(pid)
215
+ else
216
+ begin
217
+ Process.getpgid pid
218
+ true
219
+ rescue Errno::ESRCH
220
+ false
221
+ end
222
+ end
223
+ end
224
+
225
+ def capture_std
226
+ orig_out = STDOUT.clone
227
+ orig_err = STDERR.clone
228
+
229
+ out = Tempfile.new 'captured-stdout'
230
+ err = Tempfile.new 'captured-stderr'
231
+ out.sync = true
232
+ err.sync = true
233
+
234
+ STDOUT.reopen out
235
+ STDERR.reopen err
236
+
237
+ yield
238
+
239
+ OpenStruct.new stdout: rewind_and_read(out), stderr: rewind_and_read(err)
240
+ ensure
241
+ STDOUT.reopen orig_out
242
+ STDERR.reopen orig_err
243
+ end
244
+
245
+ def generate_log_messages
246
+ ChildProcess.logger.level = Logger::DEBUG
247
+
248
+ process = exit_with(0).start
249
+ process.wait
250
+ process.poll_for_exit(0.1)
251
+ end
252
+
253
+ end # ChildProcessSpecHelper
254
+
255
+ Thread.abort_on_exception = true
256
+
257
+ RSpec.configure do |c|
258
+ c.include(ChildProcessSpecHelper)
259
+ c.after(:each) {
260
+ defined?(@process) && @process.alive? && @process.stop
261
+ }
262
+
263
+ if ChildProcess.jruby? && ChildProcess.new("true").instance_of?(ChildProcess::JRuby::Process)
264
+ c.filter_run_excluding :process_builder => false
265
+ end
266
+
267
+ if ChildProcess.linux? && ChildProcess.posix_spawn?
268
+ c.filter_run_excluding :posix_spawn_on_linux => false
269
+ end
270
+ end