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

/test/configuration/connections_test.rb

http://github.com/capistrano/capistrano
Ruby | 420 lines | 373 code | 47 blank | 0 comment | 5 complexity | c0b3be5cbb77c10be57623d0d1c46c8a MD5 | raw file
  1. require "utils"
  2. require 'capistrano/configuration/connections'
  3. class ConfigurationConnectionsTest < Test::Unit::TestCase
  4. class MockConfig
  5. attr_reader :original_initialize_called
  6. attr_reader :values
  7. attr_accessor :current_task
  8. def initialize
  9. @original_initialize_called = true
  10. @values = {}
  11. end
  12. def fetch(*args)
  13. @values.fetch(*args)
  14. end
  15. def [](key)
  16. @values[key]
  17. end
  18. def exists?(key)
  19. @values.key?(key)
  20. end
  21. include Capistrano::Configuration::Connections
  22. end
  23. def setup
  24. @config = MockConfig.new
  25. @config.stubs(:logger).returns(stub_everything)
  26. Net::SSH.stubs(:configuration_for).returns({})
  27. @ssh_options = {
  28. :user => "user",
  29. :port => 8080,
  30. :password => "g00b3r",
  31. :ssh_options => { :debug => :verbose }
  32. }
  33. end
  34. def test_initialize_should_initialize_collections_and_call_original_initialize
  35. assert @config.original_initialize_called
  36. assert @config.sessions.empty?
  37. end
  38. def test_connection_factory_should_return_default_connection_factory_instance
  39. factory = @config.connection_factory
  40. assert_instance_of Capistrano::Configuration::Connections::DefaultConnectionFactory, factory
  41. end
  42. def test_connection_factory_instance_should_be_cached
  43. assert_same @config.connection_factory, @config.connection_factory
  44. end
  45. def test_default_connection_factory_honors_config_options
  46. server = server("capistrano")
  47. Capistrano::SSH.expects(:connect).with(server, @config).returns(:session)
  48. assert_equal :session, @config.connection_factory.connect_to(server)
  49. end
  50. def test_should_connect_through_gateway_if_gateway_variable_is_set
  51. @config.values[:gateway] = "j@gateway"
  52. Net::SSH::Gateway.expects(:new).with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  53. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  54. end
  55. def test_connection_factory_as_gateway_should_honor_config_options
  56. @config.values[:gateway] = "gateway"
  57. @config.values.update(@ssh_options)
  58. Net::SSH::Gateway.expects(:new).with("gateway", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  59. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  60. end
  61. def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_an_array
  62. @config.values[:gateway] = ["j@gateway1", "k@gateway2"]
  63. gateway1 = mock
  64. Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(gateway1)
  65. gateway1.expects(:open).returns(65535)
  66. Net::SSH::Gateway.expects(:new).with("127.0.0.1", "k", :port => 65535, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  67. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  68. end
  69. def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_a_hash
  70. @config.values[:gateway] = { ["j@gateway1", "k@gateway2"] => :default }
  71. gateway1 = mock
  72. Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(gateway1)
  73. gateway1.expects(:open).returns(65535)
  74. Net::SSH::Gateway.expects(:new).with("127.0.0.1", "k", :port => 65535, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  75. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  76. end
  77. def test_connection_factory_as_gateway_should_share_gateway_between_connections
  78. @config.values[:gateway] = "j@gateway"
  79. Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  80. Capistrano::SSH.stubs(:connect).returns(stub_everything)
  81. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  82. @config.establish_connections_to(server("capistrano"))
  83. @config.establish_connections_to(server("another"))
  84. end
  85. def test_connection_factory_as_gateway_should_share_gateway_between_like_connections_if_gateway_variable_is_a_hash
  86. @config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"] }
  87. Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  88. Capistrano::SSH.stubs(:connect).returns(stub_everything)
  89. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  90. @config.establish_connections_to(server("capistrano"))
  91. @config.establish_connections_to(server("another"))
  92. end
  93. def test_connection_factory_as_gateways_should_not_share_gateway_between_unlike_connections_if_gateway_variable_is_a_hash
  94. @config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"], "k@gateway2" => "yafhost" }
  95. Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  96. Net::SSH::Gateway.expects(:new).once.with("gateway2", "k", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
  97. Capistrano::SSH.stubs(:connect).returns(stub_everything)
  98. assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
  99. @config.establish_connections_to(server("capistrano"))
  100. @config.establish_connections_to(server("another"))
  101. @config.establish_connections_to(server("yafhost"))
  102. end
  103. def test_establish_connections_to_should_accept_a_single_nonarray_parameter
  104. Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success)
  105. assert @config.sessions.empty?
  106. @config.establish_connections_to(server("capistrano"))
  107. assert_equal ["capistrano"], @config.sessions.keys.map(&:host)
  108. end
  109. def test_establish_connections_to_should_accept_an_array
  110. Capistrano::SSH.expects(:connect).times(3).returns(:success)
  111. assert @config.sessions.empty?
  112. @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
  113. assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
  114. end
  115. def test_establish_connections_to_should_not_attempt_to_reestablish_existing_connections
  116. Capistrano::SSH.expects(:connect).times(2).returns(:success)
  117. @config.sessions[server("cap1")] = :ok
  118. @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
  119. assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
  120. end
  121. def test_establish_connections_to_should_raise_one_connection_error_on_failure
  122. Capistrano::SSH.expects(:connect).times(2).raises(Exception)
  123. assert_raises(Capistrano::ConnectionError) {
  124. @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
  125. }
  126. end
  127. def test_connection_error_should_include_accessor_with_host_array
  128. Capistrano::SSH.expects(:connect).times(2).raises(Exception)
  129. begin
  130. @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
  131. flunk "expected an exception to be raised"
  132. rescue Capistrano::ConnectionError => e
  133. assert e.respond_to?(:hosts)
  134. assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }.sort
  135. end
  136. end
  137. def test_connection_error_should_only_include_failed_hosts
  138. Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
  139. Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
  140. begin
  141. @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
  142. flunk "expected an exception to be raised"
  143. rescue Capistrano::ConnectionError => e
  144. assert_equal %w(cap1), e.hosts.map { |h| h.to_s }
  145. end
  146. end
  147. def test_execute_on_servers_should_require_a_block
  148. assert_raises(ArgumentError) { @config.execute_on_servers }
  149. end
  150. def test_execute_on_servers_without_current_task_should_call_find_servers
  151. list = [server("first"), server("second")]
  152. @config.expects(:find_servers).with(:a => :b, :c => :d).returns(list)
  153. @config.expects(:establish_connections_to).with(list).returns(:done)
  154. @config.execute_on_servers(:a => :b, :c => :d) do |result|
  155. assert_equal list, result
  156. end
  157. end
  158. def test_execute_on_servers_without_current_task_should_raise_error_if_no_matching_servers
  159. @config.expects(:find_servers).with(:a => :b, :c => :d).returns([])
  160. assert_raises(Capistrano::NoMatchingServersError) { @config.execute_on_servers(:a => :b, :c => :d) { |list| } }
  161. end
  162. def test_execute_on_servers_without_current_task_should_not_raise_error_if_no_matching_servers_and_continue_on_no_matching_servers
  163. @config.expects(:find_servers).with(:a => :b, :c => :d, :on_no_matching_servers => :continue).returns([])
  164. assert_nothing_raised { @config.execute_on_servers(:a => :b, :c => :d, :on_no_matching_servers => :continue) { |list| } }
  165. end
  166. def test_execute_on_servers_should_raise_an_error_if_the_current_task_has_no_matching_servers_by_default
  167. @config.current_task = mock_task
  168. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
  169. assert_raises(Capistrano::NoMatchingServersError) do
  170. @config.execute_on_servers do
  171. flunk "should not get here"
  172. end
  173. end
  174. end
  175. def test_execute_on_servers_should_not_raise_an_error_if_the_current_task_has_no_matching_servers_by_default_and_continue_on_no_matching_servers
  176. @config.current_task = mock_task(:on_no_matching_servers => :continue)
  177. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
  178. assert_nothing_raised do
  179. @config.execute_on_servers do
  180. flunk "should not get here"
  181. end
  182. end
  183. end
  184. def test_execute_on_servers_should_not_raise_an_error_if_the_current_task_has_no_matching_servers_by_default_and_command_continues_on_no_matching_servers
  185. @config.current_task = mock_task
  186. @config.expects(:find_servers_for_task).with(@config.current_task, :on_no_matching_servers => :continue).returns([])
  187. assert_nothing_raised do
  188. @config.execute_on_servers(:on_no_matching_servers => :continue) do
  189. flunk "should not get here"
  190. end
  191. end
  192. end
  193. def test_execute_on_servers_should_determine_server_list_from_active_task
  194. assert @config.sessions.empty?
  195. @config.current_task = mock_task
  196. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
  197. Capistrano::SSH.expects(:connect).times(3).returns(:success)
  198. @config.execute_on_servers {}
  199. assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
  200. end
  201. def test_execute_on_servers_should_yield_server_list_to_block
  202. assert @config.sessions.empty?
  203. @config.current_task = mock_task
  204. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
  205. Capistrano::SSH.expects(:connect).times(3).returns(:success)
  206. block_called = false
  207. @config.execute_on_servers do |servers|
  208. block_called = true
  209. assert servers.detect { |s| s.host == "cap1" }
  210. assert servers.detect { |s| s.host == "cap2" }
  211. assert servers.detect { |s| s.host == "cap3" }
  212. assert servers.all? { |s| @config.sessions[s] }
  213. end
  214. assert block_called
  215. end
  216. def test_execute_on_servers_with_once_option_should_establish_connection_to_and_yield_only_the_first_server
  217. assert @config.sessions.empty?
  218. @config.current_task = mock_task
  219. @config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
  220. Capistrano::SSH.expects(:connect).returns(:success)
  221. block_called = false
  222. @config.execute_on_servers(:once => true) do |servers|
  223. block_called = true
  224. assert_equal %w(cap1), servers.map { |s| s.host }
  225. end
  226. assert block_called
  227. assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
  228. end
  229. def test_execute_servers_should_raise_connection_error_on_failure_by_default
  230. @config.current_task = mock_task
  231. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
  232. Capistrano::SSH.expects(:connect).raises(Exception)
  233. assert_raises(Capistrano::ConnectionError) do
  234. @config.execute_on_servers do
  235. flunk "expected an exception to be raised"
  236. end
  237. end
  238. end
  239. def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
  240. @config.current_task = mock_task(:on_error => :continue)
  241. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2")])
  242. Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
  243. Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
  244. assert_nothing_raised {
  245. @config.execute_on_servers do |servers|
  246. assert_equal %w(cap2), servers.map { |s| s.host }
  247. end
  248. }
  249. end
  250. def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_errors_with_on_errors_continue
  251. list = [server("cap1"), server("cap2")]
  252. @config.current_task = mock_task(:on_error => :continue)
  253. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
  254. Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
  255. Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
  256. @config.execute_on_servers do |servers|
  257. assert_equal %w(cap2), servers.map { |s| s.host }
  258. end
  259. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
  260. @config.execute_on_servers do |servers|
  261. assert_equal %w(cap2), servers.map { |s| s.host }
  262. end
  263. end
  264. def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_errors_with_on_errors_continue
  265. cap1 = server("cap1")
  266. cap2 = server("cap2")
  267. @config.current_task = mock_task(:on_error => :continue)
  268. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  269. Capistrano::SSH.expects(:connect).times(2).returns(:success)
  270. @config.execute_on_servers do |servers|
  271. error = Capistrano::CommandError.new
  272. error.hosts = [cap1]
  273. raise error
  274. end
  275. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  276. @config.execute_on_servers do |servers|
  277. assert_equal %w(cap2), servers.map { |s| s.host }
  278. end
  279. end
  280. def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_errors_with_on_errors_continue
  281. cap1 = server("cap1")
  282. cap2 = server("cap2")
  283. @config.current_task = mock_task(:on_error => :continue)
  284. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  285. Capistrano::SSH.expects(:connect).times(2).returns(:success)
  286. @config.execute_on_servers do |servers|
  287. error = Capistrano::TransferError.new
  288. error.hosts = [cap1]
  289. raise error
  290. end
  291. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  292. @config.execute_on_servers do |servers|
  293. assert_equal %w(cap2), servers.map { |s| s.host }
  294. end
  295. end
  296. def test_connect_should_establish_connections_to_all_servers_in_scope
  297. assert @config.sessions.empty?
  298. @config.current_task = mock_task
  299. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
  300. Capistrano::SSH.expects(:connect).times(3).returns(:success)
  301. @config.connect!
  302. assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
  303. end
  304. def test_execute_on_servers_should_only_run_on_tasks_max_hosts_hosts_at_once
  305. cap1 = server("cap1")
  306. cap2 = server("cap2")
  307. connection1 = mock()
  308. connection2 = mock()
  309. connection1.expects(:close)
  310. connection2.expects(:close)
  311. @config.current_task = mock_task(:max_hosts => 1)
  312. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  313. Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
  314. block_called = 0
  315. @config.execute_on_servers do |servers|
  316. block_called += 1
  317. assert_equal 1, servers.size
  318. end
  319. assert_equal 2, block_called
  320. end
  321. def test_execute_on_servers_should_only_run_on_max_hosts_hosts_at_once
  322. cap1 = server("cap1")
  323. cap2 = server("cap2")
  324. connection1 = mock()
  325. connection2 = mock()
  326. connection1.expects(:close)
  327. connection2.expects(:close)
  328. @config.current_task = mock_task(:max_hosts => 1)
  329. @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
  330. Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
  331. block_called = 0
  332. @config.execute_on_servers do |servers|
  333. block_called += 1
  334. assert_equal 1, servers.size
  335. end
  336. assert_equal 2, block_called
  337. end
  338. def test_execute_on_servers_should_cope_with_already_dropped_connections_when_attempting_to_close_them
  339. cap1 = server("cap1")
  340. cap2 = server("cap2")
  341. connection1 = mock()
  342. connection2 = mock()
  343. connection3 = mock()
  344. connection4 = mock()
  345. connection1.expects(:close).raises(IOError)
  346. connection2.expects(:close)
  347. connection3.expects(:close)
  348. connection4.expects(:close)
  349. @config.current_task = mock_task(:max_hosts => 1)
  350. @config.expects(:find_servers_for_task).times(2).with(@config.current_task, {}).returns([cap1, cap2])
  351. Capistrano::SSH.expects(:connect).times(4).returns(connection1).then.returns(connection2).then.returns(connection3).then.returns(connection4)
  352. @config.execute_on_servers {}
  353. @config.execute_on_servers {}
  354. end
  355. def test_connect_should_honor_once_option
  356. assert @config.sessions.empty?
  357. @config.current_task = mock_task
  358. @config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
  359. Capistrano::SSH.expects(:connect).returns(:success)
  360. @config.connect! :once => true
  361. assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
  362. end
  363. private
  364. def mock_task(options={})
  365. continue_on_error = options[:on_error] == :continue
  366. stub("task",
  367. :fully_qualified_name => "name",
  368. :options => options,
  369. :continue_on_error? => continue_on_error,
  370. :max_hosts => options[:max_hosts]
  371. )
  372. end
  373. end