"Fossies" - the Fresh Open Source Software Archive

Member "vagrant-2.2.14/test/unit/vagrant/bundler_test.rb" (20 Nov 2020, 28478 Bytes) of package /linux/misc/vagrant-2.2.14.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "bundler_test.rb": 2.2.13_vs_2.2.14.

    1 require "tmpdir"
    2 require_relative "../base"
    3 
    4 require "vagrant/bundler"
    5 
    6 describe Vagrant::Bundler::SolutionFile do
    7   let(:plugin_path) { Pathname.new(tmpdir) + "plugin_file" }
    8   let(:solution_path) { Pathname.new(tmpdir) + "solution_file" }
    9   let(:tmpdir) { @tmpdir ||= Dir.mktmpdir("vagrant-bundler-test") }
   10   let(:subject) {
   11     described_class.new(
   12       plugin_file: plugin_path,
   13       solution_file: solution_path
   14     )
   15   }
   16 
   17   after do
   18     if @tmpdir
   19       FileUtils.rm_rf(@tmpdir)
   20       @tmpdir = nil
   21     end
   22   end
   23 
   24   describe "#initialize" do
   25     context "file paths" do
   26       context "with solution_file not provided" do
   27         let(:subject) { described_class.new(plugin_file: plugin_path) }
   28 
   29         it "should set the plugin_file" do
   30           expect(subject.plugin_file.to_s).to eq(plugin_path.to_s)
   31         end
   32 
   33         it "should set solution path to same directory" do
   34           expect(subject.solution_file.to_s).to eq(plugin_path.to_s + ".sol")
   35         end
   36       end
   37 
   38       context "with custom solution_file provided" do
   39         let(:subject) { described_class.
   40             new(plugin_file: plugin_path, solution_file: solution_path) }
   41 
   42         it "should set the plugin file path" do
   43           expect(subject.plugin_file.to_s).to eq(plugin_path.to_s)
   44         end
   45 
   46         it "should set the solution file path to given value" do
   47           expect(subject.solution_file.to_s).to eq(solution_path.to_s)
   48         end
   49       end
   50     end
   51 
   52     context "initialization behavior" do
   53       context "on creation" do
   54         before { expect_any_instance_of(described_class).to receive(:load) }
   55 
   56         it "should load solution file during initialization" do
   57           subject
   58         end
   59       end
   60 
   61       it "should be invalid by default" do
   62         expect(subject.valid?).to be_falsey
   63       end
   64     end
   65   end
   66 
   67   describe "#dependency_list=" do
   68     it "should accept a list of Gem::Dependency instances" do
   69       list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
   70       subject.dependency_list = list
   71       expect(subject.dependency_list.map(&:dependency)).to eq(list)
   72     end
   73 
   74     it "should error if list includes instance not Gem::Dependency" do
   75       list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) } << :invalid
   76       expect{ subject.dependency_list = list }.to raise_error(TypeError)
   77     end
   78 
   79     it "should convert list into resolver dependency request" do
   80       list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
   81       subject.dependency_list = list
   82       subject.dependency_list.each do |dep|
   83         expect(dep).to be_a(Gem::Resolver::DependencyRequest)
   84       end
   85     end
   86 
   87     it "should freeze the new dependency list" do
   88       list = ["dep1", "dep2"].map{ |x| Gem::Dependency.new(x) }
   89       subject.dependency_list = list
   90       expect(subject.dependency_list).to be_frozen
   91     end
   92   end
   93 
   94   describe "#delete!" do
   95     context "when file does not exist" do
   96       before { subject.solution_file.delete if subject.solution_file.exist? }
   97 
   98       it "should return false" do
   99         expect(subject.delete!).to be_falsey
  100       end
  101 
  102       it "should not exist" do
  103         subject.delete!
  104         expect(subject.solution_file.exist?).to be_falsey
  105       end
  106     end
  107 
  108     context "when file does exist" do
  109       before { subject.solution_file.write('x') }
  110 
  111       it "should return true" do
  112         expect(subject.delete!).to be_truthy
  113       end
  114 
  115       it "should not exist" do
  116         expect(subject.solution_file.exist?).to be_truthy
  117         subject.delete!
  118         expect(subject.solution_file.exist?).to be_falsey
  119       end
  120     end
  121   end
  122 
  123   describe "store!" do
  124     context "when plugin file does not exist" do
  125       before { subject.plugin_file.delete if subject.plugin_file.exist? }
  126 
  127       it "should return false" do
  128         expect(subject.store!).to be_falsey
  129       end
  130 
  131       it "should not create a solution file" do
  132         subject.store!
  133         expect(subject.solution_file.exist?).to be_falsey
  134       end
  135     end
  136 
  137     context "when plugin file does exist" do
  138       before { subject.plugin_file.write("x") }
  139 
  140       it "should return true" do
  141         expect(subject.store!).to be_truthy
  142       end
  143 
  144       it "should create a solution file" do
  145         expect(subject.solution_file.exist?).to be_falsey
  146         subject.store!
  147         expect(subject.solution_file.exist?).to be_truthy
  148       end
  149 
  150       context "stored file" do
  151         let(:content) {
  152           @content ||= JSON.load(subject.solution_file.read)
  153         }
  154         before { subject.store! }
  155         after { @content = nil }
  156 
  157         it "should store JSON hash" do
  158           expect(content).to be_a(Hash)
  159         end
  160 
  161         it "should include dependencies key as array value" do
  162           expect(content["dependencies"]).to be_a(Array)
  163         end
  164 
  165         it "should include checksum key as string value" do
  166           expect(content["checksum"]).to be_a(String)
  167         end
  168 
  169         it "should include vagrant_version key as string value" do
  170           expect(content["vagrant_version"]).to be_a(String)
  171         end
  172 
  173         it "should include vagrant_version key that matches current version" do
  174           expect(content["vagrant_version"]).to eq(Vagrant::VERSION)
  175         end
  176       end
  177     end
  178   end
  179 
  180   describe "behavior" do
  181     context "when storing new solution set" do
  182       let(:deps) { ["dep1", "dep2"].map{ |n| Gem::Dependency.new(n) } }
  183 
  184       context "when plugin file does not exist" do
  185         before { subject.solution_file.delete if subject.solution_file.exist? }
  186 
  187         it "should not create a solution file" do
  188           subject.dependency_list = deps
  189           subject.store!
  190           expect(subject.solution_file.exist?).to be_falsey
  191         end
  192       end
  193 
  194       context "when plugin file does exist" do
  195         before { subject.plugin_file.write("x") }
  196 
  197         it "should create a solution file" do
  198           subject.dependency_list = deps
  199           subject.store!
  200           expect(subject.solution_file.exist?).to be_truthy
  201         end
  202 
  203         it "should update solution file instance to valid" do
  204           expect(subject.valid?).to be_falsey
  205           subject.dependency_list = deps
  206           subject.store!
  207           expect(subject.valid?).to be_truthy
  208         end
  209 
  210         context "when solution file does exist" do
  211           before do
  212             subject.dependency_list = deps
  213             subject.store!
  214           end
  215 
  216           it "should be a valid solution" do
  217             subject = described_class.new(
  218               plugin_file: plugin_path,
  219               solution_file: solution_path
  220             )
  221             expect(subject.valid?).to be_truthy
  222           end
  223 
  224           it "should have expected dependency list" do
  225             subject = described_class.new(
  226               plugin_file: plugin_path,
  227               solution_file: solution_path
  228             )
  229             expect(subject.dependency_list).to eq(deps)
  230           end
  231 
  232           context "when plugin file has been changed" do
  233             before { subject.plugin_file.write("xy") }
  234 
  235             it "should not be a valid solution" do
  236               subject = described_class.new(
  237                 plugin_file: plugin_path,
  238                 solution_file: solution_path
  239               )
  240               expect(subject.valid?).to be_falsey
  241             end
  242 
  243             it "should have empty dependency list" do
  244               subject = described_class.new(
  245                 plugin_file: plugin_path,
  246                 solution_file: solution_path
  247               )
  248               expect(subject.dependency_list).to be_empty
  249             end
  250           end
  251         end
  252       end
  253     end
  254   end
  255 
  256   describe "#load" do
  257     let(:plugin_file_exists) { false }
  258     let(:solution_file_exists) { false }
  259     let(:plugin_file_path) { "PLUGIN_FILE_PATH" }
  260     let(:solution_file_path) { "SOLUTION_FILE_PATH" }
  261     let(:plugin_file) { double("plugin-file") }
  262     let(:solution_file) { double("solution-file") }
  263 
  264     subject do
  265       described_class.new(plugin_file: plugin_file_path, solution_file: solution_file_path)
  266     end
  267 
  268     before do
  269       allow(Pathname).to receive(:new).with(plugin_file_path).and_return(plugin_file)
  270       allow(Pathname).to receive(:new).with(solution_file_path).and_return(solution_file)
  271       allow(plugin_file).to receive(:exist?).and_return(plugin_file_exists)
  272       allow(solution_file).to receive(:exist?).and_return(solution_file_exists)
  273     end
  274 
  275     context "when plugin file and solution file do not exist" do
  276       it "should not attempt to read the solution" do
  277         expect_any_instance_of(described_class).not_to receive(:read_solution)
  278         subject
  279       end
  280     end
  281 
  282     context "when plugin file exists and solution file does not" do
  283       let(:plugin_file_exists) { true }
  284 
  285       it "should not attempt to read the solution" do
  286         expect_any_instance_of(described_class).not_to receive(:read_solution)
  287         subject
  288       end
  289     end
  290 
  291     context "when solution file exists and plugin file does not" do
  292       let(:solution_file_exists) { true }
  293 
  294       it "should not attempt to read the solution" do
  295         expect_any_instance_of(described_class).not_to receive(:read_solution)
  296         subject
  297       end
  298     end
  299 
  300     context "when solution file and plugin file exist" do
  301       let(:plugin_file_exists) { true }
  302       let(:solution_file_exists) { true }
  303 
  304       let(:solution_file_contents) { "" }
  305 
  306       before do
  307         allow(solution_file).to receive(:read).and_return(solution_file_contents)
  308         allow_any_instance_of(described_class).to receive(:plugin_file_checksum).and_return("VALID")
  309       end
  310 
  311       context "when solution file is empty" do
  312         it "should return false" do
  313           expect(subject.send(:load)).to be_falsey
  314         end
  315       end
  316 
  317       context "when solution file contains invalid checksum" do
  318         let(:solution_file_contents) { {checksum: "INVALID", vagrant_version: Vagrant::VERSION}.to_json }
  319 
  320         it "should return false" do
  321           expect(subject.send(:load)).to be_falsey
  322         end
  323       end
  324 
  325       context "when solution file contains different Vagrant version" do
  326         let(:solution_file_contents) { {checksum: "VALID", vagrant_version: "0.1"}.to_json }
  327 
  328         it "should return false" do
  329           expect(subject.send(:load)).to be_falsey
  330         end
  331       end
  332 
  333       context "when solution file contains valid Vagrant version and valid checksum" do
  334         let(:solution_file_contents) {
  335           {checksum: "VALID", vagrant_version: Vagrant::VERSION, dependencies: file_dependencies}.to_json
  336         }
  337         let(:file_dependencies) { dependency_list.map{|d| [d.name, d.requirements_list]} }
  338         let(:dependency_list) { [] }
  339 
  340         it "should return true" do
  341           expect(subject.send(:load)).to be_truthy
  342         end
  343 
  344         it "should be valid" do
  345           expect(subject).to be_valid
  346         end
  347 
  348         context "when solution file contains dependency list" do
  349           let(:dependency_list) { [
  350             Gem::Dependency.new("dep1", "> 0"),
  351             Gem::Dependency.new("dep2", "< 3")
  352           ] }
  353 
  354           it "should be valid" do
  355             expect(subject).to be_valid
  356           end
  357 
  358           it "should convert list into dependency requests" do
  359             subject.dependency_list.each do |d|
  360               expect(d).to be_a(Gem::Resolver::DependencyRequest)
  361             end
  362           end
  363 
  364           it "should include defined dependencies" do
  365             expect(subject.dependency_list.first).to eq(dependency_list.first)
  366             expect(subject.dependency_list.last).to eq(dependency_list.last)
  367           end
  368 
  369           it "should freeze the dependency list" do
  370             expect(subject.dependency_list).to be_frozen
  371           end
  372         end
  373       end
  374     end
  375   end
  376 
  377   describe "#read_solution" do
  378     let(:solution_file_contents) { "" }
  379     let(:plugin_file_path) { "PLUGIN_FILE_PATH" }
  380     let(:solution_file_path) { "SOLUTION_FILE_PATH" }
  381     let(:plugin_file) { double("plugin-file") }
  382     let(:solution_file) { double("solution-file") }
  383 
  384     subject do
  385       described_class.new(plugin_file: plugin_file_path, solution_file: solution_file_path)
  386     end
  387 
  388     before do
  389       allow(Pathname).to receive(:new).with(plugin_file_path).and_return(plugin_file)
  390       allow(Pathname).to receive(:new).with(solution_file_path).and_return(solution_file)
  391       allow(plugin_file).to receive(:exist?).and_return(false)
  392       allow(solution_file).to receive(:exist?).and_return(false)
  393       allow(solution_file).to receive(:read).and_return(solution_file_contents)
  394     end
  395 
  396     it "should return nil when file contents are empty" do
  397       expect(subject.send(:read_solution)).to be_nil
  398     end
  399 
  400     context "when file contents are hash" do
  401       let(:solution_file_contents) { {checksum: "VALID"}.to_json }
  402 
  403       it "should return a hash" do
  404         expect(subject.send(:read_solution)).to be_a(Hash)
  405       end
  406 
  407       it "should return a hash with indifferent access" do
  408         expect(subject.send(:read_solution)).to be_a(Vagrant::Util::HashWithIndifferentAccess)
  409       end
  410     end
  411 
  412     context "when file contents are array" do
  413       let(:solution_file_contents) { ["test"].to_json }
  414 
  415       it "should return a hash" do
  416         expect(subject.send(:read_solution)).to be_a(Hash)
  417       end
  418 
  419       it "should return a hash with indifferent access" do
  420         expect(subject.send(:read_solution)).to be_a(Vagrant::Util::HashWithIndifferentAccess)
  421       end
  422     end
  423 
  424     context "when file contents are null" do
  425       let(:solution_file_contents) { "null" }
  426 
  427       it "should return nil" do
  428         expect(subject.send(:read_solution)).to be_nil
  429       end
  430     end
  431 
  432     context "when file contents are invalid" do
  433       let(:solution_file_contents) { "{2dfwef" }
  434 
  435       it "should return nil" do
  436         expect(subject.send(:read_solution)).to be_nil
  437       end
  438     end
  439   end
  440 end
  441 
  442 describe Vagrant::Bundler do
  443   include_context "unit"
  444 
  445   let(:iso_env) { isolated_environment }
  446   let(:env) { iso_env.create_vagrant_env }
  447   let(:tmpdir) { @v_tmpdir ||= Pathname.new(Dir.mktmpdir("vagrant-bundler-test")) }
  448 
  449   before do
  450     @tmpdir = Dir.mktmpdir("vagrant-bundler-test")
  451     @vh = ENV["VAGRANT_HOME"]
  452     ENV["VAGRANT_HOME"] = @tmpdir
  453   end
  454 
  455   after do
  456     ENV["VAGRANT_HOME"] = @vh
  457     FileUtils.rm_rf(@tmpdir)
  458     FileUtils.rm_rf(@v_tmpdir) if @v_tmpdir
  459   end
  460 
  461   it "should isolate gem path based on Ruby version" do
  462     expect(subject.plugin_gem_path.to_s).to end_with(RUBY_VERSION)
  463   end
  464 
  465   it "should not have an env_plugin_gem_path by default" do
  466     expect(subject.env_plugin_gem_path).to be_nil
  467   end
  468 
  469   describe "#initialize" do
  470     it "should automatically set the plugin gem path" do
  471       expect(subject.plugin_gem_path).not_to be_nil
  472     end
  473 
  474     it "should add current ruby version to plugin gem path suffix" do
  475       expect(subject.plugin_gem_path.to_s).to end_with(RUBY_VERSION)
  476     end
  477 
  478     it "should freeze the plugin gem path" do
  479       expect(subject.plugin_gem_path).to be_frozen
  480     end
  481   end
  482 
  483   describe "#environment_path=" do
  484     it "should error if not given Pathname" do
  485       expect { subject.environment_path = :value }.
  486         to raise_error(TypeError)
  487     end
  488 
  489     context "when set with Pathname" do
  490       let(:env_path) { Pathname.new("/dev/null") }
  491       before { subject.environment_path = env_path }
  492 
  493       it "should set the environment_data_path" do
  494         expect(subject.environment_data_path).to eq(env_path)
  495       end
  496 
  497       it "should set the env_plugin_gem_path" do
  498         expect(subject.env_plugin_gem_path).not_to be_nil
  499       end
  500 
  501       it "should suffix current ruby version to env_plugin_gem_path" do
  502         expect(subject.env_plugin_gem_path.to_s).to end_with(RUBY_VERSION)
  503       end
  504 
  505       it "should base env_plugin_gem_path on environment_path value" do
  506         expect(subject.env_plugin_gem_path.to_s).to start_with(env_path.to_s)
  507       end
  508 
  509       it "should freeze the env_plugin_gem_path" do
  510         expect(subject.env_plugin_gem_path).to be_frozen
  511       end
  512     end
  513   end
  514 
  515   describe "#load_solution_file" do
  516     let(:local_opt) { nil }
  517     let(:global_opt) { nil }
  518     let(:options) { {local: local_opt, global: global_opt} }
  519 
  520     it "should return nil when local and global options are blank" do
  521       expect(subject.load_solution_file(options)).to be_nil
  522     end
  523 
  524     context "when environment data path is set" do
  525       let(:env_path) { "/dev/null" }
  526       before { subject.environment_path = Pathname.new(env_path) }
  527 
  528       context "when local option is set" do
  529         let(:local_opt) { tmpdir + "local" }
  530 
  531         it "should return a SolutionFile instance" do
  532           expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
  533         end
  534 
  535         it "should be located in the environment data path" do
  536           file = subject.load_solution_file(options)
  537           expect(file.solution_file.to_s).to start_with(env_path)
  538         end
  539 
  540         it "should have a local.sol solution file" do
  541           file = subject.load_solution_file(options)
  542           expect(file.solution_file.to_s).to end_with("local.sol")
  543         end
  544 
  545         it "should have plugin file set to local value" do
  546           file = subject.load_solution_file(options)
  547           expect(file.plugin_file.to_s).to eq(local_opt.to_s)
  548         end
  549       end
  550 
  551       context "when global option is set" do
  552         let(:global_opt) { tmpdir + "global" }
  553 
  554         it "should return a SolutionFile instance" do
  555           expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
  556         end
  557 
  558         it "should be located in the environment data path" do
  559           file = subject.load_solution_file(options)
  560           expect(file.solution_file.to_s).to start_with(env_path)
  561         end
  562 
  563         it "should have a global.sol solution file" do
  564           file = subject.load_solution_file(options)
  565           expect(file.solution_file.to_s).to end_with("global.sol")
  566         end
  567 
  568         it "should have plugin file set to global value" do
  569           file = subject.load_solution_file(options)
  570           expect(file.plugin_file.to_s).to eq(global_opt.to_s)
  571         end
  572       end
  573 
  574       context "when local and global option is set" do
  575         let(:global_opt) { tmpdir + "global" }
  576         let(:local_opt) { tmpdir + "local" }
  577 
  578         it "should return nil" do
  579           expect(subject.load_solution_file(options)).to be_nil
  580         end
  581       end
  582     end
  583 
  584     context "when environment data path is unset" do
  585       context "when local option is set" do
  586         let(:local_opt) { tmpdir + "local" }
  587 
  588         it "should return nil" do
  589           expect(subject.load_solution_file(options)).to be_nil
  590         end
  591       end
  592 
  593       context "when global option is set" do
  594         let(:global_opt) { tmpdir + "global" }
  595 
  596         it "should return a SolutionFile instance" do
  597           expect(subject.load_solution_file(options)).to be_a(Vagrant::Bundler::SolutionFile)
  598         end
  599 
  600         it "should be located in the vagrant user data path" do
  601           file = subject.load_solution_file(options)
  602           expect(file.solution_file.to_s).to start_with(Vagrant.user_data_path.to_s)
  603         end
  604 
  605         it "should have a global.sol solution file" do
  606           file = subject.load_solution_file(options)
  607           expect(file.solution_file.to_s).to end_with("global.sol")
  608         end
  609 
  610         it "should have plugin file set to global value" do
  611           file = subject.load_solution_file(options)
  612           expect(file.plugin_file.to_s).to eq(global_opt.to_s)
  613         end
  614       end
  615     end
  616   end
  617 
  618   describe "#deinit" do
  619     it "should provide method for backwards compatibility" do
  620       subject.deinit
  621     end
  622   end
  623 
  624   describe "DEFAULT_GEM_SOURCES" do
  625     it "should list hashicorp gemstore first" do
  626       expect(described_class.const_get(:DEFAULT_GEM_SOURCES).first).to eq(
  627         described_class.const_get(:HASHICORP_GEMSTORE))
  628     end
  629   end
  630 
  631   describe "#init!" do
  632     context "Gem.sources" do
  633       before {
  634         Gem.sources.clear
  635         Gem.sources << "https://rubygems.org/" }
  636 
  637       it "should add hashicorp gem store" do
  638         subject.init!([])
  639         expect(Gem.sources).to include(described_class.const_get(:HASHICORP_GEMSTORE))
  640       end
  641 
  642       it "should add hashicorp gem store to start of sources list" do
  643         subject.init!([])
  644         expect(Gem.sources.sources.first.uri.to_s).to eq(described_class.const_get(:HASHICORP_GEMSTORE))
  645       end
  646     end
  647   end
  648 
  649   describe "#install" do
  650     let(:plugins){ {"my-plugin" => {"gem_version" => "> 0"}} }
  651 
  652     it "should pass plugin information hash to internal install" do
  653       expect(subject).to receive(:internal_install).with(plugins, any_args)
  654       subject.install(plugins)
  655     end
  656 
  657     it "should not include any update plugins" do
  658       expect(subject).to receive(:internal_install).with(anything, nil, any_args)
  659       subject.install(plugins)
  660     end
  661 
  662     it "should flag local when local is true" do
  663       expect(subject).to receive(:internal_install).with(any_args, env_local: true)
  664       subject.install(plugins, true)
  665     end
  666 
  667     it "should not flag local when local is not set" do
  668       expect(subject).to receive(:internal_install).with(any_args, env_local: false)
  669       subject.install(plugins)
  670     end
  671   end
  672 
  673   describe "#install_local" do
  674     let(:plugin_source){ double("plugin_source", spec: plugin_spec) }
  675     let(:plugin_spec){ double("plugin_spec", name: plugin_name, version: plugin_version) }
  676     let(:plugin_name){ "PLUGIN_NAME" }
  677     let(:plugin_version){ "1.0.0" }
  678     let(:plugin_path){ "PLUGIN_PATH" }
  679     let(:sources){ "SOURCES" }
  680 
  681     before do
  682       allow(Gem::Source::SpecificFile).to receive(:new).and_return(plugin_source)
  683       allow(subject).to receive(:internal_install)
  684     end
  685 
  686     it "should return plugin gem specification" do
  687       expect(subject.install_local(plugin_path)).to eq(plugin_spec)
  688     end
  689 
  690     it "should set custom sources" do
  691       expect(subject).to receive(:internal_install) do |info, update, opts|
  692         expect(info[plugin_name]["sources"]).to eq(sources)
  693       end
  694       subject.install_local(plugin_path, sources: sources)
  695     end
  696 
  697     it "should not set the update parameter" do
  698       expect(subject).to receive(:internal_install) do |info, update, opts|
  699         expect(update).to be_nil
  700       end
  701       subject.install_local(plugin_path)
  702     end
  703 
  704     it "should not set plugin as environment local by default" do
  705       expect(subject).to receive(:internal_install) do |info, update, opts|
  706         expect(opts[:env_local]).to be_falsey
  707       end
  708       subject.install_local(plugin_path)
  709     end
  710 
  711     it "should set if plugin is environment local" do
  712       expect(subject).to receive(:internal_install) do |info, update, opts|
  713         expect(opts[:env_local]).to be_truthy
  714       end
  715       subject.install_local(plugin_path, env_local: true)
  716     end
  717   end
  718 
  719   describe "#update" do
  720     let(:plugins){ :plugins }
  721     let(:specific){ [] }
  722 
  723     after{ subject.update(plugins, specific) }
  724 
  725     it "should mark update as true" do
  726       expect(subject).to receive(:internal_install) do |info, update, opts|
  727         expect(update).to be_truthy
  728       end
  729     end
  730 
  731     context "with specific plugins named" do
  732       let(:specific){ ["PLUGIN_NAME"] }
  733 
  734       it "should set update to specific names" do
  735         expect(subject).to receive(:internal_install) do |info, update, opts|
  736           expect(update[:gems]).to eq(specific)
  737         end
  738       end
  739     end
  740   end
  741 
  742   describe "#vagrant_internal_specs" do
  743     let(:vagrant_spec) { double("vagrant_spec", name: "vagrant", version: Gem::Version.new(Vagrant::VERSION),
  744       activated?: vagrant_spec_activated, activate: nil, runtime_dependencies: vagrant_dep_specs) }
  745     let(:spec_list) { [] }
  746     let(:spec_dirs) { [] }
  747     let(:spec_default_dir) { "/dev/null" }
  748     let(:dir_spec_list) { [] }
  749     let(:vagrant_spec_activated) { true }
  750     let(:vagrant_dep_specs) { [] }
  751 
  752     before do
  753       allow(Gem::Specification).to receive(:find) { |&b| vagrant_spec if b.call(vagrant_spec) }
  754       allow(Gem::Specification).to receive(:find_all).and_return(spec_list)
  755       allow(Gem::Specification).to receive(:dirs).and_return(spec_dirs)
  756       allow(Gem::Specification).to receive(:default_specifications_dir).and_return(spec_default_dir)
  757       allow(Gem::Specification).to receive(:each_spec).and_return(dir_spec_list)
  758     end
  759 
  760     it "should return an empty list" do
  761       expect(subject.send(:vagrant_internal_specs)).to eq([])
  762     end
  763 
  764     context "when vagrant specification is not activated" do
  765       let(:vagrant_spec_activated) { false }
  766 
  767       it "should activate the specification" do
  768         expect(vagrant_spec).to receive(:activate)
  769         subject.send(:vagrant_internal_specs)
  770       end
  771     end
  772 
  773     context "when vagrant specification is not found" do
  774       before { allow(Gem::Specification).to receive(:find).and_return(nil) }
  775 
  776       it "should raise not found error" do
  777         expect { subject.send(:vagrant_internal_specs) }.to raise_error(Vagrant::Errors::SourceSpecNotFound)
  778       end
  779     end
  780 
  781     context "when run time dependencies are defined" do
  782       let(:vagrant_dep_specs) { [double("spec", name: "vagrant-dep", requirement: double("spec-req", as_list: []))] }
  783 
  784       it "should call #gem to activate the dependencies" do
  785         expect(subject).to receive(:gem).with("vagrant-dep", any_args)
  786         subject.send(:vagrant_internal_specs)
  787       end
  788     end
  789 
  790     context "when bundler is not defined" do
  791       before { expect(Object).to receive(:const_defined?).with(:Bundler).and_return(false) }
  792 
  793       it "should load gem specification directories" do
  794         expect(Gem::Specification).to receive(:dirs).and_return(spec_dirs)
  795         subject.send(:vagrant_internal_specs)
  796       end
  797 
  798       context "when checking paths" do
  799         let(:spec_dirs) { [double("spec-dir", start_with?: in_user_dir)] }
  800         let(:in_user_dir) { true }
  801         let(:user_dir) { double("user-dir") }
  802 
  803         before { allow(Gem).to receive(:user_dir).and_return(user_dir) }
  804 
  805         it "should check if path is within local user directory" do
  806           expect(spec_dirs.first).to receive(:start_with?).with(user_dir).and_return(false)
  807           subject.send(:vagrant_internal_specs)
  808         end
  809 
  810         context "when path is not within user directory" do
  811           let(:in_user_dir) { false }
  812 
  813           it "should use path when loading specs" do
  814             expect(Gem::Specification).to receive(:each_spec) { |arg| expect(arg).to include(spec_dirs.first) }
  815             subject.send(:vagrant_internal_specs)
  816           end
  817         end
  818       end
  819     end
  820   end
  821 
  822   describe Vagrant::Bundler::PluginSet do
  823     let(:name) { "test-gem" }
  824     let(:version) { "1.0.0" }
  825     let(:directory) { @directory ||= Dir.mktmpdir("vagrant-bundler-test") }
  826 
  827     after do
  828       FileUtils.rm_rf(@directory) if @directory
  829       @directory = nil
  830     end
  831 
  832     describe "#add_vendor_gem" do
  833       context "when spec file does not exist" do
  834         it "should raise a not found error" do
  835           expect { subject.add_vendor_gem(name, directory) }.to raise_error(Gem::GemNotFoundException)
  836         end
  837       end
  838 
  839       context "when spec file exists" do
  840         before do
  841           spec = Gem::Specification.new(name, version)
  842           File.write(File.join(directory, "#{name}.gemspec"), spec.to_ruby)
  843         end
  844 
  845         it "should load the specification" do
  846           expect(subject.add_vendor_gem(name, directory)).to be_a(Gem::Specification)
  847         end
  848 
  849         it "should set the full path in specification" do
  850           spec = subject.add_vendor_gem(name, directory)
  851           expect(spec.full_gem_path).to eq(directory)
  852         end
  853       end
  854     end
  855 
  856     describe "#find_all" do
  857       let(:request) { Gem::Resolver::DependencyRequest.new(dependency, nil) }
  858       let(:dependency) { Gem::Dependency.new("test-gem", requirement) }
  859       let(:requirement) { Gem::Requirement.new(version) }
  860 
  861       context "when specification is not included in set" do
  862         it "should return empty array" do
  863           expect(subject.find_all(request)).to eq([])
  864         end
  865       end
  866 
  867       context "when specification is included in set" do
  868         before do
  869           spec = Gem::Specification.new(name, version)
  870           File.write(File.join(directory, "#{name}.gemspec"), spec.to_ruby)
  871           subject.add_vendor_gem(name, directory)
  872         end
  873 
  874         it "should return a vendor specification instance" do
  875           expect(subject.find_all(request).first).to be_a(Gem::Resolver::VendorSpecification)
  876         end
  877       end
  878     end
  879   end
  880 end