916 lines
29 KiB
Ruby
916 lines
29 KiB
Ruby
# Copyright (c) HashiCorp, Inc.
|
|
# SPDX-License-Identifier: BUSL-1.1
|
|
|
|
require "tmpdir"
|
|
require_relative "../base"
|
|
|
|
require "vagrant/bundler"
|
|
|
|
describe Vagrant::Bundler::SolutionFile do
|
|
let(:plugin_path) { Pathname.new(tmpdir) + "plugin_file" }
|
|
let(:solution_path) { Pathname.new(tmpdir) + "solution_file" }
|
|
let(:tmpdir) { @tmpdir ||= Dir.mktmpdir("vagrant-bundler-test") }
|
|
let(:subject) {
|
|
described_class.new(
|
|
plugin_file: plugin_path,
|
|
solution_file: solution_path
|
|
)
|
|
}
|
|
|
|
after do
|
|
if @tmpdir
|
|
FileUtils.rm_rf(@tmpdir)
|
|
@tmpdir = nil
|
|
end
|
|
end
|
|
|
|
describe "#initialize" do
|
|
context "file paths" do
|
|
context "with solution_file not provided" do
|
|
let(:subject) { described_class.new(plugin_file: plugin_path) }
|
|
|
|
it "should set the plugin_file" do
|
|
expect(subject.plugin_file.to_s).to eq(plugin_path.to_s)
|
|
end
|
|
|
|
it "should set solution path to same directory" do
|
|
expect(subject.solution_file.to_s).to eq(plugin_path.to_s + ".sol")
|
|
end
|
|
end
|
|
|
|
context "with custom solution_file provided" do
|
|
let(:subject) { described_class.
|
|
new(plugin_file: plugin_path, solution_file: solution_path) }
|
|
|
|
it "should set the plugin file path" do
|
|
expect(subject.plugin_file.to_s).to eq(plugin_path.to_s)
|
|
end
|
|
|
|
it "should set the solution file path to given value" do
|
|
expect(subject.solution_file.to_s).to eq(solution_path.to_s)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "initialization behavior" do
|
|
context "on creation" do
|
|
before { expect_any_instance_of(described_class).to receive(:load) }
|
|
|
|
it "should load solution file during initialization" do
|
|
subject
|
|
end
|
|
end
|
|
|
|
it "should be invalid by default" do
|
|
expect(subject.valid?).to be_falsey
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#dependency_list=" do
|
|
it "should accept a list of Gem::Dependency instances" do
|
|
list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
|
|
subject.dependency_list = list
|
|
expect(subject.dependency_list.map(&:dependency)).to eq(list)
|
|
end
|
|
|
|
it "should error if list includes instance not Gem::Dependency" do
|
|
list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) } << :invalid
|
|
expect{ subject.dependency_list = list }.to raise_error(TypeError)
|
|
end
|
|
|
|
it "should convert list into resolver dependency request" do
|
|
list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
|
|
subject.dependency_list = list
|
|
subject.dependency_list.each do |dep|
|
|
expect(dep).to be_a(Gem::Resolver::DependencyRequest)
|
|
end
|
|
end
|
|
|
|
it "should freeze the new dependency list" do
|
|
list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
|
|
subject.dependency_list = list
|
|
expect(subject.dependency_list).to be_frozen
|
|
end
|
|
end
|
|
|
|
describe "#delete!" do
|
|
context "when file does not exist" do
|
|
before { subject.solution_file.delete if subject.solution_file.exist? }
|
|
|
|
it "should return false" do
|
|
expect(subject.delete!).to be_falsey
|
|
end
|
|
|
|
it "should not exist" do
|
|
subject.delete!
|
|
expect(subject.solution_file.exist?).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when file does exist" do
|
|
before { subject.solution_file.write('x') }
|
|
|
|
it "should return true" do
|
|
expect(subject.delete!).to be_truthy
|
|
end
|
|
|
|
it "should not exist" do
|
|
expect(subject.solution_file.exist?).to be_truthy
|
|
subject.delete!
|
|
expect(subject.solution_file.exist?).to be_falsey
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "store!" do
|
|
context "when plugin file does not exist" do
|
|
before { subject.plugin_file.delete if subject.plugin_file.exist? }
|
|
|
|
it "should return false" do
|
|
expect(subject.store!).to be_falsey
|
|
end
|
|
|
|
it "should not create a solution file" do
|
|
subject.store!
|
|
expect(subject.solution_file.exist?).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when plugin file does exist" do
|
|
before { subject.plugin_file.write("x") }
|
|
|
|
it "should return true" do
|
|
expect(subject.store!).to be_truthy
|
|
end
|
|
|
|
it "should create a solution file" do
|
|
expect(subject.solution_file.exist?).to be_falsey
|
|
subject.store!
|
|
expect(subject.solution_file.exist?).to be_truthy
|
|
end
|
|
|
|
context "stored file" do
|
|
let(:content) {
|
|
@content ||= JSON.load(subject.solution_file.read)
|
|
}
|
|
before { subject.store! }
|
|
after { @content = nil }
|
|
|
|
it "should store JSON hash" do
|
|
expect(content).to be_a(Hash)
|
|
end
|
|
|
|
it "should include dependencies key as array value" do
|
|
expect(content["dependencies"]).to be_a(Array)
|
|
end
|
|
|
|
it "should include checksum key as string value" do
|
|
expect(content["checksum"]).to be_a(String)
|
|
end
|
|
|
|
it "should include vagrant_version key as string value" do
|
|
expect(content["vagrant_version"]).to be_a(String)
|
|
end
|
|
|
|
it "should include vagrant_version key that matches current version" do
|
|
expect(content["vagrant_version"]).to eq(Vagrant::VERSION)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "behavior" do
|
|
context "when storing new solution set" do
|
|
let(:deps) { ["dep1", "dep2"].map{ |n| Gem::Dependency.new(n) } }
|
|
|
|
context "when plugin file does not exist" do
|
|
before { subject.solution_file.delete if subject.solution_file.exist? }
|
|
|
|
it "should not create a solution file" do
|
|
subject.dependency_list = deps
|
|
subject.store!
|
|
expect(subject.solution_file.exist?).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when plugin file does exist" do
|
|
before { subject.plugin_file.write("x") }
|
|
|
|
it "should create a solution file" do
|
|
subject.dependency_list = deps
|
|
subject.store!
|
|
expect(subject.solution_file.exist?).to be_truthy
|
|
end
|
|
|
|
it "should update solution file instance to valid" do
|
|
expect(subject.valid?).to be_falsey
|
|
subject.dependency_list = deps
|
|
subject.store!
|
|
expect(subject.valid?).to be_truthy
|
|
end
|
|
|
|
context "when solution file does exist" do
|
|
before do
|
|
subject.dependency_list = deps
|
|
subject.store!
|
|
end
|
|
|
|
it "should be a valid solution" do
|
|
subject = described_class.new(
|
|
plugin_file: plugin_path,
|
|
solution_file: solution_path
|
|
)
|
|
expect(subject.valid?).to be_truthy
|
|
end
|
|
|
|
it "should have expected dependency list" do
|
|
subject = described_class.new(
|
|
plugin_file: plugin_path,
|
|
solution_file: solution_path
|
|
)
|
|
expect(subject.dependency_list).to eq(deps)
|
|
end
|
|
|
|
context "when plugin file has been changed" do
|
|
before { subject.plugin_file.write("xy") }
|
|
|
|
it "should not be a valid solution" do
|
|
subject = described_class.new(
|
|
plugin_file: plugin_path,
|
|
solution_file: solution_path
|
|
)
|
|
expect(subject.valid?).to be_falsey
|
|
end
|
|
|
|
it "should have empty dependency list" do
|
|
subject = described_class.new(
|
|
plugin_file: plugin_path,
|
|
solution_file: solution_path
|
|
)
|
|
expect(subject.dependency_list).to be_empty
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#load" do
|
|
let(:plugin_file_exists) { false }
|
|
let(:solution_file_exists) { false }
|
|
let(:plugin_file_path) { "PLUGIN_FILE_PATH" }
|
|
let(:solution_file_path) { "SOLUTION_FILE_PATH" }
|
|
let(:plugin_file) { double("plugin-file") }
|
|
let(:solution_file) { double("solution-file") }
|
|
|
|
subject do
|
|
described_class.new(plugin_file: plugin_file_path, solution_file: solution_file_path)
|
|
end
|
|
|
|
before do
|
|
allow(Pathname).to receive(:new).with(plugin_file_path).and_return(plugin_file)
|
|
allow(Pathname).to receive(:new).with(solution_file_path).and_return(solution_file)
|
|
allow(plugin_file).to receive(:exist?).and_return(plugin_file_exists)
|
|
allow(solution_file).to receive(:exist?).and_return(solution_file_exists)
|
|
end
|
|
|
|
context "when plugin file and solution file do not exist" do
|
|
it "should not attempt to read the solution" do
|
|
expect_any_instance_of(described_class).not_to receive(:read_solution)
|
|
subject
|
|
end
|
|
end
|
|
|
|
context "when plugin file exists and solution file does not" do
|
|
let(:plugin_file_exists) { true }
|
|
|
|
it "should not attempt to read the solution" do
|
|
expect_any_instance_of(described_class).not_to receive(:read_solution)
|
|
subject
|
|
end
|
|
end
|
|
|
|
context "when solution file exists and plugin file does not" do
|
|
let(:solution_file_exists) { true }
|
|
|
|
it "should not attempt to read the solution" do
|
|
expect_any_instance_of(described_class).not_to receive(:read_solution)
|
|
subject
|
|
end
|
|
end
|
|
|
|
context "when solution file and plugin file exist" do
|
|
let(:plugin_file_exists) { true }
|
|
let(:solution_file_exists) { true }
|
|
|
|
let(:solution_file_contents) { "" }
|
|
|
|
before do
|
|
allow(solution_file).to receive(:read).and_return(solution_file_contents)
|
|
allow_any_instance_of(described_class).to receive(:plugin_file_checksum).and_return("VALID")
|
|
end
|
|
|
|
context "when solution file is empty" do
|
|
it "should return false" do
|
|
expect(subject.send(:load)).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when solution file contains invalid checksum" do
|
|
let(:solution_file_contents) { {checksum: "INVALID", vagrant_version: Vagrant::VERSION}.to_json }
|
|
|
|
it "should return false" do
|
|
expect(subject.send(:load)).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when solution file contains different Vagrant version" do
|
|
let(:solution_file_contents) { {checksum: "VALID", vagrant_version: "0.1"}.to_json }
|
|
|
|
it "should return false" do
|
|
expect(subject.send(:load)).to be_falsey
|
|
end
|
|
end
|
|
|
|
context "when solution file contains valid Vagrant version and valid checksum" do
|
|
let(:solution_file_contents) {
|
|
{checksum: "VALID", vagrant_version: Vagrant::VERSION, dependencies: file_dependencies}.to_json
|
|
}
|
|
let(:file_dependencies) { dependency_list.map{|d| [d.name, d.requirements_list]} }
|
|
let(:dependency_list) { [] }
|
|
|
|
it "should return true" do
|
|
expect(subject.send(:load)).to be_truthy
|
|
end
|
|
|
|
it "should be valid" do
|
|
expect(subject).to be_valid
|
|
end
|
|
|
|
context "when solution file contains dependency list" do
|
|
let(:dependency_list) { [
|
|
Gem::Dependency.new("dep1", "> 0"),
|
|
Gem::Dependency.new("dep2", "< 3")
|
|
] }
|
|
|
|
it "should be valid" do
|
|
expect(subject).to be_valid
|
|
end
|
|
|
|
it "should convert list into dependency requests" do
|
|
subject.dependency_list.each do |d|
|
|
expect(d).to be_a(Gem::Resolver::DependencyRequest)
|
|
end
|
|
end
|
|
|
|
it "should include defined dependencies" do
|
|
expect(subject.dependency_list.first).to eq(dependency_list.first)
|
|
expect(subject.dependency_list.last).to eq(dependency_list.last)
|
|
end
|
|
|
|
it "should freeze the dependency list" do
|
|
expect(subject.dependency_list).to be_frozen
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#read_solution" do
|
|
let(:solution_file_contents) { "" }
|
|
let(:plugin_file_path) { "PLUGIN_FILE_PATH" }
|
|
let(:solution_file_path) { "SOLUTION_FILE_PATH" }
|
|
let(:plugin_file) { double("plugin-file") }
|
|
let(:solution_file) { double("solution-file") }
|
|
|
|
subject do
|
|
described_class.new(plugin_file: plugin_file_path, solution_file: solution_file_path)
|
|
end
|
|
|
|
before do
|
|
allow(Pathname).to receive(:new).with(plugin_file_path).and_return(plugin_file)
|
|
allow(Pathname).to receive(:new).with(solution_file_path).and_return(solution_file)
|
|
allow(plugin_file).to receive(:exist?).and_return(false)
|
|
allow(solution_file).to receive(:exist?).and_return(false)
|
|
allow(solution_file).to receive(:read).and_return(solution_file_contents)
|
|
end
|
|
|
|
it "should return nil when file contents are empty" do
|
|
expect(subject.send(:read_solution)).to be_nil
|
|
end
|
|
|
|
context "when file contents are hash" do
|
|
let(:solution_file_contents) { {checksum: "VALID"}.to_json }
|
|
|
|
it "should return a hash" do
|
|
expect(subject.send(:read_solution)).to be_a(Hash)
|
|
end
|
|
|
|
it "should return a hash with indifferent access" do
|
|
expect(subject.send(:read_solution)).to be_a(Vagrant::Util::HashWithIndifferentAccess)
|
|
end
|
|
end
|
|
|
|
context "when file contents are array" do
|
|
let(:solution_file_contents) { ["test"].to_json }
|
|
|
|
it "should return a hash" do
|
|
expect(subject.send(:read_solution)).to be_a(Hash)
|
|
end
|
|
|
|
it "should return a hash with indifferent access" do
|
|
expect(subject.send(:read_solution)).to be_a(Vagrant::Util::HashWithIndifferentAccess)
|
|
end
|
|
end
|
|
|
|
context "when file contents are null" do
|
|
let(:solution_file_contents) { "null" }
|
|
|
|
it "should return nil" do
|
|
expect(subject.send(:read_solution)).to be_nil
|
|
end
|
|
end
|
|
|
|
context "when file contents are invalid" do
|
|
let(:solution_file_contents) { "{2dfwef" }
|
|
|
|
it "should return nil" do
|
|
expect(subject.send(:read_solution)).to be_nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe Vagrant::Bundler do
|
|
include_context "unit"
|
|
|
|
let(:iso_env) { isolated_environment }
|
|
let(:env) { iso_env.create_vagrant_env }
|
|
let(:tmpdir) { @v_tmpdir ||= Pathname.new(Dir.mktmpdir("vagrant-bundler-test")) }
|
|
|
|
before do
|
|
@tmpdir = Dir.mktmpdir("vagrant-bundler-test")
|
|
@vh = ENV["VAGRANT_HOME"]
|
|
ENV["VAGRANT_HOME"] = @tmpdir
|
|
end
|
|
|
|
after do
|
|
ENV["VAGRANT_HOME"] = @vh
|
|
FileUtils.rm_rf(@tmpdir)
|
|
FileUtils.rm_rf(@v_tmpdir) if @v_tmpdir
|
|
end
|
|
|
|
it "should isolate gem path based on Ruby version" do
|
|
expect(subject.plugin_gem_path.to_s).to end_with(RUBY_VERSION)
|
|
end
|
|
|
|
it "should not have an env_plugin_gem_path by default" do
|
|
expect(subject.env_plugin_gem_path).to be_nil
|
|
end
|
|
|
|
describe "#initialize" do
|
|
it "should automatically set the plugin gem path" do
|
|
expect(subject.plugin_gem_path).not_to be_nil
|
|
end
|
|
|
|
it "should add current ruby version to plugin gem path suffix" do
|
|
expect(subject.plugin_gem_path.to_s).to end_with(RUBY_VERSION)
|
|
end
|
|
|
|
it "should freeze the plugin gem path" do
|
|
expect(subject.plugin_gem_path).to be_frozen
|
|
end
|
|
end
|
|
|
|
describe "#environment_path=" do
|
|
it "should error if not given Pathname" do
|
|
expect { subject.environment_path = :value }.
|
|
to raise_error(TypeError)
|
|
end
|
|
|
|
context "when set with Pathname" do
|
|
let(:env_path) { Pathname.new("/dev/null") }
|
|
before { subject.environment_path = env_path }
|
|
|
|
it "should set the environment_data_path" do
|
|
expect(subject.environment_data_path).to eq(env_path)
|
|
end
|
|
|
|
it "should set the env_plugin_gem_path" do
|
|
expect(subject.env_plugin_gem_path).not_to be_nil
|
|
end
|
|
|
|
it "should suffix current ruby version to env_plugin_gem_path" do
|
|
expect(subject.env_plugin_gem_path.to_s).to end_with(RUBY_VERSION)
|
|
end
|
|
|
|
it "should base env_plugin_gem_path on environment_path value" do
|
|
expect(subject.env_plugin_gem_path.to_s).to start_with(env_path.to_s)
|
|
end
|
|
|
|
it "should freeze the env_plugin_gem_path" do
|
|
expect(subject.env_plugin_gem_path).to be_frozen
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#load_solution_file" do
|
|
let(:local_opt) { nil }
|
|
let(:global_opt) { nil }
|
|
let(:options) { {local: local_opt, global: global_opt} }
|
|
|
|
it "should return nil when local and global options are blank" do
|
|
expect(subject.load_solution_file(options)).to be_nil
|
|
end
|
|
|
|
context "when environment data path is set" do
|
|
let(:env_path) { "/dev/null" }
|
|
before { subject.environment_path = Pathname.new(env_path) }
|
|
|
|
context "when local option is set" do
|
|
let(:local_opt) { tmpdir + "local" }
|
|
|
|
it "should return a SolutionFile instance" do
|
|
expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
|
|
end
|
|
|
|
it "should be located in the environment data path" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to start_with(env_path)
|
|
end
|
|
|
|
it "should have a local.sol solution file" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to end_with("local.sol")
|
|
end
|
|
|
|
it "should have plugin file set to local value" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.plugin_file.to_s).to eq(local_opt.to_s)
|
|
end
|
|
end
|
|
|
|
context "when global option is set" do
|
|
let(:global_opt) { tmpdir + "global" }
|
|
|
|
it "should return a SolutionFile instance" do
|
|
expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
|
|
end
|
|
|
|
it "should be located in the environment data path" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to start_with(env_path)
|
|
end
|
|
|
|
it "should have a global.sol solution file" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to end_with("global.sol")
|
|
end
|
|
|
|
it "should have plugin file set to global value" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.plugin_file.to_s).to eq(global_opt.to_s)
|
|
end
|
|
end
|
|
|
|
context "when local and global option is set" do
|
|
let(:global_opt) { tmpdir + "global" }
|
|
let(:local_opt) { tmpdir + "local" }
|
|
|
|
it "should return nil" do
|
|
expect(subject.load_solution_file(options)).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when environment data path is unset" do
|
|
context "when local option is set" do
|
|
let(:local_opt) { tmpdir + "local" }
|
|
|
|
it "should return nil" do
|
|
expect(subject.load_solution_file(options)).to be_nil
|
|
end
|
|
end
|
|
|
|
context "when global option is set" do
|
|
let(:global_opt) { tmpdir + "global" }
|
|
|
|
it "should return a SolutionFile instance" do
|
|
expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
|
|
end
|
|
|
|
it "should be located in the vagrant user data path" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to start_with(Vagrant.user_data_path.to_s)
|
|
end
|
|
|
|
it "should have a global.sol solution file" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.solution_file.to_s).to end_with("global.sol")
|
|
end
|
|
|
|
it "should have plugin file set to global value" do
|
|
file = subject.load_solution_file(options)
|
|
expect(file.plugin_file.to_s).to eq(global_opt.to_s)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#deinit" do
|
|
it "should provide method for backwards compatibility" do
|
|
subject.deinit
|
|
end
|
|
end
|
|
|
|
describe "DEFAULT_GEM_SOURCES" do
|
|
it "should list hashicorp gemstore first" do
|
|
expect(described_class.const_get(:DEFAULT_GEM_SOURCES).first).to eq(
|
|
described_class.const_get(:HASHICORP_GEMSTORE))
|
|
end
|
|
end
|
|
|
|
describe "#init!" do
|
|
context "Gem.sources" do
|
|
before {
|
|
Gem.sources.clear
|
|
Gem.sources << "https://rubygems.org/" }
|
|
|
|
it "should add hashicorp gem store" do
|
|
subject.init!([])
|
|
expect(Gem.sources).to include(described_class.const_get(:HASHICORP_GEMSTORE))
|
|
end
|
|
|
|
it "should add hashicorp gem store to start of sources list" do
|
|
subject.init!([])
|
|
expect(Gem.sources.sources.first.uri.to_s).to eq(described_class.const_get(:HASHICORP_GEMSTORE))
|
|
end
|
|
end
|
|
|
|
context "multiple specs" do
|
|
let(:solution_file) { double('solution_file') }
|
|
let(:vagrant_set) { double('vagrant_set') }
|
|
|
|
before do
|
|
allow(subject).to receive(:load_solution_file).and_return(solution_file)
|
|
allow(subject).to receive(:generate_vagrant_set).and_return(vagrant_set)
|
|
allow(solution_file).to receive(:valid?).and_return(true)
|
|
end
|
|
|
|
it "should activate spec of deps already loaded" do
|
|
spec = Gem.loaded_specs.first
|
|
deps = [spec[0]]
|
|
specs = [spec[1].dup, spec[1].dup]
|
|
specs[0].version = Gem::Version::new('0.0.1')
|
|
# make sure haven't accidentally modified both
|
|
expect(specs[0].version).to_not eq(specs[1].version)
|
|
|
|
expect(solution_file).to receive(:dependency_list).and_return(deps)
|
|
expect(vagrant_set).to receive(:find_all).and_return(specs)
|
|
expect(subject).to receive(:activate_solution) do |activate_specs|
|
|
expect(activate_specs.length()).to eq(1)
|
|
expect(activate_specs[0].full_spec()).to eq(specs[1])
|
|
end
|
|
subject.init!([])
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#install" do
|
|
let(:plugins){ {"my-plugin" => {"gem_version" => "> 0"}} }
|
|
|
|
it "should pass plugin information hash to internal install" do
|
|
expect(subject).to receive(:internal_install).with(plugins, any_args)
|
|
subject.install(plugins)
|
|
end
|
|
|
|
it "should not include any update plugins" do
|
|
expect(subject).to receive(:internal_install).with(anything, nil, any_args)
|
|
subject.install(plugins)
|
|
end
|
|
|
|
it "should flag local when local is true" do
|
|
expect(subject).to receive(:internal_install).with(any_args, env_local: true)
|
|
subject.install(plugins, true)
|
|
end
|
|
|
|
it "should not flag local when local is not set" do
|
|
expect(subject).to receive(:internal_install).with(any_args, env_local: false)
|
|
subject.install(plugins)
|
|
end
|
|
end
|
|
|
|
describe "#install_local" do
|
|
let(:plugin_source){ double("plugin_source", spec: plugin_spec) }
|
|
let(:plugin_spec){ double("plugin_spec", name: plugin_name, version: plugin_version) }
|
|
let(:plugin_name){ "PLUGIN_NAME" }
|
|
let(:plugin_version){ "1.0.0" }
|
|
let(:plugin_path){ "PLUGIN_PATH" }
|
|
let(:sources){ "SOURCES" }
|
|
|
|
before do
|
|
allow(Gem::Source::SpecificFile).to receive(:new).and_return(plugin_source)
|
|
allow(subject).to receive(:internal_install)
|
|
end
|
|
|
|
it "should return plugin gem specification" do
|
|
expect(subject.install_local(plugin_path)).to eq(plugin_spec)
|
|
end
|
|
|
|
it "should set custom sources" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(info[plugin_name]["sources"]).to eq(sources)
|
|
end
|
|
subject.install_local(plugin_path, sources: sources)
|
|
end
|
|
|
|
it "should not set the update parameter" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(update).to be_nil
|
|
end
|
|
subject.install_local(plugin_path)
|
|
end
|
|
|
|
it "should not set plugin as environment local by default" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(opts[:env_local]).to be_falsey
|
|
end
|
|
subject.install_local(plugin_path)
|
|
end
|
|
|
|
it "should set if plugin is environment local" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(opts[:env_local]).to be_truthy
|
|
end
|
|
subject.install_local(plugin_path, env_local: true)
|
|
end
|
|
end
|
|
|
|
describe "#update" do
|
|
let(:plugins){ :plugins }
|
|
let(:specific){ [] }
|
|
|
|
after{ subject.update(plugins, specific) }
|
|
|
|
it "should mark update as true" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(update).to be_truthy
|
|
end
|
|
end
|
|
|
|
context "with specific plugins named" do
|
|
let(:specific){ ["PLUGIN_NAME"] }
|
|
|
|
it "should set update to specific names" do
|
|
expect(subject).to receive(:internal_install) do |info, update, opts|
|
|
expect(update[:gems]).to eq(specific)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#vagrant_internal_specs" do
|
|
let(:vagrant_spec) { double("vagrant_spec", name: "vagrant", version: Gem::Version.new(Vagrant::VERSION),
|
|
activated?: vagrant_spec_activated, activate: nil, runtime_dependencies: vagrant_dep_specs) }
|
|
let(:spec_list) { [] }
|
|
let(:spec_dirs) { [] }
|
|
let(:spec_default_dir) { "/dev/null" }
|
|
let(:dir_spec_list) { [] }
|
|
let(:vagrant_spec_activated) { true }
|
|
let(:vagrant_dep_specs) { [] }
|
|
|
|
before do
|
|
allow(Gem::Specification).to receive(:find) { |&b| vagrant_spec if b.call(vagrant_spec) }
|
|
allow(Gem::Specification).to receive(:find_all).and_return(spec_list)
|
|
allow(Gem::Specification).to receive(:dirs).and_return(spec_dirs)
|
|
allow(Gem::Specification).to receive(:default_specifications_dir).and_return(spec_default_dir)
|
|
allow(Gem::Specification).to receive(:each_spec).and_return(dir_spec_list)
|
|
end
|
|
|
|
it "should return an empty list" do
|
|
expect(subject.send(:vagrant_internal_specs)).to eq([])
|
|
end
|
|
|
|
context "when vagrant specification is not activated" do
|
|
let(:vagrant_spec_activated) { false }
|
|
|
|
it "should activate the specification" do
|
|
expect(vagrant_spec).to receive(:activate)
|
|
subject.send(:vagrant_internal_specs)
|
|
end
|
|
end
|
|
|
|
context "when vagrant specification is not found" do
|
|
before { allow(Gem::Specification).to receive(:find).and_return(nil) }
|
|
|
|
it "should raise not found error" do
|
|
expect { subject.send(:vagrant_internal_specs) }.to raise_error(Vagrant::Errors::SourceSpecNotFound)
|
|
end
|
|
end
|
|
|
|
context "when bundler is not defined" do
|
|
before { expect(Vagrant).to receive(:in_bundler?).and_return(false) }
|
|
|
|
context "when running inside the installer" do
|
|
before { expect(Vagrant).to receive(:in_installer?).and_return(true) }
|
|
|
|
it "should load gem specification directories" do
|
|
expect(Gem::Specification).to receive(:dirs).and_return(spec_dirs)
|
|
subject.send(:vagrant_internal_specs)
|
|
end
|
|
|
|
context "when checking paths" do
|
|
let(:spec_dirs) { [double("spec-dir", start_with?: in_user_dir)] }
|
|
let(:in_user_dir) { true }
|
|
let(:user_dir) { double("user-dir") }
|
|
|
|
before { allow(Gem).to receive(:user_dir).and_return(user_dir) }
|
|
|
|
it "should check if path is within local user directory" do
|
|
expect(spec_dirs.first).to receive(:start_with?).with(user_dir).and_return(false)
|
|
subject.send(:vagrant_internal_specs)
|
|
end
|
|
|
|
context "when path is not within user directory" do
|
|
let(:in_user_dir) { false }
|
|
|
|
it "should use path when loading specs" do
|
|
expect(Gem::Specification).to receive(:each_spec) { |arg| expect(arg).to include(spec_dirs.first) }
|
|
subject.send(:vagrant_internal_specs)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when running outside the installer" do
|
|
before { expect(Vagrant).to receive(:in_installer?).and_return(false) }
|
|
|
|
it "should not load gem specification directories" do
|
|
expect(Gem::Specification).not_to receive(:dirs)
|
|
subject.send(:vagrant_internal_specs)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe Vagrant::Bundler::PluginSet do
|
|
let(:name) { "test-gem" }
|
|
let(:version) { "1.0.0" }
|
|
let(:directory) { @directory ||= Dir.mktmpdir("vagrant-bundler-test") }
|
|
|
|
after do
|
|
FileUtils.rm_rf(@directory) if @directory
|
|
@directory = nil
|
|
end
|
|
|
|
describe "#add_vendor_gem" do
|
|
context "when spec file does not exist" do
|
|
it "should raise a not found error" do
|
|
expect { subject.add_vendor_gem(name, directory) }.to raise_error(Gem::GemNotFoundException)
|
|
end
|
|
end
|
|
|
|
context "when spec file exists" do
|
|
before do
|
|
spec = Gem::Specification.new(name, version)
|
|
File.write(File.join(directory, "#{name}.gemspec"), spec.to_ruby)
|
|
end
|
|
|
|
it "should load the specification" do
|
|
expect(subject.add_vendor_gem(name, directory)).to be_a(Gem::Specification)
|
|
end
|
|
|
|
it "should set the full path in specification" do
|
|
spec = subject.add_vendor_gem(name, directory)
|
|
expect(spec.full_gem_path).to eq(directory)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "#find_all" do
|
|
let(:request) { Gem::Resolver::DependencyRequest.new(dependency, nil) }
|
|
let(:dependency) { Gem::Dependency.new("test-gem", requirement) }
|
|
let(:requirement) { Gem::Requirement.new(version) }
|
|
|
|
context "when specification is not included in set" do
|
|
it "should return empty array" do
|
|
expect(subject.find_all(request)).to eq([])
|
|
end
|
|
end
|
|
|
|
context "when specification is included in set" do
|
|
before do
|
|
spec = Gem::Specification.new(name, version)
|
|
File.write(File.join(directory, "#{name}.gemspec"), spec.to_ruby)
|
|
subject.add_vendor_gem(name, directory)
|
|
end
|
|
|
|
it "should return a vendor specification instance" do
|
|
expect(subject.find_all(request).first).to be_a(Gem::Resolver::VendorSpecification)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|