File: io_spec.rb

package info (click to toggle)
ruby-childprocess 5.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 260 kB
  • sloc: ruby: 1,285; makefile: 4
file content (228 lines) | stat: -rw-r--r-- 4,724 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
require File.expand_path('../spec_helper', __FILE__)

describe ChildProcess do
  it "can run even when $stdout is a StringIO" do
    begin
      stdout = $stdout
      $stdout = StringIO.new
      expect { sleeping_ruby.start }.to_not raise_error
    ensure
      $stdout = stdout
    end
  end

  it "can redirect stdout, stderr" do
    process = ruby(<<-CODE)
      [STDOUT, STDERR].each_with_index do |io, idx|
        io.sync = true
        io.puts idx
      end
    CODE

    out = Tempfile.new("stdout-spec")
    err = Tempfile.new("stderr-spec")

    begin
      process.io.stdout = out
      process.io.stderr = err

      process.start
      expect(process.io.stdin).to be_nil
      process.wait

      expect(rewind_and_read(out)).to eq "0\n"
      expect(rewind_and_read(err)).to eq "1\n"
    ensure
      out.close
      err.close
    end
  end

  it "can redirect stdout only" do
    process = ruby(<<-CODE)
      [STDOUT, STDERR].each_with_index do |io, idx|
        io.sync = true
        io.puts idx
      end
    CODE

    out = Tempfile.new("stdout-spec")

    begin
      process.io.stdout = out

      process.start
      process.wait

      expect(rewind_and_read(out)).to eq "0\n"
    ensure
      out.close
    end
  end

  it "pumps all output" do
    process = echo

    out = Tempfile.new("pump")

    begin
      process.io.stdout = out

      process.start
      process.wait

      expect(rewind_and_read(out)).to eq "hello\n"
    ensure
      out.close
    end
  end

  it "can write to stdin if duplex = true" do
    process = cat

    out = Tempfile.new("duplex")
    out.sync = true

    begin
      process.io.stdout = out
      process.io.stderr = out
      process.duplex = true

      process.start
      process.io.stdin.puts "hello world"
      process.io.stdin.close

      process.poll_for_exit(exit_timeout)

      expect(rewind_and_read(out)).to eq "hello world\n"
    ensure
      out.close
    end
  end

  it "can write to stdin interactively if duplex = true" do
    process = cat

    out = Tempfile.new("duplex")
    out.sync = true

    out_receiver = File.open(out.path, "rb")
    begin
      process.io.stdout = out
      process.io.stderr = out
      process.duplex = true

      process.start

      stdin = process.io.stdin

      stdin.puts "hello"
      stdin.flush
      wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\n\z/m) }

      stdin.putc "n"
      stdin.flush
      wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nn\z/m) }

      stdin.print "e"
      stdin.flush
      wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nne\z/m) }

      stdin.printf "w"
      stdin.flush
      wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nnew\z/m) }

      stdin.write "\nworld\n"
      stdin.flush
      wait_until { expect(rewind_and_read(out_receiver)).to match(/\Ahello\r?\nnew\r?\nworld\r?\n\z/m) }

      stdin.close
      process.poll_for_exit(exit_timeout)
    ensure
      out_receiver.close
      out.close
    end
  end

  #
  # this works on JRuby 1.6.5 on my Mac, but for some reason
  # hangs on Travis (running 1.6.5.1 + OpenJDK).
  #
  # http://travis-ci.org/#!/enkessler/childprocess/jobs/487331
  #

  it "works with pipes" do
    process = ruby(<<-CODE)
      STDOUT.print "stdout"
      STDERR.print "stderr"
    CODE

    stdout, stdout_w = IO.pipe
    stderr, stderr_w = IO.pipe

    process.io.stdout = stdout_w
    process.io.stderr = stderr_w

    process.duplex = true

    process.start
    process.wait

    # write streams are closed *after* the process
    # has exited - otherwise it won't work on JRuby
    # with the current Process implementation

    stdout_w.close
    stderr_w.close

    out = stdout.read
    err = stderr.read

    expect([out, err]).to eq %w[stdout stderr]
  end

  it "can set close-on-exec when IO is inherited" do
    port = random_free_port
    server = TCPServer.new("127.0.0.1", port)
    ChildProcess.close_on_exec server

    process = sleeping_ruby
    process.io.inherit!

    process.start
    server.close

    wait_until { can_bind? "127.0.0.1", port }
  end

  it "handles long output" do
    process = ruby <<-CODE
    print 'a'*3000
    CODE

    out = Tempfile.new("long-output")
    out.sync = true

    begin
      process.io.stdout = out

      process.start
      process.wait

      expect(rewind_and_read(out).size).to eq 3000
    ensure
      out.close
    end
  end

  it 'should not inherit stdout and stderr by default' do
    cap = capture_std do
      process = echo
      process.start
      process.wait
    end

    expect(cap.stdout).to eq ''
    expect(cap.stderr).to eq ''
  end
end