PageRenderTime 26ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/test/configuration/execution_test.rb

http://github.com/capistrano/capistrano
Ruby | 175 lines | 146 code | 26 blank | 3 comment | 1 complexity | 8614a3cd5f60286c743c85d281c8dc00 MD5 | raw file
  1. require "utils"
  2. require 'capistrano/configuration/execution'
  3. require 'capistrano/task_definition'
  4. class ConfigurationExecutionTest < Test::Unit::TestCase
  5. class MockConfig
  6. attr_reader :tasks, :namespaces, :fully_qualified_name, :parent
  7. attr_reader :state, :original_initialize_called
  8. attr_accessor :logger, :default_task
  9. def initialize(options={})
  10. @original_initialize_called = true
  11. @tasks = {}
  12. @namespaces = {}
  13. @state = {}
  14. @fully_qualified_name = options[:fqn]
  15. @parent = options[:parent]
  16. @logger = options.delete(:logger)
  17. end
  18. include Capistrano::Configuration::Execution
  19. end
  20. def setup
  21. @config = MockConfig.new(:logger => stub(:debug => nil, :info => nil, :important => nil))
  22. @config.stubs(:search_task).returns(nil)
  23. end
  24. def test_initialize_should_initialize_collections
  25. assert_nil @config.rollback_requests
  26. assert @config.original_initialize_called
  27. assert @config.task_call_frames.empty?
  28. end
  29. def test_execute_task_should_populate_call_stack
  30. task = new_task @config, :testing
  31. assert_nothing_raised { @config.execute_task(task) }
  32. assert_equal %w(testing), @config.state[:testing][:stack]
  33. assert_nil @config.state[:testing][:history]
  34. assert @config.task_call_frames.empty?
  35. end
  36. def test_nested_execute_task_should_add_to_call_stack
  37. testing = new_task @config, :testing
  38. outer = new_task(@config, :outer) { execute_task(testing) }
  39. assert_nothing_raised { @config.execute_task(outer) }
  40. assert_equal %w(outer testing), @config.state[:testing][:stack]
  41. assert_nil @config.state[:testing][:history]
  42. assert @config.task_call_frames.empty?
  43. end
  44. def test_execute_task_should_execute_in_scope_of_tasks_parent
  45. ns = stub("namespace", :tasks => {}, :default_task => nil, :fully_qualified_name => "ns")
  46. ns.expects(:instance_eval)
  47. testing = new_task ns, :testing
  48. @config.execute_task(testing)
  49. end
  50. def test_transaction_outside_of_task_should_raise_exception
  51. assert_raises(ScriptError) { @config.transaction {} }
  52. end
  53. def test_transaction_without_block_should_raise_argument_error
  54. testing = new_task(@config, :testing) { transaction }
  55. assert_raises(ArgumentError) { @config.execute_task(testing) }
  56. end
  57. def test_transaction_should_initialize_transaction_history
  58. @config.state[:inspector] = stack_inspector
  59. testing = new_task(@config, :testing) { transaction { instance_eval(&state[:inspector]) } }
  60. @config.execute_task(testing)
  61. assert_equal [], @config.state[:testing][:history]
  62. end
  63. def test_transaction_from_within_transaction_should_not_start_new_transaction
  64. third = new_task(@config, :third, &stack_inspector)
  65. second = new_task(@config, :second) { transaction { execute_task(third) } }
  66. first = new_task(@config, :first) { transaction { execute_task(second) } }
  67. # kind of fragile...not sure how else to check that transaction was only
  68. # really run twice...but if the transaction was REALLY run, logger.info
  69. # will be called once when it starts, and once when it finishes.
  70. @config.logger = mock()
  71. @config.logger.stubs(:debug)
  72. @config.logger.expects(:info).times(2)
  73. @config.execute_task(first)
  74. end
  75. def test_on_rollback_should_have_no_effect_outside_of_transaction
  76. aaa = new_task(@config, :aaa) { on_rollback { state[:rollback] = true }; raise "boom" }
  77. assert_raises(RuntimeError) { @config.execute_task(aaa) }
  78. assert_nil @config.state[:rollback]
  79. end
  80. def test_exception_raised_in_transaction_should_call_all_registered_rollback_handlers_in_reverse_order
  81. aaa = new_task(@config, :aaa) { on_rollback { (state[:rollback] ||= []) << :aaa } }
  82. bbb = new_task(@config, :bbb) { on_rollback { (state[:rollback] ||= []) << :bbb } }
  83. ccc = new_task(@config, :ccc) {}
  84. ddd = new_task(@config, :ddd) { on_rollback { (state[:rollback] ||= []) << :ddd }; execute_task(bbb); execute_task(ccc) }
  85. eee = new_task(@config, :eee) { transaction { execute_task(ddd); execute_task(aaa); raise "boom" } }
  86. assert_raises(RuntimeError) do
  87. @config.execute_task(eee)
  88. end
  89. assert_equal [:aaa, :bbb, :ddd], @config.state[:rollback]
  90. assert_nil @config.rollback_requests
  91. assert @config.task_call_frames.empty?
  92. end
  93. def test_exception_during_rollback_should_simply_be_logged_and_ignored
  94. aaa = new_task(@config, :aaa) { on_rollback { state[:aaa] = true; raise LoadError, "ouch" }; execute_task(bbb) }
  95. bbb = new_task(@config, :bbb) { raise MadError, "boom" }
  96. ccc = new_task(@config, :ccc) { transaction { execute_task(aaa) } }
  97. assert_raises(NameError) do
  98. @config.execute_task(ccc)
  99. end
  100. assert @config.state[:aaa]
  101. end
  102. def test_on_rollback_called_twice_should_result_in_last_rollback_block_being_effective
  103. aaa = new_task(@config, :aaa) do
  104. transaction do
  105. on_rollback { (state[:rollback] ||= []) << :first }
  106. on_rollback { (state[:rollback] ||= []) << :second }
  107. raise "boom"
  108. end
  109. end
  110. assert_raises(RuntimeError) do
  111. @config.execute_task(aaa)
  112. end
  113. assert_equal [:second], @config.state[:rollback]
  114. end
  115. def test_find_and_execute_task_should_raise_error_when_task_cannot_be_found
  116. @config.expects(:find_task).with("path:to:task").returns(nil)
  117. assert_raises(Capistrano::NoSuchTaskError) { @config.find_and_execute_task("path:to:task") }
  118. end
  119. def test_find_and_execute_task_should_execute_task_when_task_is_found
  120. @config.expects(:find_task).with("path:to:task").returns(:found)
  121. @config.expects(:execute_task).with(:found)
  122. assert_nothing_raised { @config.find_and_execute_task("path:to:task") }
  123. end
  124. def test_find_and_execute_task_with_before_option_should_trigger_callback
  125. @config.expects(:find_task).with("path:to:task").returns(:found)
  126. @config.expects(:trigger).with(:incoming, :found)
  127. @config.expects(:execute_task).with(:found)
  128. @config.find_and_execute_task("path:to:task", :before => :incoming)
  129. end
  130. def test_find_and_execute_task_with_after_option_should_trigger_callback
  131. @config.expects(:find_task).with("path:to:task").returns(:found)
  132. @config.expects(:trigger).with(:outgoing, :found)
  133. @config.expects(:execute_task).with(:found)
  134. @config.find_and_execute_task("path:to:task", :after => :outgoing)
  135. end
  136. private
  137. def stack_inspector
  138. Proc.new do
  139. (state[:trail] ||= []) << current_task.fully_qualified_name
  140. data = state[current_task.name] = {}
  141. data[:stack] = task_call_frames.map { |frame| frame.task.fully_qualified_name }
  142. data[:history] = rollback_requests && rollback_requests.map { |frame| frame.task.fully_qualified_name }
  143. end
  144. end
  145. def new_task(namespace, name, options={}, &block)
  146. block ||= stack_inspector
  147. namespace.tasks[name] = Capistrano::TaskDefinition.new(name, namespace, &block)
  148. end
  149. end