From 3cd262ed75a853ed710145b945095345d8b9ef00 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 22 Dec 2011 20:17:45 -0800 Subject: [PATCH] Unit tests for Vagrant::Action::Builder --- lib/vagrant/action/builder.rb | 32 +-- lib/vagrant/action/environment.rb | 19 -- lib/vagrant/action/runner.rb | 4 +- lib/vagrant/action/warden.rb | 4 +- test/unit/vagrant/action/builder_test.rb | 161 ++++++++++++++ test/unit/vagrant/action/environment_test.rb | 6 - .../vagrant/action/builder_test.rb | 207 ------------------ 7 files changed, 182 insertions(+), 251 deletions(-) create mode 100644 test/unit/vagrant/action/builder_test.rb delete mode 100644 test/unit_legacy/vagrant/action/builder_test.rb diff --git a/lib/vagrant/action/builder.rb b/lib/vagrant/action/builder.rb index efc8c3e8b..2ed8a968b 100644 --- a/lib/vagrant/action/builder.rb +++ b/lib/vagrant/action/builder.rb @@ -23,14 +23,6 @@ module Vagrant instance_eval(&block) if block_given? end - # Returns the current stack of middlewares. You probably won't - # need to use this directly, and it's recommended that you don't. - # - # @return [Array] - def stack - @stack ||= [] - end - # Returns a mergeable version of the builder. If `use` is called with # the return value of this method, then the stack will merge, instead # of being treated as a separate single middleware. @@ -75,9 +67,9 @@ module Vagrant insert(index + 1, middleware, *args, &block) end - # Swaps out the given middlware object or index with the new + # Replaces the given middlware object or index with the new # middleware. - def swap(index, middleware, *args, &block) + def replace(index, middleware, *args, &block) if index.is_a?(Integer) delete(index) insert(index, middleware, *args, &block) @@ -93,6 +85,13 @@ module Vagrant stack.delete_at(index) end + # Runs the builder stack with the given environment. + def call(env) + to_app(env).call(env) + end + + protected + # Returns the numeric index for the given middleware object. # # @param [Object] object The item to find the index for @@ -105,6 +104,14 @@ module Vagrant nil end + # Returns the current stack of middlewares. You probably won't + # need to use this directly, and it's recommended that you don't. + # + # @return [Array] + def stack + @stack ||= [] + end + # Converts the builder stack to a runnable action sequence. # # @param [Vagrant::Action::Environment] env The action environment @@ -114,11 +121,6 @@ module Vagrant # and predictable behavior upon exceptions. Warden.new(stack.dup, env) end - - # Runs the builder stack with the given environment. - def call(env) - to_app(env).call(env) - end end end end diff --git a/lib/vagrant/action/environment.rb b/lib/vagrant/action/environment.rb index 769a16832..011601975 100644 --- a/lib/vagrant/action/environment.rb +++ b/lib/vagrant/action/environment.rb @@ -7,25 +7,6 @@ module Vagrant # some helper methods for accessing the environment as well # as being a hash, to store any additional options. class Environment < Util::HashWithIndifferentAccess - def initialize - @interrupted = false - end - - # Marks an environment as interrupted (by an outside signal or - # anything). This will trigger any middleware sequences using this - # environment to halt. This is automatically set by {Action} when - # a SIGINT is captured. - def interrupt! - @interrupted = true - end - - # Returns a boolean denoting if environment has been interrupted - # with a SIGINT. - # - # @return [Bool] - def interrupted? - !!@interrupted - end end end end diff --git a/lib/vagrant/action/runner.rb b/lib/vagrant/action/runner.rb index aa667e009..57deccfc6 100644 --- a/lib/vagrant/action/runner.rb +++ b/lib/vagrant/action/runner.rb @@ -34,13 +34,13 @@ module Vagrant # chain has been run. ui = environment[:ui] if environment.has_key?(:ui) int_callback = lambda do - if environment.interrupted? + if environment[:interrupted] ui.error I18n.t("vagrant.actions.runner.exit_immediately") if ui abort end ui.warn I18n.t("vagrant.actions.runner.waiting_cleanup") if ui && !@@reported_interrupt - environment.interrupt! + environment[:interrupted] = true @@reported_interrupt = true end diff --git a/lib/vagrant/action/warden.rb b/lib/vagrant/action/warden.rb index 42c50e49a..8a5d4978d 100644 --- a/lib/vagrant/action/warden.rb +++ b/lib/vagrant/action/warden.rb @@ -27,11 +27,11 @@ module Vagrant begin # Call the next middleware in the sequence, appending to the stack # of "recoverable" middlewares in case something goes wrong! - raise Errors::VagrantInterrupt if env.interrupted? + raise Errors::VagrantInterrupt if env[:interrupted] action = @actions.shift @logger.info("Calling action: #{action}") @stack.unshift(action).first.call(env) - raise Errors::VagrantInterrupt if env.interrupted? + raise Errors::VagrantInterrupt if env[:interrupted] rescue SystemExit # This means that an "exit" or "abort" was called. In these cases, # we just exit immediately. diff --git a/test/unit/vagrant/action/builder_test.rb b/test/unit/vagrant/action/builder_test.rb new file mode 100644 index 000000000..3eb09f304 --- /dev/null +++ b/test/unit/vagrant/action/builder_test.rb @@ -0,0 +1,161 @@ +require File.expand_path("../../../base", __FILE__) + +describe Vagrant::Action::Builder do + let(:data) { { :data => [] } } + let(:instance) { described_class.new } + + # This returns a proc that can be used with the builder + # that simply appends data to an array in the env. + def appender_proc(data) + Proc.new { |env| env[:data] << data } + end + + context "basic `use`" do + it "should add items to the stack and make them callable" do + data = {} + proc = Proc.new { |env| env[:data] = true } + + instance.use proc + instance.call(data) + + data[:data].should == true + end + + it "should be able to add multiple items" do + data = {} + proc1 = Proc.new { |env| env[:one] = true } + proc2 = Proc.new { |env| env[:two] = true } + + instance.use proc1 + instance.use proc2 + instance.call(data) + + data[:one].should == true + data[:two].should == true + end + + it "should be able to add another builder" do + data = {} + proc1 = Proc.new { |env| env[:one] = true } + + # Build the first builder + one = described_class.new + one.use proc1 + + # Add it to this builder + two = described_class.new + two.use one + + # Call the 2nd and verify results + two.call(data) + data[:one].should == true + end + + it "should be able to set additional variables if using another builder" do + data = { } + proc1 = Proc.new { |env| env[:data] += 1 } + + # Build the first builder + one = described_class.new + one.use proc1 + + # Add it to this builder + two = described_class.new + two.use one, :data => 10 + + # Call the 2nd and verify results + two.call(data) + data[:data].should == 11 + end + end + + context "inserting" do + it "can insert at an index" do + instance.use appender_proc(1) + instance.insert(0, appender_proc(2)) + instance.call(data) + + data[:data].should == [2, 1] + end + + it "can insert next to a previous object" do + proc2 = appender_proc(2) + instance.use appender_proc(1) + instance.use proc2 + instance.insert(proc2, appender_proc(3)) + instance.call(data) + + data[:data].should == [1, 3, 2] + end + + it "can insert before" do + instance.use appender_proc(1) + instance.insert_before 0, appender_proc(2) + instance.call(data) + + data[:data].should == [2, 1] + end + + it "can insert after" do + instance.use appender_proc(1) + instance.use appender_proc(3) + instance.insert_after 0, appender_proc(2) + instance.call(data) + + data[:data].should == [1, 2, 3] + end + + it "raises an exception if an invalid object given" do + expect { instance.insert_after "object", appender_proc(1) }. + to raise_error(RuntimeError) + end + end + + context "replace" do + it "can replace an object" do + proc1 = appender_proc(1) + proc2 = appender_proc(2) + + instance.use proc1 + instance.replace proc1, proc2 + instance.call(data) + + data[:data].should == [2] + end + + it "can replace by index" do + proc1 = appender_proc(1) + proc2 = appender_proc(2) + + instance.use proc1 + instance.replace 0, proc2 + instance.call(data) + + data[:data].should == [2] + end + end + + context "deleting" do + it "can delete by object" do + proc1 = appender_proc(1) + + instance.use proc1 + instance.use appender_proc(2) + instance.delete proc1 + instance.call(data) + + data[:data].should == [2] + end + + it "can delete by index" do + proc1 = appender_proc(1) + + instance.use proc1 + instance.use appender_proc(2) + instance.delete 0 + instance.call(data) + + data[:data].should == [2] + end + end +end diff --git a/test/unit/vagrant/action/environment_test.rb b/test/unit/vagrant/action/environment_test.rb index 4f278d566..e516429bc 100644 --- a/test/unit/vagrant/action/environment_test.rb +++ b/test/unit/vagrant/action/environment_test.rb @@ -13,10 +13,4 @@ describe Vagrant::Action::Environment do instance["foo"] = "bar" instance[:foo].should == "bar" end - - it "should keep track of interrupted state" do - instance.should_not be_interrupted - instance.interrupt! - instance.should be_interrupted - end end diff --git a/test/unit_legacy/vagrant/action/builder_test.rb b/test/unit_legacy/vagrant/action/builder_test.rb deleted file mode 100644 index cc0e350e2..000000000 --- a/test/unit_legacy/vagrant/action/builder_test.rb +++ /dev/null @@ -1,207 +0,0 @@ -require "test_helper" -require "logger" - -class ActionBuilderTest < Test::Unit::TestCase - setup do - @klass = Vagrant::Action::Builder - end - - context "initializing" do - should "setup empty middleware stack" do - builder = @klass.new - assert builder.stack.empty? - end - - should "take block to setup stack" do - builder = @klass.new do - use Hash - use lambda { |i| i } - end - - assert !builder.stack.empty? - assert_equal 2, builder.stack.length - end - end - - context "with an instance" do - setup do - @instance = @klass.new - end - - context "adding to the stack" do - should "return self" do - assert @instance.equal?(@instance.use(1)) - end - - should "add to the end" do - @instance.use 1 - @instance.use 2 - assert_equal [2, [], nil], @instance.stack.last - end - - should "merge in other builder's stack" do - other = @klass.new do - use 2 - use 3 - end - - @instance.use 1 - @instance.use other - assert_equal 3, @instance.stack.length - end - - should "prepend a set environment task for merging middlewares if given" do - other = @klass.new do - use 1 - end - - @instance.use 0 - @instance.use(other, :foo => :bar) - assert_equal 3, @instance.stack.length - assert_equal Vagrant::Action::Env::Set, @instance.stack[1].first - end - end - - context "flatten" do - should "return the flattened format of the builder" do - env = Vagrant::Action::Environment.new(nil) - env["logger"] = Logger.new(nil) - env.expects(:foo).once - - func = lambda { |x| x.foo } - @instance.use func - proc = @instance.flatten - assert proc.respond_to?(:call) - proc.call(env) - end - end - - context "inserting" do - setup do - @instance.use "1" - @instance.use "2" - end - - should "insert at the proper numeric index" do - @instance.insert(1, "3") - assert_equal "3", @instance.stack[1].first - end - - should "insert next to the proper object if given" do - @instance.insert("2", "3") - assert_equal "3", @instance.stack[1].first - end - - should "be able to call insert_before as well" do - @instance.insert_before("1", "0") - assert_equal "0", @instance.stack.first.first - end - - should "be able to insert_after" do - @instance.insert_after("1", "0") - assert_equal "0", @instance.stack[1].first - end - - should "be able to insert_after using numeric index" do - @instance.insert_after(1, "0") - assert_equal "0", @instance.stack[2].first - end - - should "raise an exception if invalid index" do - assert_raises(RuntimeError) { - @instance.insert_after("15", "0") - } - end - end - - context "swapping" do - setup do - @instance.use "1" - @instance.use "2" - end - - should "be able to swap using the object" do - @instance.swap "1", "3" - assert_equal "3", @instance.stack.first.first - end - - should "be able to swap using the index" do - @instance.swap 0, "3" - assert_equal "3", @instance.stack.first.first - end - end - - context "deleting" do - setup do - @instance.use "1" - end - - should "delete the proper object" do - @instance.delete("1") - assert @instance.stack.empty? - end - - should "delete by index if given" do - @instance.delete(0) - assert @instance.stack.empty? - end - end - - context "getting an index of an object" do - should "return the proper index if it exists" do - @instance.use 1 - @instance.use 2 - @instance.use 3 - assert_equal 1, @instance.index(2) - end - end - - context "converting to an app" do - should "make non-classes lambdas" do - env = Vagrant::Action::Environment.new(nil) - env["logger"] = Logger.new(nil) - env.expects(:foo).once - - func = lambda { |x| x.foo } - @instance.use func - @instance.to_app(env).call(env) - end - - should "raise exception if given invalid middleware" do - @instance.use 7 - assert_raises(RuntimeError) { - @instance.to_app(nil) - } - end - end - - context "calling" do - def mock_middleware - middleware = Class.new do - def initialize(app, env) - @app = app - end - - def call(env) - @app.call(env) - end - end - end - - should "convert to an app then call with the env" do - mw = mock_middleware - mw.any_instance.expects(:call).with() do |env| - assert env.has_key?(:key) - true - end - - env = Vagrant::Action::Environment.new(nil) - env["logger"] = Logger.new(nil) - env[:key] = :value - - @instance.use(mw) - @instance.call(env) - end - end - end -end