Implemented the "rescue" method for action runners when an exception is raised. Read documentation for more information.

This commit is contained in:
Mitchell Hashimoto 2010-02-28 01:06:01 -08:00
parent affe1cd9ad
commit 37393986e3
3 changed files with 92 additions and 29 deletions

View File

@ -46,6 +46,18 @@ module Vagrant
# Do lots of stuff here
# @vm.invoke_callback(:after_oven, "more", "than", "one", "option")
end
# This method is only called if some exception occurs in the chain
# of actions. If an exception is raised in any action in the current
# chain, then every action part of that chain has {#rescue} called
# before raising the exception further. This method should be used to
# perform any cleanup necessary in the face of errors.
#
# **Warning:** Since this method is called when an exception is already
# raised, be _extra careful_ when implementing this method to handle
# all your own exceptions, otherwise it'll mask the initially raised
# exception.
def rescue(exception); end
end
class ActionException < Exception; end

View File

@ -38,10 +38,20 @@ module Vagrant
# Call the prepare method on each once its
# initialized, then call the execute! method
[:prepare, :execute!].each do |method|
actions.each do |action|
action.send(method)
begin
[:prepare, :execute!].each do |method|
actions.each do |action|
action.send(method)
end
end
rescue Exception => e
# Run the rescue code to do any emergency cleanup
actions.each do |action|
action.rescue(e)
end
# Finally, reraise the exception
raise
end
# Clear the actions

View File

@ -66,22 +66,11 @@ class ActionRunnerTest < Test::Unit::TestCase
end
end
context "actions" do
context "adding actions" do
setup do
@runner = Vagrant::Actions::Runner.new
end
should "setup actions to be an array" do
assert_nil @runner.instance_variable_get(:@actions)
actions = @runner.actions
assert actions.is_a?(Array)
assert actions.equal?(@runner.actions)
end
should "be empty initially" do
assert @runner.actions.empty?
end
should "initialize the action when added" do
action_klass = mock("action_class")
action_inst = mock("action_inst")
@ -95,6 +84,34 @@ class ActionRunnerTest < Test::Unit::TestCase
action_klass.expects(:new).with(@runner, "foo", "bar").once
@runner.add_action(action_klass, "foo", "bar")
end
end
context "class method execute" do
should "run actions on class method execute!" do
vm = mock("vm")
execute_seq = sequence("execute_seq")
Vagrant::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
vm.expects(:add_action).with("foo").in_sequence(execute_seq)
vm.expects(:execute!).once.in_sequence(execute_seq)
Vagrant::Actions::Runner.execute!("foo")
end
should "forward arguments to add_action on class method execute!" do
vm = mock("vm")
execute_seq = sequence("execute_seq")
Vagrant::Actions::Runner.expects(:new).returns(vm).in_sequence(execute_seq)
vm.expects(:add_action).with("foo", "bar", "baz").in_sequence(execute_seq)
vm.expects(:execute!).once.in_sequence(execute_seq)
Vagrant::Actions::Runner.execute!("foo", "bar", "baz")
end
end
context "instance method execute" do
setup do
@runner = Vagrant::Actions::Runner.new
end
should "clear the actions and run a single action if given to execute!" do
action = mock("action")
@ -138,24 +155,48 @@ class ActionRunnerTest < Test::Unit::TestCase
@runner.execute!
end
should "run actions on class method execute!" do
vm = mock("vm")
execute_seq = sequence("execute_seq")
Vagrant::VM.expects(:new).returns(vm).in_sequence(execute_seq)
vm.expects(:add_action).with("foo").in_sequence(execute_seq)
vm.expects(:execute!).once.in_sequence(execute_seq)
context "exceptions" do
setup do
@actions = [mock_fake_action, mock_fake_action]
@actions.each { |a| @runner.actions << a }
Vagrant::VM.execute!("foo")
@exception = Exception.new
end
should "call #rescue on each action if an exception is raised during execute!" do
@actions.each do |a|
a.expects(:rescue).with(@exception).once
end
@actions[0].stubs(:execute!).raises(@exception)
assert_raises(Exception) { @runner.execute! }
end
should "call #rescue on each action if an exception is raised during prepare" do
@actions.each do |a|
a.expects(:rescue).with(@exception).once
end
@actions[0].stubs(:prepare).raises(@exception)
assert_raises(Exception) { @runner.execute! }
end
end
end
context "actions" do
setup do
@runner = Vagrant::Actions::Runner.new
end
should "forward arguments to add_action on class method execute!" do
vm = mock("vm")
execute_seq = sequence("execute_seq")
Vagrant::VM.expects(:new).returns(vm).in_sequence(execute_seq)
vm.expects(:add_action).with("foo", "bar", "baz").in_sequence(execute_seq)
vm.expects(:execute!).once.in_sequence(execute_seq)
should "setup actions to be an array" do
assert_nil @runner.instance_variable_get(:@actions)
actions = @runner.actions
assert actions.is_a?(Array)
assert actions.equal?(@runner.actions)
end
Vagrant::VM.execute!("foo", "bar", "baz")
should "be empty initially" do
assert @runner.actions.empty?
end
end
end