diff --git a/lib/vagrant/action/builder.rb b/lib/vagrant/action/builder.rb index 526dfe8b2..c828c1eb6 100644 --- a/lib/vagrant/action/builder.rb +++ b/lib/vagrant/action/builder.rb @@ -50,12 +50,19 @@ module Vagrant # @param [Vagrant::Action::Environment] env The action environment # @return [Object] A callable object def to_app(env) - items = stack.collect do |item| + # Prepend the error halt task so errneous environments are halted + # before the chain even begins. + items = stack.dup.unshift([ErrorHalt, [], nil]) + + # Convert each middleware into a lambda which takes the next + # middleware. + items = items.collect do |item| klass, args, block = item lambda { |app| klass.new(app, env, *args, &block) } end - items << lambda { |env| } # The final step, which simply returns + # Append the final step and convert into flattened call chain. + items << lambda { |env| } items[0...-1].reverse.inject(items.last) { |a,e| e.call(a) } end diff --git a/lib/vagrant/action/error_halt.rb b/lib/vagrant/action/error_halt.rb new file mode 100644 index 000000000..2c4411659 --- /dev/null +++ b/lib/vagrant/action/error_halt.rb @@ -0,0 +1,14 @@ +module Vagrant + class Action + # A middleware which simply halts if the environment is erroneous. + class ErrorHalt + def initialize(app,env) + @app = app + end + + def call(env) + @app.call(env) if !env.error? + end + end + end +end diff --git a/test/vagrant/action/builder_test.rb b/test/vagrant/action/builder_test.rb index 1254fbda6..2b8aa372f 100644 --- a/test/vagrant/action/builder_test.rb +++ b/test/vagrant/action/builder_test.rb @@ -47,16 +47,17 @@ class ActionBuilderTest < Test::Unit::TestCase end context "converting to an app" do - should "initialize each middleware with app and env" do - # TODO: better testing of this method... somehow - + should "preprend error halt to the chain" do result = mock("result") env = {:a => :b} middleware = mock("middleware") middleware.expects(:new).with(anything, env).returns(result) @instance.use middleware - assert_equal result, @instance.to_app(env) + result = @instance.to_app(env) + assert result.kind_of?(Vagrant::Action::ErrorHalt) end + + # TODO: Better testing of this method end context "calling" do @@ -79,8 +80,11 @@ class ActionBuilderTest < Test::Unit::TestCase true end + env = Vagrant::Action::Environment.new(nil) + env[:key] = :value + @instance.use(mw) - @instance.call(:key => :value) + @instance.call(env) end end end diff --git a/test/vagrant/action/error_halt_test.rb b/test/vagrant/action/error_halt_test.rb new file mode 100644 index 000000000..4f3af8771 --- /dev/null +++ b/test/vagrant/action/error_halt_test.rb @@ -0,0 +1,21 @@ +require File.join(File.dirname(__FILE__), '..', '..', 'test_helper') + +class ErrorHaltTest < Test::Unit::TestCase + setup do + @klass = Vagrant::Action::ErrorHalt + @app, @env = mock_action_data + @instance = @klass.new(@app, @env) + end + + should "continue the chain if no error" do + assert !@env.error? + @app.expects(:call).with(@env).once + @instance.call(@env) + end + + should "halt the chain if an error occured" do + @env.error!(:foo) + @app.expects(:call).never + @instance.call(@env) + end +end