The local-exec push strategy was assuming it was running from a CLI and so it wouldn't be a big deal for it to straight up `exec` and replace its running with the user command. That command will just do its thing and we want the exit code for the CLI command to match anyways, right? Sure that works for a shell, but in a GRPC server setting it's decidedly Not Cool to suddenly swap out the running process! As you can imagine - the effect of doing this was all sorts of broken pipes and unexpected EOFs and a very confused @phinze. Luckily we had a subprocess strategy sitting right there for Windows compat, so it was just a matter of switching to that in the server context as well. Long and winding debugging process; simple fix; just another classic!
134 lines
3.9 KiB
Ruby
134 lines
3.9 KiB
Ruby
require_relative "../../../base"
|
|
|
|
require Vagrant.source_root.join("plugins/pushes/local-exec/push")
|
|
|
|
describe VagrantPlugins::LocalExecPush::Push do
|
|
include_context "unit"
|
|
|
|
before(:all) do
|
|
I18n.load_path << Vagrant.source_root.join("plugins/pushes/local-exec/locales/en.yml")
|
|
I18n.reload!
|
|
end
|
|
|
|
let(:env) { isolated_environment }
|
|
let(:config) do
|
|
double("config",
|
|
script: nil,
|
|
inline: nil,
|
|
args: "some args",
|
|
)
|
|
end
|
|
|
|
subject { described_class.new(env, config) }
|
|
|
|
before do
|
|
allow(env).to receive(:root_path)
|
|
.and_return(File.expand_path("..", __FILE__))
|
|
end
|
|
|
|
describe "#push" do
|
|
before do
|
|
allow(subject).to receive(:execute_inline!)
|
|
allow(subject).to receive(:execute_script!)
|
|
allow(subject).to receive(:execute!)
|
|
end
|
|
|
|
context "when inline is given" do
|
|
before { allow(config).to receive(:inline).and_return("echo") }
|
|
|
|
it "executes the inline script" do
|
|
expect(subject).to receive(:execute_inline!)
|
|
.with(config.inline, config.args)
|
|
subject.push
|
|
end
|
|
end
|
|
|
|
context "when script is given" do
|
|
before { allow(config).to receive(:script).and_return("foo.sh") }
|
|
|
|
it "executes the script" do
|
|
expect(subject).to receive(:execute_script!)
|
|
.with(config.script, config.args)
|
|
subject.push
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#execute_inline!" do
|
|
before { allow(subject).to receive(:execute_script!) }
|
|
|
|
it "writes the script to a tempfile" do
|
|
expect(Tempfile).to receive(:new).and_call_original
|
|
subject.execute_inline!("echo", config.args)
|
|
end
|
|
|
|
it "executes the script" do
|
|
expect(subject).to receive(:execute_script!)
|
|
subject.execute_inline!("echo", config.args)
|
|
end
|
|
end
|
|
|
|
describe "#execute_script!" do
|
|
before do
|
|
allow(subject).to receive(:execute!)
|
|
allow(FileUtils).to receive(:chmod)
|
|
end
|
|
|
|
it "expands the path relative to the machine root" do
|
|
expect(subject).to receive(:execute!)
|
|
.with(File.expand_path("foo.sh", env.root_path))
|
|
subject.execute_script!("./foo.sh", nil)
|
|
end
|
|
|
|
it "makes the file executable" do
|
|
expect(FileUtils).to receive(:chmod)
|
|
.with("+x", File.expand_path("foo.sh", env.root_path))
|
|
subject.execute_script!("./foo.sh", config.args)
|
|
end
|
|
|
|
it "calls execute!" do
|
|
expect(subject).to receive(:execute!)
|
|
.with(File.expand_path("foo.sh", env.root_path))
|
|
subject.execute_script!("./foo.sh", nil)
|
|
end
|
|
|
|
context "when args is given" do
|
|
it "passes string args to execute!" do
|
|
expect(subject).to receive(:execute!)
|
|
.with(File.expand_path("foo.sh", env.root_path) + " " + config.args)
|
|
subject.execute_script!("./foo.sh", config.args)
|
|
end
|
|
|
|
it "passes array args as string to execute!" do
|
|
expect(subject).to receive(:execute!)
|
|
.with(File.expand_path("foo.sh", env.root_path) + " \"one\" \"two\" \"three\"")
|
|
subject.execute_script!("./foo.sh", ["one", "two", "three"])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#execute!" do
|
|
it "uses exec on unix" do
|
|
allow(Vagrant::Util::Platform).to receive(:windows?).and_return(false)
|
|
expect(Vagrant::Util::SafeExec).to receive(:exec)
|
|
expect { subject.execute! }.to_not raise_error
|
|
end
|
|
|
|
it "uses subprocess on windows" do
|
|
allow(Vagrant::Util::Platform).to receive(:windows?).and_return(true)
|
|
result = double("result", exit_code: 0)
|
|
expect(Vagrant::Util::Subprocess).to receive(:execute).and_return(result)
|
|
expect { subject.execute! }.to raise_error { |e|
|
|
expect(e).to be_a(SystemExit)
|
|
}
|
|
end
|
|
|
|
it "uses subprocess when running in server mode, and does not exit" do
|
|
allow(Vagrant).to receive(:server_mode?).and_return(true)
|
|
result = double("result", exit_code: 0)
|
|
expect(Vagrant::Util::Subprocess).to receive(:execute).and_return(result)
|
|
expect { subject.execute! }.to_not raise_error
|
|
end
|
|
end
|
|
end
|