Implemented the "rescue" method for action runners when an exception is raised. Read documentation for more information.
This commit is contained in:
parent
affe1cd9ad
commit
37393986e3
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue