capistrano 2.0.0 → 2.15.9

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 (124) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +755 -18
  5. data/Gemfile +13 -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 +224 -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 +99 -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 +34 -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 +67 -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 +202 -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 +11 -9
  49. data/lib/capistrano/recipes/deploy/scm/darcs.rb +12 -1
  50. data/lib/capistrano/recipes/deploy/scm/git.rb +299 -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 +36 -18
  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 +4 -3
  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 +8 -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 +141 -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 +33 -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 +274 -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 +68 -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 +28 -33
  114. data/test/version_test.rb +4 -17
  115. metadata +215 -100
  116. data/MIT-LICENSE +0 -20
  117. data/README +0 -43
  118. data/examples/sample.rb +0 -14
  119. data/lib/capistrano/gateway.rb +0 -131
  120. data/lib/capistrano/recipes/deploy/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
@@ -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,33 @@ 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
+
133
+ def test_file_in_load_path_returns_true_when_file_is_in_load_path
134
+ File.stubs(:file?).returns(false)
135
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
136
+
137
+ @config.load_paths << "custom/path/for"
138
+ assert_equal true, @config.file_in_load_path?("file")
139
+ end
140
+
141
+ def test_file_in_load_path_returns_false_when_file_is_not_in_load_path
142
+ File.stubs(:file?).returns(false)
143
+ File.stubs(:file?).with("custom/path/for/file.rb").returns(false)
144
+
145
+ @config.load_paths << "custom/path/for"
146
+ assert_equal false, @config.file_in_load_path?("file")
147
+ end
148
+ 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