When computing the solution set, if a gem is already loaded, make sure to use the specification of the loaded one instead of the first available as otherwise there is a risk that when multiple matches are available the specification for the wrong version may be picked. When this happens an error message will be triggered that looks like can't activate json-2.3.0, already activated json-2.5.1 This can occur for distribution packaged vagrants as well as installs for development purposes where the ruby install may contain a default gem spec of an older version than is needed. Fixes: #12521 Fixes: vagrant-libvirt/vagrant-libvirt#1390
913 lines
29 KiB
Ruby
913 lines
29 KiB
Ruby
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
|