capistrano 2.0.0 → 2.15.2

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 (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +715 -18
  5. data/Gemfile +12 -0
  6. data/README.md +94 -0
  7. data/Rakefile +11 -0
  8. data/bin/cap +0 -0
  9. data/bin/capify +37 -22
  10. data/capistrano.gemspec +40 -0
  11. data/lib/capistrano/callback.rb +5 -1
  12. data/lib/capistrano/cli/execute.rb +10 -7
  13. data/lib/capistrano/cli/help.rb +39 -16
  14. data/lib/capistrano/cli/help.txt +44 -16
  15. data/lib/capistrano/cli/options.rb +71 -11
  16. data/lib/capistrano/cli/ui.rb +13 -1
  17. data/lib/capistrano/cli.rb +5 -5
  18. data/lib/capistrano/command.rb +215 -58
  19. data/lib/capistrano/configuration/actions/file_transfer.rb +29 -14
  20. data/lib/capistrano/configuration/actions/inspect.rb +3 -3
  21. data/lib/capistrano/configuration/actions/invocation.rb +212 -22
  22. data/lib/capistrano/configuration/alias_task.rb +26 -0
  23. data/lib/capistrano/configuration/callbacks.rb +26 -27
  24. data/lib/capistrano/configuration/connections.rb +130 -52
  25. data/lib/capistrano/configuration/execution.rb +34 -18
  26. data/lib/capistrano/configuration/loading.rb +91 -6
  27. data/lib/capistrano/configuration/log_formatters.rb +75 -0
  28. data/lib/capistrano/configuration/namespaces.rb +45 -12
  29. data/lib/capistrano/configuration/roles.rb +28 -2
  30. data/lib/capistrano/configuration/servers.rb +51 -10
  31. data/lib/capistrano/configuration/variables.rb +3 -3
  32. data/lib/capistrano/configuration.rb +20 -4
  33. data/lib/capistrano/errors.rb +12 -8
  34. data/lib/capistrano/ext/multistage.rb +62 -0
  35. data/lib/capistrano/ext/string.rb +5 -0
  36. data/lib/capistrano/extensions.rb +1 -1
  37. data/lib/capistrano/fix_rake_deprecated_dsl.rb +8 -0
  38. data/lib/capistrano/logger.rb +112 -5
  39. data/lib/capistrano/processable.rb +55 -0
  40. data/lib/capistrano/recipes/compat.rb +2 -2
  41. data/lib/capistrano/recipes/deploy/assets.rb +185 -0
  42. data/lib/capistrano/recipes/deploy/dependencies.rb +2 -2
  43. data/lib/capistrano/recipes/deploy/local_dependency.rb +10 -2
  44. data/lib/capistrano/recipes/deploy/remote_dependency.rb +54 -2
  45. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  46. data/lib/capistrano/recipes/deploy/scm/base.rb +31 -11
  47. data/lib/capistrano/recipes/deploy/scm/bzr.rb +14 -14
  48. data/lib/capistrano/recipes/deploy/scm/cvs.rb +10 -8
  49. data/lib/capistrano/recipes/deploy/scm/darcs.rb +12 -1
  50. data/lib/capistrano/recipes/deploy/scm/git.rb +293 -0
  51. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +23 -15
  52. data/lib/capistrano/recipes/deploy/scm/none.rb +55 -0
  53. data/lib/capistrano/recipes/deploy/scm/perforce.rb +54 -28
  54. data/lib/capistrano/recipes/deploy/scm/subversion.rb +35 -17
  55. data/lib/capistrano/recipes/deploy/scm.rb +1 -1
  56. data/lib/capistrano/recipes/deploy/strategy/base.rb +32 -4
  57. data/lib/capistrano/recipes/deploy/strategy/copy.rb +238 -43
  58. data/lib/capistrano/recipes/deploy/strategy/remote.rb +1 -1
  59. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +11 -1
  60. data/lib/capistrano/recipes/deploy/strategy/unshared_remote_cache.rb +21 -0
  61. data/lib/capistrano/recipes/deploy/strategy.rb +1 -1
  62. data/lib/capistrano/recipes/deploy.rb +265 -123
  63. data/lib/capistrano/recipes/standard.rb +1 -1
  64. data/lib/capistrano/role.rb +102 -0
  65. data/lib/capistrano/server_definition.rb +6 -1
  66. data/lib/capistrano/shell.rb +30 -33
  67. data/lib/capistrano/ssh.rb +46 -60
  68. data/lib/capistrano/task_definition.rb +16 -8
  69. data/lib/capistrano/transfer.rb +218 -0
  70. data/lib/capistrano/version.rb +6 -17
  71. data/lib/capistrano.rb +4 -1
  72. data/test/cli/execute_test.rb +3 -3
  73. data/test/cli/help_test.rb +33 -7
  74. data/test/cli/options_test.rb +109 -6
  75. data/test/cli/ui_test.rb +2 -2
  76. data/test/cli_test.rb +3 -3
  77. data/test/command_test.rb +144 -124
  78. data/test/configuration/actions/file_transfer_test.rb +41 -20
  79. data/test/configuration/actions/inspect_test.rb +21 -7
  80. data/test/configuration/actions/invocation_test.rb +91 -30
  81. data/test/configuration/alias_task_test.rb +118 -0
  82. data/test/configuration/callbacks_test.rb +41 -46
  83. data/test/configuration/connections_test.rb +187 -36
  84. data/test/configuration/execution_test.rb +18 -2
  85. data/test/configuration/loading_test.rb +17 -4
  86. data/test/configuration/namespace_dsl_test.rb +54 -5
  87. data/test/configuration/roles_test.rb +114 -4
  88. data/test/configuration/servers_test.rb +97 -4
  89. data/test/configuration/variables_test.rb +12 -2
  90. data/test/configuration_test.rb +9 -13
  91. data/test/deploy/local_dependency_test.rb +76 -0
  92. data/test/deploy/remote_dependency_test.rb +146 -0
  93. data/test/deploy/scm/accurev_test.rb +23 -0
  94. data/test/deploy/scm/base_test.rb +1 -1
  95. data/test/deploy/scm/bzr_test.rb +51 -0
  96. data/test/deploy/scm/darcs_test.rb +37 -0
  97. data/test/deploy/scm/git_test.rb +221 -0
  98. data/test/deploy/scm/mercurial_test.rb +134 -0
  99. data/test/deploy/scm/none_test.rb +35 -0
  100. data/test/deploy/scm/perforce_test.rb +23 -0
  101. data/test/deploy/scm/subversion_test.rb +40 -0
  102. data/test/deploy/strategy/copy_test.rb +240 -26
  103. data/test/extensions_test.rb +2 -2
  104. data/test/logger_formatting_test.rb +149 -0
  105. data/test/logger_test.rb +13 -2
  106. data/test/recipes_test.rb +25 -0
  107. data/test/role_test.rb +11 -0
  108. data/test/server_definition_test.rb +15 -2
  109. data/test/shell_test.rb +33 -1
  110. data/test/ssh_test.rb +40 -24
  111. data/test/task_definition_test.rb +18 -2
  112. data/test/transfer_test.rb +168 -0
  113. data/test/utils.rb +27 -33
  114. metadata +215 -102
  115. data/MIT-LICENSE +0 -20
  116. data/README +0 -43
  117. data/examples/sample.rb +0 -14
  118. data/lib/capistrano/gateway.rb +0 -131
  119. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
  120. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  121. data/lib/capistrano/recipes/upgrade.rb +0 -33
  122. data/lib/capistrano/upload.rb +0 -146
  123. data/test/gateway_test.rb +0 -167
  124. data/test/upload_test.rb +0 -131
  125. data/test/version_test.rb +0 -24
@@ -1,10 +1,11 @@
1
- require "#{File.dirname(__FILE__)}/../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/connections'
3
3
 
4
4
  class ConfigurationConnectionsTest < Test::Unit::TestCase
5
5
  class MockConfig
6
6
  attr_reader :original_initialize_called
7
7
  attr_reader :values
8
+ attr_reader :dry_run
8
9
  attr_accessor :current_task
9
10
 
10
11
  def initialize
@@ -30,8 +31,9 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
30
31
  def setup
31
32
  @config = MockConfig.new
32
33
  @config.stubs(:logger).returns(stub_everything)
34
+ Net::SSH.stubs(:configuration_for).returns({})
33
35
  @ssh_options = {
34
- :user => "jamis",
36
+ :user => "user",
35
37
  :port => 8080,
36
38
  :password => "g00b3r",
37
39
  :ssh_options => { :debug => :verbose }
@@ -58,65 +60,111 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
58
60
  assert_equal :session, @config.connection_factory.connect_to(server)
59
61
  end
60
62
 
61
- def test_connection_factory_should_return_gateway_instance_if_gateway_variable_is_set
62
- @config.values[:gateway] = "capistrano"
63
- server = server("capistrano")
64
- Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.yields(stub_everything)
65
- assert_instance_of Capistrano::Gateway, @config.connection_factory
63
+ def test_should_connect_through_gateway_if_gateway_variable_is_set
64
+ @config.values[:gateway] = "j@gateway"
65
+ Net::SSH::Gateway.expects(:new).with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
66
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
66
67
  end
67
68
 
68
69
  def test_connection_factory_as_gateway_should_honor_config_options
69
- @config.values[:gateway] = "capistrano"
70
+ @config.values[:gateway] = "gateway"
70
71
  @config.values.update(@ssh_options)
71
- Capistrano::SSH.expects(:connect).with { |s,opts| s.host == "capistrano" && opts == @config }.yields(stub_everything)
72
- assert_instance_of Capistrano::Gateway, @config.connection_factory
72
+ Net::SSH::Gateway.expects(:new).with("gateway", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
73
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
74
+ end
75
+
76
+ def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_an_array
77
+ @config.values[:gateway] = ["j@gateway1", "k@gateway2"]
78
+ gateway1 = mock
79
+ Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(gateway1)
80
+ gateway1.expects(:open).returns(65535)
81
+ 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)
82
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
83
+ end
84
+
85
+ def test_connection_factory_as_gateway_should_chain_gateways_if_gateway_variable_is_a_hash
86
+ @config.values[:gateway] = { ["j@gateway1", "k@gateway2"] => :default }
87
+ gateway1 = mock
88
+ Net::SSH::Gateway.expects(:new).with("gateway1", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(gateway1)
89
+ gateway1.expects(:open).returns(65535)
90
+ 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)
91
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
92
+ end
93
+
94
+ def test_connection_factory_as_gateway_should_share_gateway_between_connections
95
+ @config.values[:gateway] = "j@gateway"
96
+ Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :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
+ end
102
+
103
+ def test_connection_factory_as_gateway_should_share_gateway_between_like_connections_if_gateway_variable_is_a_hash
104
+ @config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"] }
105
+ Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
106
+ Capistrano::SSH.stubs(:connect).returns(stub_everything)
107
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
108
+ @config.establish_connections_to(server("capistrano"))
109
+ @config.establish_connections_to(server("another"))
110
+ end
111
+
112
+ def test_connection_factory_as_gateways_should_not_share_gateway_between_unlike_connections_if_gateway_variable_is_a_hash
113
+ @config.values[:gateway] = { "j@gateway" => [ "capistrano", "another"], "k@gateway2" => "yafhost" }
114
+ Net::SSH::Gateway.expects(:new).once.with("gateway", "j", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
115
+ Net::SSH::Gateway.expects(:new).once.with("gateway2", "k", :password => nil, :auth_methods => %w(publickey hostbased), :config => false).returns(stub_everything)
116
+ Capistrano::SSH.stubs(:connect).returns(stub_everything)
117
+ assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
118
+ @config.establish_connections_to(server("capistrano"))
119
+ @config.establish_connections_to(server("another"))
120
+ @config.establish_connections_to(server("yafhost"))
73
121
  end
74
122
 
75
123
  def test_establish_connections_to_should_accept_a_single_nonarray_parameter
76
124
  Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success)
77
125
  assert @config.sessions.empty?
78
126
  @config.establish_connections_to(server("capistrano"))
79
- assert ["capistrano"], @config.sessions.keys
127
+ assert_equal ["capistrano"], @config.sessions.keys.map(&:host)
80
128
  end
81
129
 
82
130
  def test_establish_connections_to_should_accept_an_array
83
131
  Capistrano::SSH.expects(:connect).times(3).returns(:success)
84
132
  assert @config.sessions.empty?
85
133
  @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
86
- assert %w(cap1 cap2 cap3), @config.sessions.keys.sort
134
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
87
135
  end
88
136
 
89
137
  def test_establish_connections_to_should_not_attempt_to_reestablish_existing_connections
90
138
  Capistrano::SSH.expects(:connect).times(2).returns(:success)
91
139
  @config.sessions[server("cap1")] = :ok
92
140
  @config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
93
- assert %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
141
+ assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map(&:host)
94
142
  end
95
-
143
+
96
144
  def test_establish_connections_to_should_raise_one_connection_error_on_failure
97
145
  Capistrano::SSH.expects(:connect).times(2).raises(Exception)
98
146
  assert_raises(Capistrano::ConnectionError) {
99
- @config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
147
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
100
148
  }
101
149
  end
102
150
 
103
151
  def test_connection_error_should_include_accessor_with_host_array
104
152
  Capistrano::SSH.expects(:connect).times(2).raises(Exception)
105
-
106
153
  begin
107
- @config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
154
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
108
155
  flunk "expected an exception to be raised"
109
156
  rescue Capistrano::ConnectionError => e
110
157
  assert e.respond_to?(:hosts)
111
- assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }
158
+ assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }.sort
112
159
  end
113
160
  end
114
-
161
+
115
162
  def test_connection_error_should_only_include_failed_hosts
116
- Capistrano::SSH.expects(:connect).times(2).raises(Exception).then.returns(:success)
163
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
164
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
117
165
 
118
166
  begin
119
- @config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
167
+ @config.establish_connections_to(%w(cap1 cap2).map { |s| server(s) })
120
168
  flunk "expected an exception to be raised"
121
169
  rescue Capistrano::ConnectionError => e
122
170
  assert_equal %w(cap1), e.hosts.map { |h| h.to_s }
@@ -141,6 +189,11 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
141
189
  assert_raises(Capistrano::NoMatchingServersError) { @config.execute_on_servers(:a => :b, :c => :d) { |list| } }
142
190
  end
143
191
 
192
+ def test_execute_on_servers_without_current_task_should_not_raise_error_if_no_matching_servers_and_continue_on_no_matching_servers
193
+ @config.expects(:find_servers).with(:a => :b, :c => :d, :on_no_matching_servers => :continue).returns([])
194
+ assert_nothing_raised { @config.execute_on_servers(:a => :b, :c => :d, :on_no_matching_servers => :continue) { |list| } }
195
+ end
196
+
144
197
  def test_execute_on_servers_should_raise_an_error_if_the_current_task_has_no_matching_servers_by_default
145
198
  @config.current_task = mock_task
146
199
  @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
@@ -150,7 +203,27 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
150
203
  end
151
204
  end
152
205
  end
153
-
206
+
207
+ 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
208
+ @config.current_task = mock_task(:on_no_matching_servers => :continue)
209
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
210
+ assert_nothing_raised do
211
+ @config.execute_on_servers do
212
+ flunk "should not get here"
213
+ end
214
+ end
215
+ end
216
+
217
+ 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
218
+ @config.current_task = mock_task
219
+ @config.expects(:find_servers_for_task).with(@config.current_task, :on_no_matching_servers => :continue).returns([])
220
+ assert_nothing_raised do
221
+ @config.execute_on_servers(:on_no_matching_servers => :continue) do
222
+ flunk "should not get here"
223
+ end
224
+ end
225
+ end
226
+
154
227
  def test_execute_on_servers_should_determine_server_list_from_active_task
155
228
  assert @config.sessions.empty?
156
229
  @config.current_task = mock_task
@@ -189,35 +262,36 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
189
262
  assert block_called
190
263
  assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
191
264
  end
192
-
265
+
193
266
  def test_execute_servers_should_raise_connection_error_on_failure_by_default
194
267
  @config.current_task = mock_task
195
268
  @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
196
269
  Capistrano::SSH.expects(:connect).raises(Exception)
197
- assert_raises(Capistrano::ConnectionError) {
270
+ assert_raises(Capistrano::ConnectionError) do
198
271
  @config.execute_on_servers do
199
272
  flunk "expected an exception to be raised"
200
273
  end
201
- }
274
+ end
202
275
  end
203
-
276
+
204
277
  def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
205
278
  @config.current_task = mock_task(:on_error => :continue)
206
279
  @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2")])
207
- Capistrano::SSH.expects(:connect).times(2).raises(Exception).then.returns(:success)
280
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
281
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
208
282
  assert_nothing_raised {
209
283
  @config.execute_on_servers do |servers|
210
284
  assert_equal %w(cap2), servers.map { |s| s.host }
211
285
  end
212
286
  }
213
287
  end
214
-
288
+
215
289
  def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_errors_with_on_errors_continue
216
290
  list = [server("cap1"), server("cap2")]
217
291
  @config.current_task = mock_task(:on_error => :continue)
218
292
  @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
219
- Capistrano::SSH.expects(:connect).times(2).raises(Exception).then.returns(:success)
220
- @config.expects(:failed!).with(server("cap1"))
293
+ Capistrano::SSH.expects(:connect).with(server('cap1'), anything).raises(Exception)
294
+ Capistrano::SSH.expects(:connect).with(server('cap2'), anything).returns(:success)
221
295
  @config.execute_on_servers do |servers|
222
296
  assert_equal %w(cap2), servers.map { |s| s.host }
223
297
  end
@@ -226,7 +300,7 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
226
300
  assert_equal %w(cap2), servers.map { |s| s.host }
227
301
  end
228
302
  end
229
-
303
+
230
304
  def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_errors_with_on_errors_continue
231
305
  cap1 = server("cap1")
232
306
  cap2 = server("cap2")
@@ -243,15 +317,15 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
243
317
  assert_equal %w(cap2), servers.map { |s| s.host }
244
318
  end
245
319
  end
246
-
247
- def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_upload_errors_with_on_errors_continue
320
+
321
+ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_errors_with_on_errors_continue
248
322
  cap1 = server("cap1")
249
323
  cap2 = server("cap2")
250
324
  @config.current_task = mock_task(:on_error => :continue)
251
325
  @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
252
326
  Capistrano::SSH.expects(:connect).times(2).returns(:success)
253
327
  @config.execute_on_servers do |servers|
254
- error = Capistrano::UploadError.new
328
+ error = Capistrano::TransferError.new
255
329
  error.hosts = [cap1]
256
330
  raise error
257
331
  end
@@ -270,6 +344,78 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
270
344
  assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
271
345
  end
272
346
 
347
+ def test_execute_on_servers_should_only_run_on_tasks_max_hosts_hosts_at_once
348
+ cap1 = server("cap1")
349
+ cap2 = server("cap2")
350
+ connection1 = mock()
351
+ connection2 = mock()
352
+ connection1.expects(:close)
353
+ connection2.expects(:close)
354
+ @config.current_task = mock_task(:max_hosts => 1)
355
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
356
+ Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
357
+ block_called = 0
358
+ @config.execute_on_servers do |servers|
359
+ block_called += 1
360
+ assert_equal 1, servers.size
361
+ end
362
+ assert_equal 2, block_called
363
+ end
364
+
365
+ def test_execute_on_servers_should_only_run_on_max_hosts_hosts_at_once
366
+ cap1 = server("cap1")
367
+ cap2 = server("cap2")
368
+ connection1 = mock()
369
+ connection2 = mock()
370
+ connection1.expects(:close)
371
+ connection2.expects(:close)
372
+ @config.current_task = mock_task(:max_hosts => 1)
373
+ @config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
374
+ Capistrano::SSH.expects(:connect).times(2).returns(connection1).then.returns(connection2)
375
+ block_called = 0
376
+ @config.execute_on_servers do |servers|
377
+ block_called += 1
378
+ assert_equal 1, servers.size
379
+ end
380
+ assert_equal 2, block_called
381
+ end
382
+
383
+ def test_execute_on_servers_should_cope_with_already_dropped_connections_when_attempting_to_close_them
384
+ cap1 = server("cap1")
385
+ cap2 = server("cap2")
386
+ connection1 = mock()
387
+ connection2 = mock()
388
+ connection3 = mock()
389
+ connection4 = mock()
390
+ connection1.expects(:close).raises(IOError)
391
+ connection2.expects(:close)
392
+ connection3.expects(:close)
393
+ connection4.expects(:close)
394
+ @config.current_task = mock_task(:max_hosts => 1)
395
+ @config.expects(:find_servers_for_task).times(2).with(@config.current_task, {}).returns([cap1, cap2])
396
+ Capistrano::SSH.expects(:connect).times(4).returns(connection1).then.returns(connection2).then.returns(connection3).then.returns(connection4)
397
+ @config.execute_on_servers {}
398
+ @config.execute_on_servers {}
399
+ end
400
+
401
+ def test_execute_on_servers_should_cope_with_already_disconnected_connections_when_attempting_to_close_them
402
+ cap1 = server("cap1")
403
+ cap2 = server("cap2")
404
+ connection1 = mock()
405
+ connection2 = mock()
406
+ connection3 = mock()
407
+ connection4 = mock()
408
+ connection1.expects(:close).raises(Net::SSH::Disconnect)
409
+ connection2.expects(:close)
410
+ connection3.expects(:close)
411
+ connection4.expects(:close)
412
+ @config.current_task = mock_task(:max_hosts => 1)
413
+ @config.expects(:find_servers_for_task).times(2).with(@config.current_task, {}).returns([cap1, cap2])
414
+ Capistrano::SSH.expects(:connect).times(4).returns(connection1).then.returns(connection2).then.returns(connection3).then.returns(connection4)
415
+ @config.execute_on_servers {}
416
+ @config.execute_on_servers {}
417
+ end
418
+
273
419
  def test_connect_should_honor_once_option
274
420
  assert @config.sessions.empty?
275
421
  @config.current_task = mock_task
@@ -283,6 +429,11 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
283
429
 
284
430
  def mock_task(options={})
285
431
  continue_on_error = options[:on_error] == :continue
286
- stub("task", :fully_qualified_name => "name", :options => options, :continue_on_error? => continue_on_error)
432
+ stub("task",
433
+ :fully_qualified_name => "name",
434
+ :options => options,
435
+ :continue_on_error? => continue_on_error,
436
+ :max_hosts => options[:max_hosts]
437
+ )
287
438
  end
288
- end
439
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/execution'
3
3
  require 'capistrano/task_definition'
4
4
 
@@ -116,6 +116,22 @@ class ConfigurationExecutionTest < Test::Unit::TestCase
116
116
  assert @config.state[:aaa]
117
117
  end
118
118
 
119
+ def test_on_rollback_called_twice_should_result_in_last_rollback_block_being_effective
120
+ aaa = new_task(@config, :aaa) do
121
+ transaction do
122
+ on_rollback { (state[:rollback] ||= []) << :first }
123
+ on_rollback { (state[:rollback] ||= []) << :second }
124
+ raise "boom"
125
+ end
126
+ end
127
+
128
+ assert_raises(RuntimeError) do
129
+ @config.execute_task(aaa)
130
+ end
131
+
132
+ assert_equal [:second], @config.state[:rollback]
133
+ end
134
+
119
135
  def test_find_and_execute_task_should_raise_error_when_task_cannot_be_found
120
136
  @config.expects(:find_task).with("path:to:task").returns(nil)
121
137
  assert_raises(Capistrano::NoSuchTaskError) { @config.find_and_execute_task("path:to:task") }
@@ -156,4 +172,4 @@ class ConfigurationExecutionTest < Test::Unit::TestCase
156
172
  block ||= stack_inspector
157
173
  namespace.tasks[name] = Capistrano::TaskDefinition.new(name, namespace, &block)
158
174
  end
159
- end
175
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../utils"
1
+ require 'utils'
2
2
  require 'capistrano/configuration/loading'
3
3
 
4
4
  class ConfigurationLoadingTest < Test::Unit::TestCase
@@ -23,7 +23,7 @@ class ConfigurationLoadingTest < Test::Unit::TestCase
23
23
 
24
24
  def teardown
25
25
  MockConfig.instance = nil
26
- $".delete "#{File.dirname(__FILE__)}/../fixtures/custom.rb"
26
+ $LOADED_FEATURES.delete_if { |a| a =~ /fixtures\/custom\.rb$/ }
27
27
  end
28
28
 
29
29
  def test_initialize_should_init_collections
@@ -106,7 +106,7 @@ class ConfigurationLoadingTest < Test::Unit::TestCase
106
106
 
107
107
  def test_require_from_config_should_load_file_in_config_scope
108
108
  assert_nothing_raised do
109
- @config.require "#{File.dirname(__FILE__)}/../fixtures/custom"
109
+ @config.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
110
110
  end
111
111
  assert_equal :custom, @config.ping
112
112
  end
@@ -116,4 +116,17 @@ class ConfigurationLoadingTest < Test::Unit::TestCase
116
116
  require "#{File.dirname(__FILE__)}/../fixtures/custom"
117
117
  end
118
118
  end
119
- end
119
+
120
+ def test_require_from_config_should_return_false_when_called_a_second_time_with_same_args
121
+ assert @config.require("#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom")
122
+ assert_equal false, @config.require("#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom")
123
+ end
124
+
125
+ def test_require_in_multiple_instances_should_load_recipes_in_each_instance
126
+ config2 = MockConfig.new
127
+ @config.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
128
+ config2.require "#{File.expand_path(File.dirname(__FILE__))}/../fixtures/custom"
129
+ assert_equal :custom, @config.ping
130
+ assert_equal :custom, config2.ping
131
+ end
132
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/namespaces'
3
3
 
4
4
  class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
@@ -108,9 +108,9 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
108
108
  end
109
109
 
110
110
  def test_defining_ask_should_add_task_as_method
111
- assert !@config.methods.include?("original")
111
+ assert !@config.methods.any? { |m| m.to_sym == :original }
112
112
  @config.task(:original) { puts "foo" }
113
- assert @config.methods.include?("original")
113
+ assert @config.methods.any? { |m| m.to_sym == :original }
114
114
  end
115
115
 
116
116
  def test_calling_defined_task_should_delegate_to_execute_task
@@ -146,7 +146,7 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
146
146
 
147
147
  def test_parent_for_namespace_should_be_the_top_level
148
148
  @config.namespace(:outer) {}
149
- assert_equal @config, @config.namespaces[:outer].parent
149
+ assert_equal @config, @config.namespaces[:outer].parent
150
150
  end
151
151
 
152
152
  def test_fqn_for_nested_namespace_should_be_color_delimited
@@ -239,6 +239,12 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
239
239
  assert ns.respond_to?(:original_initialize_called)
240
240
  end
241
241
 
242
+ def test_namespace_should_accept_respond_to_with_include_priv_parameter
243
+ @config.namespace(:outer) {}
244
+ ns = @config.namespaces[:outer]
245
+ assert ns.respond_to?(:original_initialize_called, true)
246
+ end
247
+
242
248
  def test_namespace_should_delegate_unknown_messages_to_its_parent
243
249
  @config.namespace(:outer) {}
244
250
  ns = @config.namespaces[:outer]
@@ -280,4 +286,47 @@ class ConfigurationNamespacesDSLTest < Test::Unit::TestCase
280
286
  inner = @config.namespaces[:outer].namespaces[:inner]
281
287
  assert_nil inner.search_task(:first)
282
288
  end
283
- end
289
+
290
+ def test_top_should_return_self_if_self_is_top
291
+ assert_equal @config, @config.top
292
+ end
293
+
294
+ def test_top_should_return_parent_if_parent_is_top
295
+ @config.namespace(:outer) {}
296
+ assert_equal @config, @config.namespaces[:outer].top
297
+ end
298
+
299
+ def test_top_should_return_topmost_parent_if_self_is_deeply_nested
300
+ @config.namespace(:outer) { namespace(:middle) { namespace(:inner) {} } }
301
+ assert_equal @config, @config.namespaces[:outer].namespaces[:middle].namespaces[:inner].top
302
+ end
303
+
304
+ def test_find_task_should_return_nil_when_empty_inner_task
305
+ @config.namespace :outer do
306
+ namespace :inner do
307
+ end
308
+ end
309
+ assert_nil @config.find_task("outer::inner")
310
+ end
311
+
312
+ def test_kernel_method_clashing_should_not_affect_method_delegation_to_parent
313
+ @config.class.class_eval do
314
+ def some_weird_method() 'config' end
315
+ end
316
+
317
+ @config.namespace(:clash) {}
318
+ namespace = @config.namespaces[:clash]
319
+ assert_equal 'config', namespace.some_weird_method
320
+
321
+ Kernel.module_eval do
322
+ def some_weird_method() 'kernel' end
323
+ end
324
+
325
+ @config.namespace(:clash2) {}
326
+ namespace = @config.namespaces[:clash2]
327
+ assert_equal 'config', namespace.some_weird_method
328
+
329
+ Kernel.send :remove_method, :some_weird_method
330
+ @config.class.send :remove_method, :some_weird_method
331
+ end
332
+ end
@@ -1,5 +1,6 @@
1
- require "#{File.dirname(__FILE__)}/../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/roles'
3
+ require 'capistrano/server_definition'
3
4
 
4
5
  class ConfigurationRolesTest < Test::Unit::TestCase
5
6
  class MockConfig
@@ -21,21 +22,56 @@ class ConfigurationRolesTest < Test::Unit::TestCase
21
22
  assert @config.roles.empty?
22
23
  end
23
24
 
25
+ def test_roles_for_host_with_one_role
26
+ @config.role :app, "app1.capistrano.test"
27
+ @config.role :not_app, "not-app.capistrano.test"
28
+ app_server = @config.roles[:app].servers.first
29
+ assert @config.role_names_for_host(app_server)==[ :app ]
30
+ end
31
+
32
+ def test_roles_for_host_with_multiple_roles
33
+ @config.server "www.capistrano.test", :db, :worker
34
+ db_server = @config.roles[:db].servers.first
35
+ assert_equal @config.role_names_for_host(db_server).map(&:to_s).sort, [ 'db', 'worker' ]
36
+ end
37
+
24
38
  def test_role_should_allow_empty_list
25
39
  @config.role :app
40
+ assert @config.roles.keys.include?(:app)
26
41
  assert @config.roles[:app].empty?
27
42
  end
28
43
 
29
44
  def test_role_with_one_argument_should_add_to_roles_collection
30
45
  @config.role :app, "app1.capistrano.test"
31
46
  assert_equal [:app], @config.roles.keys
32
- assert_equal %w(app1.capistrano.test), @config.roles[:app].map { |s| s.host }
47
+ assert_role_equals %w(app1.capistrano.test)
48
+ end
49
+
50
+ def test_role_block_returning_single_string_is_added_to_roles_collection
51
+ @config.role :app do
52
+ 'app1.capistrano.test'
53
+ end
54
+ assert_role_equals %w(app1.capistrano.test)
33
55
  end
34
56
 
35
57
  def test_role_with_multiple_arguments_should_add_each_to_roles_collection
36
58
  @config.role :app, "app1.capistrano.test", "app2.capistrano.test"
37
59
  assert_equal [:app], @config.roles.keys
38
- assert_equal %w(app1.capistrano.test app2.capistrano.test), @config.roles[:app].map { |s| s.host }
60
+ assert_role_equals %w(app1.capistrano.test app2.capistrano.test)
61
+ end
62
+
63
+ def test_role_with_block_and_strings_should_add_both_to_roles_collection
64
+ @config.role :app, 'app1.capistrano.test' do
65
+ 'app2.capistrano.test'
66
+ end
67
+ assert_role_equals %w(app1.capistrano.test app2.capistrano.test)
68
+ end
69
+
70
+ def test_role_block_returning_array_should_add_each_to_roles_collection
71
+ @config.role :app do
72
+ ['app1.capistrano.test', 'app2.capistrano.test']
73
+ end
74
+ assert_role_equals %w(app1.capistrano.test app2.capistrano.test)
39
75
  end
40
76
 
41
77
  def test_role_with_options_should_apply_options_to_each_argument
@@ -44,4 +80,78 @@ class ConfigurationRolesTest < Test::Unit::TestCase
44
80
  assert_equal({:extra => :value}, server.options)
45
81
  end
46
82
  end
47
- end
83
+
84
+ def test_role_with_options_should_apply_options_to_block_results
85
+ @config.role :app, :extra => :value do
86
+ ['app1.capistrano.test', 'app2.capistrano.test']
87
+ end
88
+ @config.roles[:app].each do |server|
89
+ assert_equal({:extra => :value}, server.options)
90
+ end
91
+ end
92
+
93
+ def test_options_should_apply_only_to_this_argument_set
94
+ @config.role :app, 'app1.capistrano.test', 'app2.capistrano.test' do
95
+ ['app3.capistrano.test', 'app4.capistrano.test']
96
+ end
97
+ @config.role :app, 'app5.capistrano.test', 'app6.capistrano.test', :extra => :value do
98
+ ['app7.capistrano.test', 'app8.capistrano.test']
99
+ end
100
+ @config.role :app, 'app9.capistrano.test'
101
+
102
+ option_hosts = ['app5.capistrano.test', 'app6.capistrano.test', 'app7.capistrano.test', 'app8.capistrano.test']
103
+ @config.roles[:app].each do |server|
104
+ if (option_hosts.include? server.host)
105
+ assert_equal({:extra => :value}, server.options)
106
+ else
107
+ assert_not_equal({:extra => :value}, server.options)
108
+ end
109
+ end
110
+ end
111
+
112
+ # Here, the source should be more readable than the method name
113
+ def test_role_block_returns_options_hash_is_merged_with_role_options_argument
114
+ @config.role :app, :first => :one, :second => :two do
115
+ ['app1.capistrano.test', 'app2.capistrano.test', {:second => :please, :third => :three}]
116
+ end
117
+ @config.roles[:app].each do |server|
118
+ assert_equal({:first => :one, :second => :please, :third => :three}, server.options)
119
+ end
120
+ end
121
+
122
+ def test_role_block_can_override_role_options_argument
123
+ @config.role :app, :value => :wrong do
124
+ Capistrano::ServerDefinition.new('app.capistrano.test')
125
+ end
126
+ @config.roles[:app].servers
127
+ @config.roles[:app].servers.each do |server|
128
+ assert_not_equal({:value => :wrong}, server.options)
129
+ end
130
+ end
131
+
132
+ def test_role_block_can_return_nil
133
+ @config.role :app do
134
+ nil
135
+ end
136
+ assert_role_equals ([])
137
+ end
138
+
139
+ def test_role_block_can_return_empty_array
140
+ @config.role :app do
141
+ []
142
+ end
143
+ assert_role_equals ([])
144
+ end
145
+
146
+ def test_role_definitions_via_server_should_associate_server_with_roles
147
+ @config.server "www.capistrano.test", :web, :app
148
+ assert_equal %w(www.capistrano.test), @config.roles[:app].map { |s| s.host }
149
+ assert_equal %w(www.capistrano.test), @config.roles[:web].map { |s| s.host }
150
+ end
151
+
152
+ private
153
+
154
+ def assert_role_equals(list)
155
+ assert_equal list, @config.roles[:app].map { |s| s.host }
156
+ end
157
+ end