If starting a process while running from within AppImage adjust the LD_LIBRARY_PATH of the subprocess when the executable exists outside of the AppImage. This prevents issues of invalid dynamic library lookups when the AppImage contains common named libraries.
164 lines
5.2 KiB
Ruby
164 lines
5.2 KiB
Ruby
require File.expand_path("../../../base", __FILE__)
|
|
require "vagrant/util/subprocess"
|
|
|
|
describe Vagrant::Util::Subprocess do
|
|
describe '#execute' do
|
|
before do
|
|
# ensure we have `cat` and `echo` in our PATH so that we can run these
|
|
# tests successfully.
|
|
['cat', 'echo'].each do |cmd|
|
|
if !Vagrant::Util::Which.which(cmd)
|
|
pending("cannot run subprocess tests without command #{cmd.inspect}")
|
|
end
|
|
end
|
|
end
|
|
|
|
let (:cat) { described_class.new('cat', :notify => [:stdin]) }
|
|
|
|
it 'yields the STDIN stream for the process if we set :notify => :stdin' do
|
|
echo = described_class.new('echo', 'hello world', :notify => [:stdin])
|
|
echo.execute do |type, data|
|
|
expect(type).to eq(:stdin)
|
|
expect(data).to be_a(::IO)
|
|
end
|
|
end
|
|
|
|
it 'can close STDIN' do
|
|
result = cat.execute do |type, stdin|
|
|
# We should be able to close STDIN without raising an exception
|
|
stdin.close
|
|
end
|
|
|
|
# we should exit successfully.
|
|
expect(result.exit_code).to eq(0)
|
|
end
|
|
|
|
it 'can write to STDIN correctly' do
|
|
data = "hello world\n"
|
|
result = cat.execute do |type, stdin|
|
|
stdin.write(data)
|
|
stdin.close
|
|
end
|
|
|
|
# we should exit successfully.
|
|
expect(result.exit_code).to eq(0)
|
|
|
|
# we should see our data as the output from `cat`
|
|
expect(result.stdout).to eq(data)
|
|
end
|
|
|
|
context "running within AppImage" do
|
|
let(:appimage_ld_path) { nil }
|
|
let(:exec_path) { "/exec/path" }
|
|
let(:appimage_path) { "/appimage" }
|
|
let(:process) { double("process", io: process_io, environment: process_env) }
|
|
let(:process_io) { double("process_io") }
|
|
let(:process_env) { double("process_env") }
|
|
let(:subject) { described_class.new(exec_path) }
|
|
|
|
before do
|
|
allow(process).to receive(:start)
|
|
allow(process).to receive(:duplex=)
|
|
allow(process).to receive(:alive?).and_return(false)
|
|
allow(process).to receive(:exited?).and_return(true)
|
|
allow(process).to receive(:poll_for_exit).and_return(0)
|
|
allow(process).to receive(:exit_code).and_return(0)
|
|
allow(process_io).to receive(:stdout=)
|
|
allow(process_io).to receive(:stderr=)
|
|
allow(process_io).to receive(:stdin).and_return(double("io_stdin", "sync=" => true))
|
|
allow(process_env).to receive(:[]=)
|
|
allow(ENV).to receive(:[]).with("VAGRANT_INSTALLER_ENV").and_return("1")
|
|
allow(ENV).to receive(:[]).with("VAGRANT_APPIMAGE").and_return("1")
|
|
allow(ENV).to receive(:[]).with("VAGRANT_APPIMAGE_LD_LIBRARY_PATH").and_return(appimage_ld_path)
|
|
allow(File).to receive(:file?).with(exec_path).and_return(true)
|
|
allow(ChildProcess).to receive(:build).and_return(process)
|
|
allow(Vagrant).to receive(:installer_embedded_dir).and_return(appimage_path)
|
|
allow(Vagrant).to receive(:user_data_path).and_return("")
|
|
end
|
|
|
|
after { subject.execute }
|
|
|
|
it "should not update LD_LIBRARY_PATH when environment variable is not set" do
|
|
expect(process_env).not_to receive(:[]=).with("LD_LIBRARY_PATH", anything)
|
|
end
|
|
|
|
context "when APPIMAGE_LD_LIBRARY_PATH environment variable is set" do
|
|
let(:appimage_ld_path) { "APPIMAGE_SYSTEM_LIBS" }
|
|
|
|
it "should set LD_LIBRARY_PATH when executable is not within appimage" do
|
|
expect(process_env).to receive(:[]=).with("LD_LIBRARY_PATH", appimage_ld_path)
|
|
end
|
|
|
|
context "when executable is located within AppImage" do
|
|
let(:exec_path) { "#{appimage_path}/exec/path" }
|
|
|
|
it "should not set LD_LIBRARY_PATH" do
|
|
expect(process_env).not_to receive(:[]=).with("LD_LIBRARY_PATH", anything)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#running?" do
|
|
context "when subprocess has not been started" do
|
|
it "should return false" do
|
|
sp = described_class.new("ls")
|
|
expect(sp.running?).to be(false)
|
|
end
|
|
end
|
|
context "when subprocess has completed" do
|
|
it "should return false" do
|
|
sp = described_class.new("ls")
|
|
sp.execute
|
|
expect(sp.running?).to be(false)
|
|
end
|
|
end
|
|
context "when subprocess is running" do
|
|
it "should return true" do
|
|
sp = described_class.new("sleep", "5")
|
|
thread = Thread.new{ sp.execute }
|
|
sleep(0.3)
|
|
expect(sp.running?).to be(true)
|
|
sp.stop
|
|
thread.join
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#stop" do
|
|
context "when subprocess has not been started" do
|
|
it "should return false" do
|
|
sp = described_class.new("ls")
|
|
expect(sp.stop).to be(false)
|
|
end
|
|
end
|
|
|
|
context "when subprocess has already completed" do
|
|
it "should return false" do
|
|
sp = described_class.new("ls")
|
|
sp.execute
|
|
expect(sp.stop).to be(false)
|
|
end
|
|
end
|
|
|
|
context "when subprocess is running" do
|
|
let(:sp){ described_class.new("sleep", "1") }
|
|
it "should return true" do
|
|
thread = Thread.new{ sp.execute }
|
|
sleep(0.1)
|
|
expect(sp.stop).to be(true)
|
|
thread.join
|
|
end
|
|
|
|
it "should stop the process" do
|
|
thread = Thread.new{ sp.execute }
|
|
sleep(0.1)
|
|
sp.stop
|
|
expect(sp.running?).to be(false)
|
|
thread.join
|
|
end
|
|
end
|
|
end
|
|
end
|