mbailey-capistrano 2.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. data/CHANGELOG.rdoc +761 -0
  2. data/Manifest +104 -0
  3. data/README.rdoc +66 -0
  4. data/Rakefile +34 -0
  5. data/bin/cap +4 -0
  6. data/bin/capify +78 -0
  7. data/examples/sample.rb +14 -0
  8. data/lib/capistrano/callback.rb +45 -0
  9. data/lib/capistrano/cli/execute.rb +84 -0
  10. data/lib/capistrano/cli/help.rb +125 -0
  11. data/lib/capistrano/cli/help.txt +75 -0
  12. data/lib/capistrano/cli/options.rb +224 -0
  13. data/lib/capistrano/cli/ui.rb +40 -0
  14. data/lib/capistrano/cli.rb +47 -0
  15. data/lib/capistrano/command.rb +283 -0
  16. data/lib/capistrano/configuration/actions/file_transfer.rb +47 -0
  17. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  18. data/lib/capistrano/configuration/actions/invocation.rb +293 -0
  19. data/lib/capistrano/configuration/callbacks.rb +148 -0
  20. data/lib/capistrano/configuration/connections.rb +200 -0
  21. data/lib/capistrano/configuration/execution.rb +132 -0
  22. data/lib/capistrano/configuration/loading.rb +197 -0
  23. data/lib/capistrano/configuration/namespaces.rb +197 -0
  24. data/lib/capistrano/configuration/roles.rb +73 -0
  25. data/lib/capistrano/configuration/servers.rb +85 -0
  26. data/lib/capistrano/configuration/variables.rb +127 -0
  27. data/lib/capistrano/configuration.rb +43 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +57 -0
  30. data/lib/capistrano/logger.rb +59 -0
  31. data/lib/capistrano/processable.rb +53 -0
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  34. data/lib/capistrano/recipes/deploy/local_dependency.rb +54 -0
  35. data/lib/capistrano/recipes/deploy/remote_dependency.rb +105 -0
  36. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  37. data/lib/capistrano/recipes/deploy/scm/base.rb +196 -0
  38. data/lib/capistrano/recipes/deploy/scm/bzr.rb +83 -0
  39. data/lib/capistrano/recipes/deploy/scm/cvs.rb +152 -0
  40. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  41. data/lib/capistrano/recipes/deploy/scm/git.rb +271 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +137 -0
  43. data/lib/capistrano/recipes/deploy/scm/none.rb +44 -0
  44. data/lib/capistrano/recipes/deploy/scm/perforce.rb +133 -0
  45. data/lib/capistrano/recipes/deploy/scm/subversion.rb +121 -0
  46. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  47. data/lib/capistrano/recipes/deploy/strategy/base.rb +79 -0
  48. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  49. data/lib/capistrano/recipes/deploy/strategy/copy.rb +210 -0
  50. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  52. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +56 -0
  53. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  54. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  55. data/lib/capistrano/recipes/deploy.rb +562 -0
  56. data/lib/capistrano/recipes/standard.rb +37 -0
  57. data/lib/capistrano/recipes/templates/maintenance.rhtml +53 -0
  58. data/lib/capistrano/recipes/upgrade.rb +33 -0
  59. data/lib/capistrano/role.rb +102 -0
  60. data/lib/capistrano/server_definition.rb +56 -0
  61. data/lib/capistrano/shell.rb +260 -0
  62. data/lib/capistrano/ssh.rb +99 -0
  63. data/lib/capistrano/task_definition.rb +70 -0
  64. data/lib/capistrano/transfer.rb +216 -0
  65. data/lib/capistrano/version.rb +18 -0
  66. data/lib/capistrano.rb +2 -0
  67. data/setup.rb +1346 -0
  68. data/test/cli/execute_test.rb +132 -0
  69. data/test/cli/help_test.rb +165 -0
  70. data/test/cli/options_test.rb +317 -0
  71. data/test/cli/ui_test.rb +28 -0
  72. data/test/cli_test.rb +17 -0
  73. data/test/command_test.rb +286 -0
  74. data/test/configuration/actions/file_transfer_test.rb +61 -0
  75. data/test/configuration/actions/inspect_test.rb +65 -0
  76. data/test/configuration/actions/invocation_test.rb +224 -0
  77. data/test/configuration/callbacks_test.rb +220 -0
  78. data/test/configuration/connections_test.rb +349 -0
  79. data/test/configuration/execution_test.rb +175 -0
  80. data/test/configuration/loading_test.rb +132 -0
  81. data/test/configuration/namespace_dsl_test.rb +311 -0
  82. data/test/configuration/roles_test.rb +144 -0
  83. data/test/configuration/servers_test.rb +121 -0
  84. data/test/configuration/variables_test.rb +184 -0
  85. data/test/configuration_test.rb +88 -0
  86. data/test/deploy/local_dependency_test.rb +76 -0
  87. data/test/deploy/remote_dependency_test.rb +114 -0
  88. data/test/deploy/scm/accurev_test.rb +23 -0
  89. data/test/deploy/scm/base_test.rb +55 -0
  90. data/test/deploy/scm/git_test.rb +167 -0
  91. data/test/deploy/scm/mercurial_test.rb +129 -0
  92. data/test/deploy/strategy/copy_test.rb +258 -0
  93. data/test/extensions_test.rb +69 -0
  94. data/test/fixtures/cli_integration.rb +5 -0
  95. data/test/fixtures/config.rb +5 -0
  96. data/test/fixtures/custom.rb +3 -0
  97. data/test/logger_test.rb +123 -0
  98. data/test/role_test.rb +11 -0
  99. data/test/server_definition_test.rb +121 -0
  100. data/test/shell_test.rb +90 -0
  101. data/test/ssh_test.rb +104 -0
  102. data/test/task_definition_test.rb +101 -0
  103. data/test/transfer_test.rb +160 -0
  104. data/test/utils.rb +38 -0
  105. metadata +205 -0
@@ -0,0 +1,220 @@
1
+ require "utils"
2
+ require 'capistrano/configuration/callbacks'
3
+
4
+ class ConfigurationCallbacksTest < Test::Unit::TestCase
5
+ class MockConfig
6
+ attr_reader :original_initialize_called
7
+ attr_reader :called
8
+
9
+ def initialize
10
+ @original_initialize_called = true
11
+ @called = []
12
+ end
13
+
14
+ def execute_task(task)
15
+ invoke_task_directly(task)
16
+ end
17
+
18
+ protected
19
+
20
+ def invoke_task_directly(task)
21
+ @called << task
22
+ end
23
+
24
+ include Capistrano::Configuration::Callbacks
25
+ end
26
+
27
+ def setup
28
+ @config = MockConfig.new
29
+ @config.stubs(:logger).returns(stub_everything("logger"))
30
+ end
31
+
32
+ def test_initialize_should_initialize_callbacks_collection
33
+ assert @config.original_initialize_called
34
+ assert @config.callbacks.empty?
35
+ end
36
+
37
+ def test_before_should_delegate_to_on
38
+ @config.expects(:on).with(:before, :foo, "bing:blang", {:only => :bar, :zip => :zing})
39
+ @config.before :bar, :foo, "bing:blang", :zip => :zing
40
+ end
41
+
42
+ def test_after_should_delegate_to_on
43
+ @config.expects(:on).with(:after, :foo, "bing:blang", {:only => :bar, :zip => :zing})
44
+ @config.after :bar, :foo, "bing:blang", :zip => :zing
45
+ end
46
+
47
+ def test_on_with_single_reference_should_add_task_callback
48
+ @config.on :before, :a_test
49
+ assert_equal 1, @config.callbacks[:before].length
50
+ assert_equal :a_test, @config.callbacks[:before][0].source
51
+ @config.expects(:find_and_execute_task).with(:a_test)
52
+ @config.callbacks[:before][0].call
53
+ end
54
+
55
+ def test_on_with_multi_reference_should_add_all_as_task_callback
56
+ @config.on :before, :first, :second, :third
57
+ assert_equal 3, @config.callbacks[:before].length
58
+ assert_equal %w(first second third), @config.callbacks[:before].map { |c| c.source.to_s }
59
+ end
60
+
61
+ def test_on_with_block_should_add_block_as_proc_callback
62
+ called = false
63
+ @config.on(:before) { called = true }
64
+ assert_equal 1, @config.callbacks[:before].length
65
+ assert_instance_of Proc, @config.callbacks[:before][0].source
66
+ @config.callbacks[:before][0].call
67
+ assert called
68
+ end
69
+
70
+ def test_on_with_single_only_should_set_only_as_string_array_on_all_references
71
+ @config.on :before, :first, "second:third", :only => :primary
72
+ assert_equal 2, @config.callbacks[:before].length
73
+ assert @config.callbacks[:before].all? { |c| c.only == %w(primary) }
74
+ end
75
+
76
+ def test_on_with_multi_only_should_set_only_as_string_array_on_all_references
77
+ @config.on :before, :first, "second:third", :only => [:primary, "other:one"]
78
+ assert_equal 2, @config.callbacks[:before].length
79
+ assert @config.callbacks[:before].all? { |c| c.only == %w(primary other:one) }
80
+ end
81
+
82
+ def test_on_with_single_except_should_set_except_as_string_array_on_all_references
83
+ @config.on :before, :first, "second:third", :except => :primary
84
+ assert_equal 2, @config.callbacks[:before].length
85
+ assert @config.callbacks[:before].all? { |c| c.except == %w(primary) }
86
+ end
87
+
88
+ def test_on_with_multi_except_should_set_except_as_string_array_on_all_references
89
+ @config.on :before, :first, "second:third", :except => [:primary, "other:one"]
90
+ assert_equal 2, @config.callbacks[:before].length
91
+ assert @config.callbacks[:before].all? { |c| c.except == %w(primary other:one) }
92
+ end
93
+
94
+ def test_on_with_only_and_block_should_set_only_as_string_array
95
+ @config.on(:before, :only => :primary) { blah }
96
+ assert_equal 1, @config.callbacks[:before].length
97
+ assert_equal %w(primary), @config.callbacks[:before].first.only
98
+ end
99
+
100
+ def test_on_with_except_and_block_should_set_except_as_string_array
101
+ @config.on(:before, :except => :primary) { blah }
102
+ assert_equal 1, @config.callbacks[:before].length
103
+ assert_equal %w(primary), @config.callbacks[:before].first.except
104
+ end
105
+
106
+ def test_on_without_tasks_or_block_should_raise_error
107
+ assert_raises(ArgumentError) { @config.on(:before) }
108
+ end
109
+
110
+ def test_on_with_both_tasks_and_block_should_raise_error
111
+ assert_raises(ArgumentError) { @config.on(:before, :first) { blah } }
112
+ end
113
+
114
+ def test_trigger_without_constraints_should_invoke_all_callbacks
115
+ task = stub(:fully_qualified_name => "any:old:thing")
116
+ @config.on(:before, :first, "second:third")
117
+ @config.on(:after, :another, "and:another")
118
+ @config.expects(:find_and_execute_task).with(:first)
119
+ @config.expects(:find_and_execute_task).with("second:third")
120
+ @config.expects(:find_and_execute_task).with(:another).never
121
+ @config.expects(:find_and_execute_task).with("and:another").never
122
+ @config.trigger(:before, task)
123
+ end
124
+
125
+ def test_trigger_with_only_constraint_should_invoke_only_matching_callbacks
126
+ task = stub(:fully_qualified_name => "any:old:thing")
127
+ @config.on(:before, :first)
128
+ @config.on(:before, "second:third", :only => "any:old:thing")
129
+ @config.on(:before, "this:too", :only => "any:other:thing")
130
+ @config.on(:after, :another, "and:another")
131
+ @config.expects(:find_and_execute_task).with(:first)
132
+ @config.expects(:find_and_execute_task).with("second:third")
133
+ @config.expects(:find_and_execute_task).with("this:too").never
134
+ @config.expects(:find_and_execute_task).with(:another).never
135
+ @config.expects(:find_and_execute_task).with("and:another").never
136
+ @config.trigger(:before, task)
137
+ end
138
+
139
+ def test_trigger_with_except_constraint_should_invoke_anything_but_matching_callbacks
140
+ task = stub(:fully_qualified_name => "any:old:thing")
141
+ @config.on(:before, :first)
142
+ @config.on(:before, "second:third", :except => "any:old:thing")
143
+ @config.on(:before, "this:too", :except => "any:other:thing")
144
+ @config.on(:after, :another, "and:another")
145
+ @config.expects(:find_and_execute_task).with(:first)
146
+ @config.expects(:find_and_execute_task).with("second:third").never
147
+ @config.expects(:find_and_execute_task).with("this:too")
148
+ @config.expects(:find_and_execute_task).with(:another).never
149
+ @config.expects(:find_and_execute_task).with("and:another").never
150
+ @config.trigger(:before, task)
151
+ end
152
+
153
+ def test_trigger_without_task_should_invoke_all_callbacks_for_that_event
154
+ task = stub(:fully_qualified_name => "any:old:thing")
155
+ @config.on(:before, :first)
156
+ @config.on(:before, "second:third", :except => "any:old:thing")
157
+ @config.on(:before, "this:too", :except => "any:other:thing")
158
+ @config.on(:after, :another, "and:another")
159
+ @config.expects(:find_and_execute_task).with(:first)
160
+ @config.expects(:find_and_execute_task).with("second:third")
161
+ @config.expects(:find_and_execute_task).with("this:too")
162
+ @config.expects(:find_and_execute_task).with(:another).never
163
+ @config.expects(:find_and_execute_task).with("and:another").never
164
+ @config.trigger(:before)
165
+ end
166
+
167
+ def test_execute_task_without_named_hooks_should_just_call_task
168
+ ns = stub("namespace", :default_task => nil, :name => "old", :fully_qualified_name => "any:old")
169
+ task = stub(:fully_qualified_name => "any:old:thing", :name => "thing", :namespace => ns)
170
+
171
+ ns.stubs(:search_task).returns(nil)
172
+
173
+ @config.execute_task(task)
174
+ assert_equal [task], @config.called
175
+ end
176
+
177
+ def test_execute_task_with_named_before_hook_should_call_named_before_hook
178
+ ns = stub("namespace", :default_task => nil, :name => "old", :fully_qualified_name => "any:old")
179
+ task = stub(:fully_qualified_name => "any:old:thing", :name => "thing", :namespace => ns)
180
+ before_task = stub(:fully_qualified_name => "any:old:before_thing", :name => "before_thing", :namespace => ns)
181
+
182
+ ns.stubs(:search_task).returns(nil)
183
+ ns.expects(:search_task).with("before_thing").returns(before_task)
184
+
185
+ @config.execute_task(task)
186
+ assert_equal [before_task, task], @config.called
187
+ end
188
+
189
+ def test_execute_task_with_named_after_hook_should_call_named_after_hook
190
+ ns = stub("namespace", :default_task => nil, :name => "old", :fully_qualified_name => "any:old")
191
+ task = stub(:fully_qualified_name => "any:old:thing", :name => "thing", :namespace => ns)
192
+ after_task = stub(:fully_qualified_name => "any:old:after_thing", :name => "after_thing", :namespace => ns)
193
+
194
+ ns.stubs(:search_task).returns(nil)
195
+ ns.expects(:search_task).with("after_thing").returns(after_task)
196
+
197
+ @config.execute_task(task)
198
+ assert_equal [task, after_task], @config.called
199
+ end
200
+
201
+ def test_execute_task_with_on_hooks_should_trigger_hooks_around_task
202
+ ns = stub("namespace", :default_task => nil, :name => "old", :fully_qualified_name => "any:old")
203
+ task = stub(:fully_qualified_name => "any:old:thing", :name => "thing", :namespace => ns)
204
+ before_task = stub(:fully_qualified_name => "any:old:before_thing", :name => "before_thing", :namespace => ns)
205
+ after_task = stub(:fully_qualified_name => "any:old:after_thing", :name => "after_thing", :namespace => ns)
206
+
207
+ ns.stubs(:search_task).returns(nil)
208
+ ns.expects(:search_task).with("before_thing").returns(before_task)
209
+ ns.expects(:search_task).with("after_thing").returns(after_task)
210
+
211
+ @config.before("any:old:thing", :first_this, :then_this)
212
+ @config.after("any:old:thing", :and_then_this, :lastly_this)
213
+
214
+ [:first_this, :then_this, :and_then_this, :lastly_this].each do |t|
215
+ @config.expects(:find_and_execute_task).with(t)
216
+ end
217
+
218
+ @config.execute_task(task)
219
+ end
220
+ end
@@ -0,0 +1,349 @@
1
+ require "utils"
2
+ require 'capistrano/configuration/connections'
3
+
4
+ class ConfigurationConnectionsTest < Test::Unit::TestCase
5
+ class MockConfig
6
+ attr_reader :original_initialize_called
7
+ attr_reader :values
8
+ attr_accessor :current_task
9
+
10
+ def initialize
11
+ @original_initialize_called = true
12
+ @values = {}
13
+ end
14
+
15
+ def fetch(*args)
16
+ @values.fetch(*args)
17
+ end
18
+
19
+ def [](key)
20
+ @values[key]
21
+ end
22
+
23
+ def exists?(key)
24
+ @values.key?(key)
25
+ end
26
+
27
+ include Capistrano::Configuration::Connections
28
+ end
29
+
30
+ def setup
31
+ @config = MockConfig.new
32
+ @config.stubs(:logger).returns(stub_everything)
33
+ Net::SSH.stubs(:configuration_for).returns({})
34
+ @ssh_options = {
35
+ :user => "user",
36
+ :port => 8080,
37
+ :password => "g00b3r",
38
+ :ssh_options => { :debug => :verbose }
39
+ }
40
+ end
41
+
42
+ def test_initialize_should_initialize_collections_and_call_original_initialize
43
+ assert @config.original_initialize_called
44
+ assert @config.sessions.empty?
45
+ end
46
+
47
+ def test_connection_factory_should_return_default_connection_factory_instance
48
+ factory = @config.connection_factory
49
+ assert_instance_of Capistrano::Configuration::Connections::DefaultConnectionFactory, factory
50
+ end
51
+
52
+ def test_connection_factory_instance_should_be_cached
53
+ assert_same @config.connection_factory, @config.connection_factory
54
+ end
55
+
56
+ def test_default_connection_factory_honors_config_options
57
+ server = server("capistrano")
58
+ Capistrano::SSH.expects(:connect).with(server, @config).returns(:session)
59
+ assert_equal :session, @config.connection_factory.connect_to(server)
60
+ end
61
+
62
+ def test_should_connect_through_gateway_if_gateway_variable_is_set
63
+ @config.values[:gateway] = "j@gateway"
64
+ Net::SSH::Gateway.expects(:new).with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
65
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
66
+ end
67
+
68
+ def test_connection_factory_as_gateway_should_honor_config_options
69
+ @config.values[:gateway] = "gateway"
70
+ @config.values.update(@ssh_options)
71
+ Net::SSH::Gateway.expects(:new).with("gateway", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
72
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
73
+ end
74
+
75
+ def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_an_array
76
+ @config.values[:gateway] = ["j@gateway1", "k@gateway2"]
77
+ gateway1 = mock
78
+ Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(gateway1)
79
+ gateway1.expects(:open).returns(65535)
80
+ 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)
81
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
82
+ end
83
+
84
+ def test_connection_factory_as_gateway_should_share_gateway_between_connections
85
+ @config.values[:gateway] = "j@gateway"
86
+ Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
87
+ Capistrano::SSH.stubs(:connect).returns(stub_everything)
88
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
89
+ @config.establish_connections_to(server("capistrano"))
90
+ @config.establish_connections_to(server("another"))
91
+ end
92
+
93
+ def test_establish_connections_to_should_accept_a_single_nonarray_parameter
94
+ Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success)
95
+ assert @config.sessions.empty?
96
+ @config.establish_connections_to(server("capistrano"))
97
+ assert ["capistrano"], @config.sessions.keys
98
+ end
99
+
100
+ def test_establish_connections_to_should_accept_an_array
101
+ Capistrano::SSH.expects(:connect).times(3).returns(:success)
102
+ assert @config.sessions.empty?
103
+ @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
104
+ assert %w(cap1 cap2 cap3), @config.sessions.keys.sort
105
+ end
106
+
107
+ def test_establish_connections_to_should_not_attempt_to_reestablish_existing_connections
108
+ Capistrano::SSH.expects(:connect).times(2).returns(:success)
109
+ @config.sessions[server("cap1")] = :ok
110
+ @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
111
+ assert %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
112
+ end
113
+
114
+ def test_establish_connections_to_should_raise_one_connection_error_on_failure
115
+ Capistrano::SSH.expects(:connect).times(2).raises(Exception)
116
+ assert_raises(Capistrano::ConnectionError) {
117
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
118
+ }
119
+ end
120
+
121
+ def test_connection_error_should_include_accessor_with_host_array
122
+ Capistrano::SSH.expects(:connect).times(2).raises(Exception)
123
+
124
+ begin
125
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
126
+ flunk "expected an exception to be raised"
127
+ rescue Capistrano::ConnectionError => e
128
+ assert e.respond_to?(:hosts)
129
+ assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }.sort
130
+ end
131
+ end
132
+
133
+ def test_connection_error_should_only_include_failed_hosts
134
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
135
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
136
+
137
+ begin
138
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
139
+ flunk "expected an exception to be raised"
140
+ rescue Capistrano::ConnectionError => e
141
+ assert_equal %w(cap1), e.hosts.map { |h| h.to_s }
142
+ end
143
+ end
144
+
145
+ def test_execute_on_servers_should_require_a_block
146
+ assert_raises(ArgumentError) { @config.execute_on_servers }
147
+ end
148
+
149
+ def test_execute_on_servers_without_current_task_should_call_find_servers
150
+ list = [server("first"), server("second")]
151
+ @config.expects(:find_servers).with(:a => :b, :c => :d).returns(list)
152
+ @config.expects(:establish_connections_to).with(list).returns(:done)
153
+ @config.execute_on_servers(:a => :b, :c => :d) do |result|
154
+ assert_equal list, result
155
+ end
156
+ end
157
+
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
+
163
+ def test_execute_on_servers_should_raise_an_error_if_the_current_task_has_no_matching_servers_by_default
164
+ @config.current_task = mock_task
165
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
166
+ assert_raises(Capistrano::NoMatchingServersError) do
167
+ @config.execute_on_servers do
168
+ flunk "should not get here"
169
+ end
170
+ end
171
+ end
172
+
173
+ def test_execute_on_servers_should_determine_server_list_from_active_task
174
+ assert @config.sessions.empty?
175
+ @config.current_task = mock_task
176
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
177
+ Capistrano::SSH.expects(:connect).times(3).returns(:success)
178
+ @config.execute_on_servers {}
179
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
180
+ end
181
+
182
+ def test_execute_on_servers_should_yield_server_list_to_block
183
+ assert @config.sessions.empty?
184
+ @config.current_task = mock_task
185
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
186
+ Capistrano::SSH.expects(:connect).times(3).returns(:success)
187
+ block_called = false
188
+ @config.execute_on_servers do |servers|
189
+ block_called = true
190
+ assert servers.detect { |s| s.host == "cap1" }
191
+ assert servers.detect { |s| s.host == "cap2" }
192
+ assert servers.detect { |s| s.host == "cap3" }
193
+ assert servers.all? { |s| @config.sessions[s] }
194
+ end
195
+ assert block_called
196
+ end
197
+
198
+ def test_execute_on_servers_with_once_option_should_establish_connection_to_and_yield_only_the_first_server
199
+ assert @config.sessions.empty?
200
+ @config.current_task = mock_task
201
+ @config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
202
+ Capistrano::SSH.expects(:connect).returns(:success)
203
+ block_called = false
204
+ @config.execute_on_servers(:once => true) do |servers|
205
+ block_called = true
206
+ assert_equal %w(cap1), servers.map { |s| s.host }
207
+ end
208
+ assert block_called
209
+ assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
210
+ end
211
+
212
+ def test_execute_servers_should_raise_connection_error_on_failure_by_default
213
+ @config.current_task = mock_task
214
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
215
+ Capistrano::SSH.expects(:connect).raises(Exception)
216
+ assert_raises(Capistrano::ConnectionError) do
217
+ @config.execute_on_servers do
218
+ flunk "expected an exception to be raised"
219
+ end
220
+ end
221
+ end
222
+
223
+ def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
224
+ @config.current_task = mock_task(:on_error => :continue)
225
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2")])
226
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
227
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
228
+ assert_nothing_raised {
229
+ @config.execute_on_servers do |servers|
230
+ assert_equal %w(cap2), servers.map { |s| s.host }
231
+ end
232
+ }
233
+ end
234
+
235
+ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_errors_with_on_errors_continue
236
+ list = [server("cap1"), server("cap2")]
237
+ @config.current_task = mock_task(:on_error => :continue)
238
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
239
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
240
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
241
+ @config.execute_on_servers do |servers|
242
+ assert_equal %w(cap2), servers.map { |s| s.host }
243
+ end
244
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
245
+ @config.execute_on_servers do |servers|
246
+ assert_equal %w(cap2), servers.map { |s| s.host }
247
+ end
248
+ end
249
+
250
+ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_errors_with_on_errors_continue
251
+ cap1 = server("cap1")
252
+ cap2 = server("cap2")
253
+ @config.current_task = mock_task(:on_error => :continue)
254
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
255
+ Capistrano::SSH.expects(:connect).times(2).returns(:success)
256
+ @config.execute_on_servers do |servers|
257
+ error = Capistrano::CommandError.new
258
+ error.hosts = [cap1]
259
+ raise error
260
+ end
261
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
262
+ @config.execute_on_servers do |servers|
263
+ assert_equal %w(cap2), servers.map { |s| s.host }
264
+ end
265
+ end
266
+
267
+ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_errors_with_on_errors_continue
268
+ cap1 = server("cap1")
269
+ cap2 = server("cap2")
270
+ @config.current_task = mock_task(:on_error => :continue)
271
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
272
+ Capistrano::SSH.expects(:connect).times(2).returns(:success)
273
+ @config.execute_on_servers do |servers|
274
+ error = Capistrano::TransferError.new
275
+ error.hosts = [cap1]
276
+ raise error
277
+ end
278
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
279
+ @config.execute_on_servers do |servers|
280
+ assert_equal %w(cap2), servers.map { |s| s.host }
281
+ end
282
+ end
283
+
284
+ def test_connect_should_establish_connections_to_all_servers_in_scope
285
+ assert @config.sessions.empty?
286
+ @config.current_task = mock_task
287
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
288
+ Capistrano::SSH.expects(:connect).times(3).returns(:success)
289
+ @config.connect!
290
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
291
+ end
292
+
293
+ def test_execute_on_servers_should_only_run_on_tasks_max_hosts_hosts_at_once
294
+ cap1 = server("cap1")
295
+ cap2 = server("cap2")
296
+ connection1 = mock()
297
+ connection2 = mock()
298
+ connection1.expects(:close)
299
+ connection2.expects(:close)
300
+ @config.current_task = mock_task(:max_hosts => 1)
301
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
302
+ Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
303
+ block_called = 0
304
+ @config.execute_on_servers do |servers|
305
+ block_called += 1
306
+ assert_equal 1, servers.size
307
+ end
308
+ assert_equal 2, block_called
309
+ end
310
+
311
+ def test_execute_on_servers_should_only_run_on_max_hosts_hosts_at_once
312
+ cap1 = server("cap1")
313
+ cap2 = server("cap2")
314
+ connection1 = mock()
315
+ connection2 = mock()
316
+ connection1.expects(:close)
317
+ connection2.expects(:close)
318
+ @config.current_task = mock_task(:max_hosts => 1)
319
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
320
+ Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
321
+ block_called = 0
322
+ @config.execute_on_servers do |servers|
323
+ block_called += 1
324
+ assert_equal 1, servers.size
325
+ end
326
+ assert_equal 2, block_called
327
+ end
328
+
329
+ def test_connect_should_honor_once_option
330
+ assert @config.sessions.empty?
331
+ @config.current_task = mock_task
332
+ @config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
333
+ Capistrano::SSH.expects(:connect).returns(:success)
334
+ @config.connect! :once => true
335
+ assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
336
+ end
337
+
338
+ private
339
+
340
+ def mock_task(options={})
341
+ continue_on_error = options[:on_error] == :continue
342
+ stub("task",
343
+ :fully_qualified_name => "name",
344
+ :options => options,
345
+ :continue_on_error? => continue_on_error,
346
+ :max_hosts => options[:max_hosts]
347
+ )
348
+ end
349
+ end