From 99982fb26e7e87fc654d0fe7964a1bddc0f8a0b0 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Sat, 3 Dec 2011 19:05:50 -0800 Subject: [PATCH] VM-specific configuration now works. --- lib/vagrant/config/loader.rb | 4 ++ lib/vagrant/config/vm.rb | 4 -- lib/vagrant/environment.rb | 24 +++++++-- test/acceptance/base.rb | 1 + .../support/isolated_environment.rb | 4 +- test/{acceptance => }/support/tempdir.rb | 0 test/unit/base.rb | 1 + test/unit/support/isolated_environment.rb | 52 +++++++++++++++++++ test/unit/support/shared/base_context.rb | 14 +++++ test/unit/vagrant/config/loader_test.rb | 28 ++++++++++ test/unit/vagrant/environment_test.rb | 51 +++++++++++++++--- test/unit_legacy/vagrant/config/vm_test.rb | 9 ---- 12 files changed, 166 insertions(+), 26 deletions(-) rename test/{acceptance => }/support/tempdir.rb (100%) create mode 100644 test/unit/support/isolated_environment.rb diff --git a/lib/vagrant/config/loader.rb b/lib/vagrant/config/loader.rb index b0367d10d..fe3accdb4 100644 --- a/lib/vagrant/config/loader.rb +++ b/lib/vagrant/config/loader.rb @@ -38,6 +38,10 @@ module Vagrant # Make all sources an array. data = [data] if !data.kind_of?(Array) + + # Clear the cache for this key only if the data is different + @proc_cache.delete(name) if @sources[name] && @sources[name] != data + @sources[name] = data end diff --git a/lib/vagrant/config/vm.rb b/lib/vagrant/config/vm.rb index a20198cd4..d89ad1b64 100644 --- a/lib/vagrant/config/vm.rb +++ b/lib/vagrant/config/vm.rb @@ -71,10 +71,6 @@ module Vagrant push_proc(&block) end - def has_multi_vms? - !defined_vms.empty? - end - def defined_vms @defined_vms ||= {} end diff --git a/lib/vagrant/environment.rb b/lib/vagrant/environment.rb index 274a85d70..4c94fadf3 100644 --- a/lib/vagrant/environment.rb +++ b/lib/vagrant/environment.rb @@ -9,7 +9,7 @@ module Vagrant # access to the VMs, CLI, etc. all in the scope of this environment. class Environment HOME_SUBDIRS = ["tmp", "boxes", "logs"] - DEFAULT_VM = :default + DEFAULT_VM = "default" DEFAULT_HOME = "~/.vagrant.d" # Parent environment (in the case of multi-VMs) @@ -439,13 +439,27 @@ module Vagrant # to load the configuration in two-passes. We do this because the # first pass is used to determine the box for the VM. The second pass # is used to also load the box Vagrantfile. - vm_configs = global.vm.defined_vm_keys.map do |vm_name| + defined_vm_keys = global.vm.defined_vm_keys.dup + defined_vms = global.vm.defined_vms.dup + + # If this isn't a multi-VM environment, then setup the default VM + # to simply be our configuration. + if defined_vm_keys.empty? + defined_vm_keys << DEFAULT_VM + defined_vms[DEFAULT_VM] = Config::VMConfig::SubVM.new + end + + vm_configs = defined_vm_keys.map do |vm_name| + @logger.debug("Loading configuration for VM: #{vm_name}") + + subvm = defined_vms[vm_name] + # First pass, first run. - config = inner_load[vm_name] + config = inner_load[subvm] # Second pass, with the box - config = inner_load[global.vm.defined_vms[vm_name], config.vm.box] - config.vm.name = vm_name + config = inner_load[subvm, config.vm.box] + config.vm.name = vm_name.to_s # Return the final configuration for this VM config diff --git a/test/acceptance/base.rb b/test/acceptance/base.rb index a999dbb9f..655fd6f09 100644 --- a/test/acceptance/base.rb +++ b/test/acceptance/base.rb @@ -6,6 +6,7 @@ require "log4r" # Add this directory to the load path, since it just makes # everything else so much easier. $:.unshift File.expand_path("../", __FILE__) +$:.unshift File.expand_path("../../", __FILE__) # Load in the supporting files for our tests require "support/shared/base_context" diff --git a/test/acceptance/support/isolated_environment.rb b/test/acceptance/support/isolated_environment.rb index 4be90c819..9540e6fba 100644 --- a/test/acceptance/support/isolated_environment.rb +++ b/test/acceptance/support/isolated_environment.rb @@ -4,8 +4,8 @@ require "pathname" require "log4r" require "childprocess" -require File.expand_path("../tempdir", __FILE__) -require File.expand_path("../virtualbox", __FILE__) +require "support/tempdir" +require "support/virtualbox" module Acceptance # This class manages an isolated environment for Vagrant to diff --git a/test/acceptance/support/tempdir.rb b/test/support/tempdir.rb similarity index 100% rename from test/acceptance/support/tempdir.rb rename to test/support/tempdir.rb diff --git a/test/unit/base.rb b/test/unit/base.rb index 208b02d03..bd0cff1c5 100644 --- a/test/unit/base.rb +++ b/test/unit/base.rb @@ -8,6 +8,7 @@ require "vagrant" # Add this directory to the load path, since it just makes # everything else easier. $:.unshift File.expand_path("../", __FILE__) +$:.unshift File.expand_path("../../", __FILE__) # Load in helpers require "support/shared/base_context" diff --git a/test/unit/support/isolated_environment.rb b/test/unit/support/isolated_environment.rb new file mode 100644 index 000000000..c3a302561 --- /dev/null +++ b/test/unit/support/isolated_environment.rb @@ -0,0 +1,52 @@ +require "fileutils" +require "pathname" + +require "log4r" + +require "support/tempdir" + +module Unit + # This class manages an isolated environment for Vagrant to + # run in. It creates a temporary directory to act as the + # working directory as well as sets a custom home directory. + # + # This class also provides various helpers to create Vagrantfiles, + # boxes, etc. + class IsolatedEnvironment + attr_reader :homedir + attr_reader :workdir + + # Initializes an isolated environment. You can pass in some + # options here to configure runing custom applications in place + # of others as well as specifying environmental variables. + # + # @param [Hash] apps A mapping of application name (such as "vagrant") + # to an alternate full path to the binary to run. + # @param [Hash] env Additional environmental variables to inject + # into the execution environments. + def initialize(apps=nil, env=nil) + @logger = Log4r::Logger.new("unit::isolated_environment") + + # Create a temporary directory for our work + @tempdir = Tempdir.new("vagrant") + @logger.info("Initialize isolated environment: #{@tempdir.path}") + + # Setup the home and working directories + @homedir = Pathname.new(File.join(@tempdir.path, "home")) + @workdir = Pathname.new(File.join(@tempdir.path, "work")) + + @homedir.mkdir + @workdir.mkdir + end + + def create_vagrant_env + Vagrant::Environment.new(:cwd => @workdir, :home_path => @homedir) + end + + def vagrantfile(contents) + @workdir.join("Vagrantfile").open("w+") do |f| + f.write(contents) + end + end + end +end diff --git a/test/unit/support/shared/base_context.rb b/test/unit/support/shared/base_context.rb index fb0018c55..c730afd13 100644 --- a/test/unit/support/shared/base_context.rb +++ b/test/unit/support/shared/base_context.rb @@ -1,6 +1,20 @@ require "tempfile" +require "support/isolated_environment" + shared_context "unit" do + # This creates an isolated environment so that Vagrant doesn't + # muck around with your real system during unit tests. + # + # The returned isolated environment has a variety of helper + # methods on it to easily create files, Vagrantfiles, boxes, + # etc. + def isolated_environment + env = Unit::IsolatedEnvironment.new + yield env if block_given? + env + end + # This helper creates a temporary file and returns a Pathname # object pointed to it. def temporary_file(contents=nil) diff --git a/test/unit/vagrant/config/loader_test.rb b/test/unit/vagrant/config/loader_test.rb index ceb8b732f..3b598d9b2 100644 --- a/test/unit/vagrant/config/loader_test.rb +++ b/test/unit/vagrant/config/loader_test.rb @@ -32,6 +32,34 @@ describe Vagrant::Config::Loader do $_config_data.should == 1 end + it "should clear cache on setting to a new value" do + $_config_data = 0 + + instance.load_order = [:proc] + instance.set(:proc, temporary_file("$_config_data += 1")) + 5.times { instance.load } + + instance.set(:proc, temporary_file("$_config_data += 1")) + 5.times { instance.load } + + $_config_data.should == 2 + end + + it "should not clear the cache if setting to the same value multiple times" do + $_config_data = 0 + + file = temporary_file("$_config_data += 1") + + instance.load_order = [:proc] + instance.set(:proc, file) + 5.times { instance.load } + + instance.set(:proc, file) + 5.times { instance.load } + + $_config_data.should == 1 + end + it "should raise proper error if there is a syntax error in a Vagrantfile" do instance.load_order = [:file] instance.set(:file, temporary_file("Vagrant:^Config")) diff --git a/test/unit/vagrant/environment_test.rb b/test/unit/vagrant/environment_test.rb index 86bfb00a3..7b0f0b7a1 100644 --- a/test/unit/vagrant/environment_test.rb +++ b/test/unit/vagrant/environment_test.rb @@ -2,7 +2,11 @@ require File.expand_path("../../base", __FILE__) require "pathname" +require "support/tempdir" + describe Vagrant::Environment do + include_context "unit" + describe "current working directory" do it "is the cwd by default" do described_class.new.cwd.should == Pathname.new(Dir.pwd) @@ -16,8 +20,9 @@ describe Vagrant::Environment do describe "home path" do it "is set to the home path given" do - instance = described_class.new(:home_path => "/tmp/foo") - instance.home_path.should == Pathname.new("/tmp/foo") + dir = Tempdir.new.path + instance = described_class.new(:home_path => dir) + instance.home_path.should == Pathname.new(dir) end it "is set to the environmental variable VAGRANT_HOME" do @@ -31,19 +36,53 @@ describe Vagrant::Environment do end describe "loading configuration" do - let(:home_path) { Pathname.new("/tmp/foo") } + let(:home_path) { Pathname.new(Tempdir.new.path) } let(:instance) { described_class.new(:home_path => home_path) } it "should load global configuration" do - File.open(home_path.join("Vagrantfile"), "w+") do |f| - f.write(<<-VF) + environment = isolated_environment do |env| + env.vagrantfile(<<-VF) Vagrant::Config.run do |config| config.vagrant.dotfile_name = "foo" end VF end - instance.config.global.vagrant.dotfile_name.should == "foo" + env = environment.create_vagrant_env + env.config.global.vagrant.dotfile_name.should == "foo" + end + + it "should load VM configuration" do + environment = isolated_environment do |env| + env.vagrantfile(<<-VF) +Vagrant::Config.run do |config| + config.vagrant.dotfile_name = "foo" +end +VF + end + + env = environment.create_vagrant_env + env.config.for_vm("default").vm.name.should == "default" + end + + it "should load VM configuration with multiple VMs" do + environment = isolated_environment do |env| + env.vagrantfile(<<-VF) +Vagrant::Config.run do |config| + config.vm.define :foo do |vm| + vm.ssh.port = 100 + end + + config.vm.define :bar do |vm| + vm.ssh.port = 200 + end +end +VF + end + + env = environment.create_vagrant_env + env.config.for_vm("foo").ssh.port.should == 100 + env.config.for_vm("bar").ssh.port.should == 200 end end diff --git a/test/unit_legacy/vagrant/config/vm_test.rb b/test/unit_legacy/vagrant/config/vm_test.rb index 585e1aef3..3501af53f 100644 --- a/test/unit_legacy/vagrant/config/vm_test.rb +++ b/test/unit_legacy/vagrant/config/vm_test.rb @@ -24,15 +24,6 @@ class ConfigVMTest < Test::Unit::TestCase assert @config.defined_vms[:name].options[:set] end - should "not have multi-VMs by default" do - assert !@config.has_multi_vms? - end - - should "have multi-VMs once one is specified" do - @config.define(:foo) {} - assert @config.has_multi_vms? - end - should "retain vm definition order" do @config.define(:a) {} @config.define(:b) {}