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