capistrano 1.4.2 → 2.0.0
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.
- data/CHANGELOG +140 -4
- data/MIT-LICENSE +1 -1
- data/README +22 -14
- data/bin/cap +1 -8
- data/bin/capify +77 -0
- data/examples/sample.rb +10 -109
- data/lib/capistrano.rb +1 -0
- data/lib/capistrano/callback.rb +41 -0
- data/lib/capistrano/cli.rb +17 -317
- data/lib/capistrano/cli/execute.rb +82 -0
- data/lib/capistrano/cli/help.rb +102 -0
- data/lib/capistrano/cli/help.txt +53 -0
- data/lib/capistrano/cli/options.rb +183 -0
- data/lib/capistrano/cli/ui.rb +28 -0
- data/lib/capistrano/command.rb +62 -29
- data/lib/capistrano/configuration.rb +25 -226
- data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
- data/lib/capistrano/configuration/actions/inspect.rb +46 -0
- data/lib/capistrano/configuration/actions/invocation.rb +127 -0
- data/lib/capistrano/configuration/callbacks.rb +148 -0
- data/lib/capistrano/configuration/connections.rb +159 -0
- data/lib/capistrano/configuration/execution.rb +126 -0
- data/lib/capistrano/configuration/loading.rb +112 -0
- data/lib/capistrano/configuration/namespaces.rb +190 -0
- data/lib/capistrano/configuration/roles.rb +51 -0
- data/lib/capistrano/configuration/servers.rb +75 -0
- data/lib/capistrano/configuration/variables.rb +127 -0
- data/lib/capistrano/errors.rb +15 -0
- data/lib/capistrano/extensions.rb +27 -8
- data/lib/capistrano/gateway.rb +54 -29
- data/lib/capistrano/logger.rb +11 -11
- data/lib/capistrano/recipes/compat.rb +32 -0
- data/lib/capistrano/recipes/deploy.rb +483 -0
- data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
- data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
- data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
- data/lib/capistrano/recipes/deploy/scm.rb +19 -0
- data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
- data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
- data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
- data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
- data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
- data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
- data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
- data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
- data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
- data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
- data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
- data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
- data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
- data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
- data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
- data/lib/capistrano/recipes/standard.rb +26 -276
- data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
- data/lib/capistrano/recipes/upgrade.rb +33 -0
- data/lib/capistrano/server_definition.rb +51 -0
- data/lib/capistrano/shell.rb +125 -81
- data/lib/capistrano/ssh.rb +80 -36
- data/lib/capistrano/task_definition.rb +69 -0
- data/lib/capistrano/upload.rb +146 -0
- data/lib/capistrano/version.rb +13 -17
- data/test/cli/execute_test.rb +132 -0
- data/test/cli/help_test.rb +139 -0
- data/test/cli/options_test.rb +226 -0
- data/test/cli/ui_test.rb +28 -0
- data/test/cli_test.rb +17 -0
- data/test/command_test.rb +284 -25
- data/test/configuration/actions/file_transfer_test.rb +40 -0
- data/test/configuration/actions/inspect_test.rb +62 -0
- data/test/configuration/actions/invocation_test.rb +195 -0
- data/test/configuration/callbacks_test.rb +206 -0
- data/test/configuration/connections_test.rb +288 -0
- data/test/configuration/execution_test.rb +159 -0
- data/test/configuration/loading_test.rb +119 -0
- data/test/configuration/namespace_dsl_test.rb +283 -0
- data/test/configuration/roles_test.rb +47 -0
- data/test/configuration/servers_test.rb +90 -0
- data/test/configuration/variables_test.rb +180 -0
- data/test/configuration_test.rb +60 -212
- data/test/deploy/scm/base_test.rb +55 -0
- data/test/deploy/strategy/copy_test.rb +146 -0
- data/test/extensions_test.rb +69 -0
- data/test/fixtures/cli_integration.rb +5 -0
- data/test/fixtures/custom.rb +2 -2
- data/test/gateway_test.rb +167 -0
- data/test/logger_test.rb +123 -0
- data/test/server_definition_test.rb +108 -0
- data/test/shell_test.rb +64 -0
- data/test/ssh_test.rb +67 -154
- data/test/task_definition_test.rb +101 -0
- data/test/upload_test.rb +131 -0
- data/test/utils.rb +31 -39
- data/test/version_test.rb +24 -0
- metadata +145 -98
- data/THANKS +0 -4
- data/lib/capistrano/actor.rb +0 -567
- data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
- data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
- data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
- data/lib/capistrano/generators/rails/loader.rb +0 -20
- data/lib/capistrano/scm/base.rb +0 -61
- data/lib/capistrano/scm/baz.rb +0 -118
- data/lib/capistrano/scm/bzr.rb +0 -70
- data/lib/capistrano/scm/cvs.rb +0 -129
- data/lib/capistrano/scm/darcs.rb +0 -27
- data/lib/capistrano/scm/mercurial.rb +0 -83
- data/lib/capistrano/scm/perforce.rb +0 -139
- data/lib/capistrano/scm/subversion.rb +0 -128
- data/lib/capistrano/transfer.rb +0 -97
- data/lib/capistrano/utils.rb +0 -26
- data/test/actor_test.rb +0 -402
- data/test/scm/cvs_test.rb +0 -196
- data/test/scm/subversion_test.rb +0 -145
@@ -0,0 +1,288 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../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
|
+
@ssh_options = {
|
34
|
+
:user => "jamis",
|
35
|
+
:port => 8080,
|
36
|
+
:password => "g00b3r",
|
37
|
+
:ssh_options => { :debug => :verbose }
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_initialize_should_initialize_collections_and_call_original_initialize
|
42
|
+
assert @config.original_initialize_called
|
43
|
+
assert @config.sessions.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_connection_factory_should_return_default_connection_factory_instance
|
47
|
+
factory = @config.connection_factory
|
48
|
+
assert_instance_of Capistrano::Configuration::Connections::DefaultConnectionFactory, factory
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_connection_factory_instance_should_be_cached
|
52
|
+
assert_same @config.connection_factory, @config.connection_factory
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_default_connection_factory_honors_config_options
|
56
|
+
server = server("capistrano")
|
57
|
+
Capistrano::SSH.expects(:connect).with(server, @config).returns(:session)
|
58
|
+
assert_equal :session, @config.connection_factory.connect_to(server)
|
59
|
+
end
|
60
|
+
|
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
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_connection_factory_as_gateway_should_honor_config_options
|
69
|
+
@config.values[:gateway] = "capistrano"
|
70
|
+
@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
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_establish_connections_to_should_accept_a_single_nonarray_parameter
|
76
|
+
Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.returns(:success)
|
77
|
+
assert @config.sessions.empty?
|
78
|
+
@config.establish_connections_to(server("capistrano"))
|
79
|
+
assert ["capistrano"], @config.sessions.keys
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_establish_connections_to_should_accept_an_array
|
83
|
+
Capistrano::SSH.expects(:connect).times(3).returns(:success)
|
84
|
+
assert @config.sessions.empty?
|
85
|
+
@config.establish_connections_to(%w(cap1 cap2 cap3).map { |s| server(s) })
|
86
|
+
assert %w(cap1 cap2 cap3), @config.sessions.keys.sort
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_establish_connections_to_should_not_attempt_to_reestablish_existing_connections
|
90
|
+
Capistrano::SSH.expects(:connect).times(2).returns(:success)
|
91
|
+
@config.sessions[server("cap1")] = :ok
|
92
|
+
@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 }
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_establish_connections_to_should_raise_one_connection_error_on_failure
|
97
|
+
Capistrano::SSH.expects(:connect).times(2).raises(Exception)
|
98
|
+
assert_raises(Capistrano::ConnectionError) {
|
99
|
+
@config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_connection_error_should_include_accessor_with_host_array
|
104
|
+
Capistrano::SSH.expects(:connect).times(2).raises(Exception)
|
105
|
+
|
106
|
+
begin
|
107
|
+
@config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
|
108
|
+
flunk "expected an exception to be raised"
|
109
|
+
rescue Capistrano::ConnectionError => e
|
110
|
+
assert e.respond_to?(:hosts)
|
111
|
+
assert_equal %w(cap1 cap2), e.hosts.map { |h| h.to_s }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_connection_error_should_only_include_failed_hosts
|
116
|
+
Capistrano::SSH.expects(:connect).times(2).raises(Exception).then.returns(:success)
|
117
|
+
|
118
|
+
begin
|
119
|
+
@config.establish_connections_to(%w(cap1 cap2)).map { |s| servers(s) }
|
120
|
+
flunk "expected an exception to be raised"
|
121
|
+
rescue Capistrano::ConnectionError => e
|
122
|
+
assert_equal %w(cap1), e.hosts.map { |h| h.to_s }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_execute_on_servers_should_require_a_block
|
127
|
+
assert_raises(ArgumentError) { @config.execute_on_servers }
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_execute_on_servers_without_current_task_should_call_find_servers
|
131
|
+
list = [server("first"), server("second")]
|
132
|
+
@config.expects(:find_servers).with(:a => :b, :c => :d).returns(list)
|
133
|
+
@config.expects(:establish_connections_to).with(list).returns(:done)
|
134
|
+
@config.execute_on_servers(:a => :b, :c => :d) do |result|
|
135
|
+
assert_equal list, result
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_execute_on_servers_without_current_task_should_raise_error_if_no_matching_servers
|
140
|
+
@config.expects(:find_servers).with(:a => :b, :c => :d).returns([])
|
141
|
+
assert_raises(Capistrano::NoMatchingServersError) { @config.execute_on_servers(:a => :b, :c => :d) { |list| } }
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_execute_on_servers_should_raise_an_error_if_the_current_task_has_no_matching_servers_by_default
|
145
|
+
@config.current_task = mock_task
|
146
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([])
|
147
|
+
assert_raises(Capistrano::NoMatchingServersError) do
|
148
|
+
@config.execute_on_servers do
|
149
|
+
flunk "should not get here"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_execute_on_servers_should_determine_server_list_from_active_task
|
155
|
+
assert @config.sessions.empty?
|
156
|
+
@config.current_task = mock_task
|
157
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
|
158
|
+
Capistrano::SSH.expects(:connect).times(3).returns(:success)
|
159
|
+
@config.execute_on_servers {}
|
160
|
+
assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
|
161
|
+
end
|
162
|
+
|
163
|
+
def test_execute_on_servers_should_yield_server_list_to_block
|
164
|
+
assert @config.sessions.empty?
|
165
|
+
@config.current_task = mock_task
|
166
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
|
167
|
+
Capistrano::SSH.expects(:connect).times(3).returns(:success)
|
168
|
+
block_called = false
|
169
|
+
@config.execute_on_servers do |servers|
|
170
|
+
block_called = true
|
171
|
+
assert servers.detect { |s| s.host == "cap1" }
|
172
|
+
assert servers.detect { |s| s.host == "cap2" }
|
173
|
+
assert servers.detect { |s| s.host == "cap3" }
|
174
|
+
assert servers.all? { |s| @config.sessions[s] }
|
175
|
+
end
|
176
|
+
assert block_called
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_execute_on_servers_with_once_option_should_establish_connection_to_and_yield_only_the_first_server
|
180
|
+
assert @config.sessions.empty?
|
181
|
+
@config.current_task = mock_task
|
182
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
|
183
|
+
Capistrano::SSH.expects(:connect).returns(:success)
|
184
|
+
block_called = false
|
185
|
+
@config.execute_on_servers(:once => true) do |servers|
|
186
|
+
block_called = true
|
187
|
+
assert_equal %w(cap1), servers.map { |s| s.host }
|
188
|
+
end
|
189
|
+
assert block_called
|
190
|
+
assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_execute_servers_should_raise_connection_error_on_failure_by_default
|
194
|
+
@config.current_task = mock_task
|
195
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
|
196
|
+
Capistrano::SSH.expects(:connect).raises(Exception)
|
197
|
+
assert_raises(Capistrano::ConnectionError) {
|
198
|
+
@config.execute_on_servers do
|
199
|
+
flunk "expected an exception to be raised"
|
200
|
+
end
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
|
205
|
+
@config.current_task = mock_task(:on_error => :continue)
|
206
|
+
@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)
|
208
|
+
assert_nothing_raised {
|
209
|
+
@config.execute_on_servers do |servers|
|
210
|
+
assert_equal %w(cap2), servers.map { |s| s.host }
|
211
|
+
end
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_connection_errors_with_on_errors_continue
|
216
|
+
list = [server("cap1"), server("cap2")]
|
217
|
+
@config.current_task = mock_task(:on_error => :continue)
|
218
|
+
@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"))
|
221
|
+
@config.execute_on_servers do |servers|
|
222
|
+
assert_equal %w(cap2), servers.map { |s| s.host }
|
223
|
+
end
|
224
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns(list)
|
225
|
+
@config.execute_on_servers do |servers|
|
226
|
+
assert_equal %w(cap2), servers.map { |s| s.host }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_errors_with_on_errors_continue
|
231
|
+
cap1 = server("cap1")
|
232
|
+
cap2 = server("cap2")
|
233
|
+
@config.current_task = mock_task(:on_error => :continue)
|
234
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
|
235
|
+
Capistrano::SSH.expects(:connect).times(2).returns(:success)
|
236
|
+
@config.execute_on_servers do |servers|
|
237
|
+
error = Capistrano::CommandError.new
|
238
|
+
error.hosts = [cap1]
|
239
|
+
raise error
|
240
|
+
end
|
241
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
|
242
|
+
@config.execute_on_servers do |servers|
|
243
|
+
assert_equal %w(cap2), servers.map { |s| s.host }
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_upload_errors_with_on_errors_continue
|
248
|
+
cap1 = server("cap1")
|
249
|
+
cap2 = server("cap2")
|
250
|
+
@config.current_task = mock_task(:on_error => :continue)
|
251
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
|
252
|
+
Capistrano::SSH.expects(:connect).times(2).returns(:success)
|
253
|
+
@config.execute_on_servers do |servers|
|
254
|
+
error = Capistrano::UploadError.new
|
255
|
+
error.hosts = [cap1]
|
256
|
+
raise error
|
257
|
+
end
|
258
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
|
259
|
+
@config.execute_on_servers do |servers|
|
260
|
+
assert_equal %w(cap2), servers.map { |s| s.host }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_connect_should_establish_connections_to_all_servers_in_scope
|
265
|
+
assert @config.sessions.empty?
|
266
|
+
@config.current_task = mock_task
|
267
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1"), server("cap2"), server("cap3")])
|
268
|
+
Capistrano::SSH.expects(:connect).times(3).returns(:success)
|
269
|
+
@config.connect!
|
270
|
+
assert_equal %w(cap1 cap2 cap3), @config.sessions.keys.sort.map { |s| s.host }
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_connect_should_honor_once_option
|
274
|
+
assert @config.sessions.empty?
|
275
|
+
@config.current_task = mock_task
|
276
|
+
@config.expects(:find_servers_for_task).with(@config.current_task, :once => true).returns([server("cap1"), server("cap2"), server("cap3")])
|
277
|
+
Capistrano::SSH.expects(:connect).returns(:success)
|
278
|
+
@config.connect! :once => true
|
279
|
+
assert_equal %w(cap1), @config.sessions.keys.sort.map { |s| s.host }
|
280
|
+
end
|
281
|
+
|
282
|
+
private
|
283
|
+
|
284
|
+
def mock_task(options={})
|
285
|
+
continue_on_error = options[:on_error] == :continue
|
286
|
+
stub("task", :fully_qualified_name => "name", :options => options, :continue_on_error? => continue_on_error)
|
287
|
+
end
|
288
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../utils"
|
2
|
+
require 'capistrano/configuration/execution'
|
3
|
+
require 'capistrano/task_definition'
|
4
|
+
|
5
|
+
class ConfigurationExecutionTest < Test::Unit::TestCase
|
6
|
+
class MockConfig
|
7
|
+
attr_reader :tasks, :namespaces, :fully_qualified_name, :parent
|
8
|
+
attr_reader :state, :original_initialize_called
|
9
|
+
attr_accessor :logger, :default_task
|
10
|
+
|
11
|
+
def initialize(options={})
|
12
|
+
@original_initialize_called = true
|
13
|
+
@tasks = {}
|
14
|
+
@namespaces = {}
|
15
|
+
@state = {}
|
16
|
+
@fully_qualified_name = options[:fqn]
|
17
|
+
@parent = options[:parent]
|
18
|
+
@logger = options.delete(:logger)
|
19
|
+
end
|
20
|
+
|
21
|
+
include Capistrano::Configuration::Execution
|
22
|
+
end
|
23
|
+
|
24
|
+
def setup
|
25
|
+
@config = MockConfig.new(:logger => stub(:debug => nil, :info => nil, :important => nil))
|
26
|
+
@config.stubs(:search_task).returns(nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_initialize_should_initialize_collections
|
30
|
+
assert_nil @config.rollback_requests
|
31
|
+
assert @config.original_initialize_called
|
32
|
+
assert @config.task_call_frames.empty?
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_execute_task_should_populate_call_stack
|
36
|
+
task = new_task @config, :testing
|
37
|
+
assert_nothing_raised { @config.execute_task(task) }
|
38
|
+
assert_equal %w(testing), @config.state[:testing][:stack]
|
39
|
+
assert_nil @config.state[:testing][:history]
|
40
|
+
assert @config.task_call_frames.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_nested_execute_task_should_add_to_call_stack
|
44
|
+
testing = new_task @config, :testing
|
45
|
+
outer = new_task(@config, :outer) { execute_task(testing) }
|
46
|
+
|
47
|
+
assert_nothing_raised { @config.execute_task(outer) }
|
48
|
+
assert_equal %w(outer testing), @config.state[:testing][:stack]
|
49
|
+
assert_nil @config.state[:testing][:history]
|
50
|
+
assert @config.task_call_frames.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_execute_task_should_execute_in_scope_of_tasks_parent
|
54
|
+
ns = stub("namespace", :tasks => {}, :default_task => nil, :fully_qualified_name => "ns")
|
55
|
+
ns.expects(:instance_eval)
|
56
|
+
testing = new_task ns, :testing
|
57
|
+
@config.execute_task(testing)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_transaction_outside_of_task_should_raise_exception
|
61
|
+
assert_raises(ScriptError) { @config.transaction {} }
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_transaction_without_block_should_raise_argument_error
|
65
|
+
testing = new_task(@config, :testing) { transaction }
|
66
|
+
assert_raises(ArgumentError) { @config.execute_task(testing) }
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_transaction_should_initialize_transaction_history
|
70
|
+
@config.state[:inspector] = stack_inspector
|
71
|
+
testing = new_task(@config, :testing) { transaction { instance_eval(&state[:inspector]) } }
|
72
|
+
@config.execute_task(testing)
|
73
|
+
assert_equal [], @config.state[:testing][:history]
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_transaction_from_within_transaction_should_not_start_new_transaction
|
77
|
+
third = new_task(@config, :third, &stack_inspector)
|
78
|
+
second = new_task(@config, :second) { transaction { execute_task(third) } }
|
79
|
+
first = new_task(@config, :first) { transaction { execute_task(second) } }
|
80
|
+
# kind of fragile...not sure how else to check that transaction was only
|
81
|
+
# really run twice...but if the transaction was REALLY run, logger.info
|
82
|
+
# will be called once when it starts, and once when it finishes.
|
83
|
+
@config.logger = mock()
|
84
|
+
@config.logger.stubs(:debug)
|
85
|
+
@config.logger.expects(:info).times(2)
|
86
|
+
@config.execute_task(first)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_on_rollback_should_have_no_effect_outside_of_transaction
|
90
|
+
aaa = new_task(@config, :aaa) { on_rollback { state[:rollback] = true }; raise "boom" }
|
91
|
+
assert_raises(RuntimeError) { @config.execute_task(aaa) }
|
92
|
+
assert_nil @config.state[:rollback]
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_exception_raised_in_transaction_should_call_all_registered_rollback_handlers_in_reverse_order
|
96
|
+
aaa = new_task(@config, :aaa) { on_rollback { (state[:rollback] ||= []) << :aaa } }
|
97
|
+
bbb = new_task(@config, :bbb) { on_rollback { (state[:rollback] ||= []) << :bbb } }
|
98
|
+
ccc = new_task(@config, :ccc) {}
|
99
|
+
ddd = new_task(@config, :ddd) { on_rollback { (state[:rollback] ||= []) << :ddd }; execute_task(bbb); execute_task(ccc) }
|
100
|
+
eee = new_task(@config, :eee) { transaction { execute_task(ddd); execute_task(aaa); raise "boom" } }
|
101
|
+
assert_raises(RuntimeError) do
|
102
|
+
@config.execute_task(eee)
|
103
|
+
end
|
104
|
+
assert_equal [:aaa, :bbb, :ddd], @config.state[:rollback]
|
105
|
+
assert_nil @config.rollback_requests
|
106
|
+
assert @config.task_call_frames.empty?
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_exception_during_rollback_should_simply_be_logged_and_ignored
|
110
|
+
aaa = new_task(@config, :aaa) { on_rollback { state[:aaa] = true; raise LoadError, "ouch" }; execute_task(bbb) }
|
111
|
+
bbb = new_task(@config, :bbb) { raise MadError, "boom" }
|
112
|
+
ccc = new_task(@config, :ccc) { transaction { execute_task(aaa) } }
|
113
|
+
assert_raises(NameError) do
|
114
|
+
@config.execute_task(ccc)
|
115
|
+
end
|
116
|
+
assert @config.state[:aaa]
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_find_and_execute_task_should_raise_error_when_task_cannot_be_found
|
120
|
+
@config.expects(:find_task).with("path:to:task").returns(nil)
|
121
|
+
assert_raises(Capistrano::NoSuchTaskError) { @config.find_and_execute_task("path:to:task") }
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_find_and_execute_task_should_execute_task_when_task_is_found
|
125
|
+
@config.expects(:find_task).with("path:to:task").returns(:found)
|
126
|
+
@config.expects(:execute_task).with(:found)
|
127
|
+
assert_nothing_raised { @config.find_and_execute_task("path:to:task") }
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_find_and_execute_task_with_before_option_should_trigger_callback
|
131
|
+
@config.expects(:find_task).with("path:to:task").returns(:found)
|
132
|
+
@config.expects(:trigger).with(:incoming, :found)
|
133
|
+
@config.expects(:execute_task).with(:found)
|
134
|
+
@config.find_and_execute_task("path:to:task", :before => :incoming)
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_find_and_execute_task_with_after_option_should_trigger_callback
|
138
|
+
@config.expects(:find_task).with("path:to:task").returns(:found)
|
139
|
+
@config.expects(:trigger).with(:outgoing, :found)
|
140
|
+
@config.expects(:execute_task).with(:found)
|
141
|
+
@config.find_and_execute_task("path:to:task", :after => :outgoing)
|
142
|
+
end
|
143
|
+
|
144
|
+
private
|
145
|
+
|
146
|
+
def stack_inspector
|
147
|
+
Proc.new do
|
148
|
+
(state[:trail] ||= []) << current_task.fully_qualified_name
|
149
|
+
data = state[current_task.name] = {}
|
150
|
+
data[:stack] = task_call_frames.map { |frame| frame.task.fully_qualified_name }
|
151
|
+
data[:history] = rollback_requests && rollback_requests.map { |frame| frame.task.fully_qualified_name }
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def new_task(namespace, name, options={}, &block)
|
156
|
+
block ||= stack_inspector
|
157
|
+
namespace.tasks[name] = Capistrano::TaskDefinition.new(name, namespace, &block)
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../utils"
|
2
|
+
require 'capistrano/configuration/loading'
|
3
|
+
|
4
|
+
class ConfigurationLoadingTest < Test::Unit::TestCase
|
5
|
+
class MockConfig
|
6
|
+
attr_accessor :ping
|
7
|
+
attr_reader :original_initialize_called
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@original_initialize_called = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def ping!(value)
|
14
|
+
@ping = value
|
15
|
+
end
|
16
|
+
|
17
|
+
include Capistrano::Configuration::Loading
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup
|
21
|
+
@config = MockConfig.new
|
22
|
+
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
MockConfig.instance = nil
|
26
|
+
$".delete "#{File.dirname(__FILE__)}/../fixtures/custom.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_initialize_should_init_collections
|
30
|
+
assert @config.original_initialize_called
|
31
|
+
assert @config.load_paths.include?(".")
|
32
|
+
assert @config.load_paths.detect { |v| v =~ /capistrano\/recipes$/ }
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_load_with_options_and_block_should_raise_argument_error
|
36
|
+
assert_raises(ArgumentError) do
|
37
|
+
@config.load(:string => "foo") { something }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_load_with_arguments_and_block_should_raise_argument_error
|
42
|
+
assert_raises(ArgumentError) do
|
43
|
+
@config.load("foo") { something }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_load_from_string_should_eval_in_config_scope
|
48
|
+
@config.load :string => "ping! :here"
|
49
|
+
assert_equal :here, @config.ping
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_load_from_file_shoudld_respect_load_path
|
53
|
+
File.stubs(:file?).returns(false)
|
54
|
+
File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
|
55
|
+
File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
|
56
|
+
|
57
|
+
@config.load_paths << "custom/path/for"
|
58
|
+
@config.load :file => "file.rb"
|
59
|
+
|
60
|
+
assert_equal :here, @config.ping
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_load_from_file_should_respect_load_path_and_appends_rb
|
64
|
+
File.stubs(:file?).returns(false)
|
65
|
+
File.stubs(:file?).with("custom/path/for/file.rb").returns(true)
|
66
|
+
File.stubs(:read).with("custom/path/for/file.rb").returns("ping! :here")
|
67
|
+
|
68
|
+
@config.load_paths << "custom/path/for"
|
69
|
+
@config.load :file => "file"
|
70
|
+
|
71
|
+
assert_equal :here, @config.ping
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_load_from_file_should_raise_load_error_if_file_cannot_be_found
|
75
|
+
File.stubs(:file?).returns(false)
|
76
|
+
assert_raises(LoadError) do
|
77
|
+
@config.load :file => "file"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_load_from_proc_should_eval_proc_in_config_scope
|
82
|
+
@config.load :proc => Proc.new { ping! :here }
|
83
|
+
assert_equal :here, @config.ping
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_load_with_block_should_treat_block_as_proc_parameter
|
87
|
+
@config.load { ping! :here }
|
88
|
+
assert_equal :here, @config.ping
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_load_with_unrecognized_option_should_raise_argument_error
|
92
|
+
assert_raises(ArgumentError) do
|
93
|
+
@config.load :url => "http://www.load-this.test"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_load_with_arguments_should_treat_arguments_as_files
|
98
|
+
File.stubs(:file?).returns(false)
|
99
|
+
File.stubs(:file?).with("./first.rb").returns(true)
|
100
|
+
File.stubs(:file?).with("./second.rb").returns(true)
|
101
|
+
File.stubs(:read).with("./first.rb").returns("ping! 'this'")
|
102
|
+
File.stubs(:read).with("./second.rb").returns("ping << 'that'")
|
103
|
+
assert_nothing_raised { @config.load "first", "second" }
|
104
|
+
assert_equal "thisthat", @config.ping
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_require_from_config_should_load_file_in_config_scope
|
108
|
+
assert_nothing_raised do
|
109
|
+
@config.require "#{File.dirname(__FILE__)}/../fixtures/custom"
|
110
|
+
end
|
111
|
+
assert_equal :custom, @config.ping
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_require_without_config_should_raise_load_error
|
115
|
+
assert_raises(LoadError) do
|
116
|
+
require "#{File.dirname(__FILE__)}/../fixtures/custom"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|