File: spawn_process_spec.rb

package info (click to toggle)
ruby-aruba 2.1.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,972 kB
  • sloc: ruby: 7,151; javascript: 6,850; makefile: 5
file content (247 lines) | stat: -rw-r--r-- 7,505 bytes parent folder | download | duplicates (2)
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
require "spec_helper"

RSpec.describe Aruba::Processes::SpawnProcess do
  subject(:process) do
    described_class.new(command_line, exit_timeout, io_wait, working_directory)
  end

  include_context "uses aruba API"

  let(:command_line) { 'echo "yo"' }
  let(:exit_timeout) { 30 }
  let(:io_wait) { 1 }
  let(:working_directory) { @aruba.expand_path(".") }

  describe "#stdout" do
    before do
      process.start
      process.stop
    end

    context "when invoked once" do
      it { expect(process.stdout.chomp).to eq "yo" }
    end

    context "when invoked twice" do
      it { 2.times { expect(process.stdout.chomp).to eq "yo" } }
    end
  end

  describe "#stderr" do
    let(:command_line) { "sh -c \"echo 'yo' >&2\"" }

    before do
      process.start
      process.stop
    end

    it "returns the output of the process on stderr" do
      expect(process).not_to be_timed_out
      expect(process.stderr.chomp).to eq "yo"
    end

    it "returns the same result when invoked a second time" do
      2.times { expect(process.stderr.chomp).to eq "yo" }
    end
  end

  describe "#stop" do
    before { process.start }

    context "when stopped successfully" do
      it { expect { process.stop }.not_to raise_error }

      it "makes the process stopped" do
        process.stop
        expect(process).to be_stopped
      end
    end
  end

  describe "#start" do
    context "when process run succeeds" do
      it { expect { process.start }.not_to raise_error }

      it "makes the process started" do
        process.start
        expect(process).to be_started
      end
    end

    context "when process run fails" do
      let(:command_line) { "does_not_exists" }

      it { expect { process.start }.to raise_error Aruba::LaunchError }
    end

    context "when on unix" do
      let(:child) { instance_double(ChildProcess::AbstractProcess).as_null_object }
      let(:io) { instance_double(ChildProcess::AbstractIO).as_null_object }
      let(:command_line) { "foo" }
      let(:command) { "foo" }
      let(:command_path) { "/bar/foo" }

      before do
        allow(Aruba.platform).to receive(:command_string)
          .and_return Aruba::Platforms::UnixCommandString
        allow(Aruba.platform)
          .to receive(:which).with(command, anything).and_return(command_path)
        allow(ChildProcess).to receive(:build).and_return(child)

        allow(child).to receive(:io).and_return(io)
        allow(child).to receive(:environment).and_return({})
      end

      context "with a childprocess launch error" do
        before do
          allow(child).to receive(:start).and_raise(ChildProcess::LaunchError, "Foobar!")
        end

        it "reraises LaunchError as Aruba's LaunchError" do
          expect { process.start }
            .to raise_error(Aruba::LaunchError, "It tried to start #{command}. Foobar!")
        end
      end

      context "with a command with a space in the path" do
        let(:command_path) { "/path with space/foo" }

        before do
          allow(Aruba.platform).to receive(:command_string)
            .and_return Aruba::Platforms::UnixCommandString
          allow(Aruba.platform)
            .to receive(:which).with(command, anything).and_return(command_path)
          allow(ChildProcess).to receive(:build).with(command_path).and_return(child)
          allow(child).to receive(:io).and_return io
          allow(child).to receive(:environment).and_return({})
        end

        it "passes the command path as a single string to ChildProcess.build" do
          process.start
          expect(ChildProcess).to have_received(:build).with(command_path)
        end
      end

      context "with a command with arguments" do
        let(:command_line) { 'foo -x "bar baz"' }

        it "passes the command and arguments as separate items to ChildProcess.build" do
          process.start
          expect(ChildProcess).to have_received(:build)
            .with(command_path, "-x", "bar baz")
        end
      end
    end

    context "when on windows" do
      let(:child) { instance_double(ChildProcess::AbstractProcess).as_null_object }
      let(:io) { instance_double(ChildProcess::AbstractIO).as_null_object }
      let(:command_line) { "foo" }
      let(:command) { "foo" }
      let(:cmd_path) { 'C:\Bar\cmd.exe' }
      let(:command_path) { 'D:\Foo\foo' }

      before do
        allow(Aruba.platform).to receive(:command_string)
          .and_return Aruba::Platforms::WindowsCommandString
        allow(Aruba.platform).to receive(:which).with("cmd.exe").and_return(cmd_path)
        allow(Aruba.platform)
          .to receive(:which).with(command, anything).and_return(command_path)
        allow(ChildProcess).to receive(:build).and_return(child)

        allow(child).to receive(:io).and_return(io)
        allow(child).to receive(:environment).and_return({})
      end

      context "with a childprocess launch error" do
        before do
          allow(child).to receive(:start).and_raise(ChildProcess::LaunchError, "Foobar!")
        end

        it "reraises LaunchError as Aruba's LaunchError" do
          expect { process.start }
            .to raise_error(Aruba::LaunchError, "It tried to start #{command}. Foobar!")
        end
      end

      context "with a command without a space in the path" do
        it "passes the command and shell paths as single strings to ChildProcess.build" do
          process.start
          expect(ChildProcess).to have_received(:build).with(cmd_path, "/c", command_path)
        end
      end

      context "with a command with a space in the path" do
        let(:command_path) { 'D:\Bar Baz\foo' }

        it "escapes the spaces using excessive double quotes" do
          process.start
          expect(ChildProcess)
            .to have_received(:build).with(cmd_path, "/c", 'D:\Bar""" """Baz\foo')
        end
      end

      context "with a command with arguments" do
        let(:command_line) { "foo -x 'bar \"baz\"'" }

        it "passes the command and arguments as one string with escaped quotes" do
          process.start
          expect(ChildProcess).to have_received(:build)
            .with(cmd_path, "/c", "#{command_path} -x \"bar \"\"\"baz\"\"\"\"")
        end
      end
    end
  end

  describe "#send_signal" do
    let(:signal) { Gem.win_platform? ? 9 : "KILL" }

    context "with a command that is running" do
      let(:cmd) { "bin/test-cli" }
      let(:command_line) { "bash bin/test-cli" }

      before do
        @aruba.write_file cmd, <<~BASH
          #!/usr/bin/env bash

          sleep 5
          echo "Success"
          exit 0
        BASH
      end

      it "sends the given signal to the command" do
        process.start
        process.send_signal signal
        process.stop
        expect(process).not_to have_output "Success"
      end
    end

    context "with a command that has stopped" do
      it "raises an error" do
        process.start
        process.stop

        expect { process.send_signal signal }
          .to raise_error Aruba::CommandAlreadyStoppedError
      end
    end
  end

  describe "#command" do
    let(:command_line) { "ruby -e 'warn \"yo\"'" }

    it "returns the first item of the command line" do
      expect(process.command).to eq "ruby"
    end
  end

  describe "#arguments" do
    let(:command_line) { "ruby -e 'warn \"yo\"'" }

    it "handles arguments delimited with quotes" do
      expect(process.arguments).to eq ["-e", 'warn "yo"']
    end
  end
end