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,226 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../utils"
|
2
|
+
require 'capistrano/cli/options'
|
3
|
+
|
4
|
+
class CLIOptionsTest < Test::Unit::TestCase
|
5
|
+
class ExitException < Exception; end
|
6
|
+
|
7
|
+
class MockCLI
|
8
|
+
def initialize
|
9
|
+
@args = []
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :args
|
13
|
+
|
14
|
+
include Capistrano::CLI::Options
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup
|
18
|
+
@cli = MockCLI.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_parse_options_should_require_non_empty_args_list
|
22
|
+
@cli.stubs(:warn)
|
23
|
+
@cli.expects(:exit).raises(ExitException)
|
24
|
+
assert_raises(ExitException) { @cli.parse_options! }
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_parse_options_with_e_should_set_explain_option
|
28
|
+
@cli.args << "-e" << "sample"
|
29
|
+
@cli.parse_options!
|
30
|
+
assert_equal "sample", @cli.options[:explain]
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_parse_options_with_f_should_add_recipe_file
|
34
|
+
@cli.args << "-f" << "deploy"
|
35
|
+
@cli.parse_options!
|
36
|
+
assert_equal %w(deploy), @cli.options[:recipes]
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_parse_options_with_multiple_f_should_add_each_as_recipe_file
|
40
|
+
@cli.args << "-f" << "deploy" << "-f" << "monitor"
|
41
|
+
@cli.parse_options!
|
42
|
+
assert_equal %w(deploy monitor), @cli.options[:recipes]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_parse_options_with_H_should_show_verbose_help_and_exit
|
46
|
+
@cli.expects(:exit).raises(ExitException)
|
47
|
+
@cli.expects(:long_help)
|
48
|
+
@cli.args << "-H"
|
49
|
+
assert_raises(ExitException) { @cli.parse_options! }
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_parse_options_with_h_should_show_options_and_exit
|
53
|
+
@cli.expects(:puts).with(@cli.option_parser)
|
54
|
+
@cli.expects(:exit).raises(ExitException)
|
55
|
+
@cli.args << "-h"
|
56
|
+
assert_raises(ExitException) { @cli.parse_options! }
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_parse_options_with_p_should_prompt_for_password
|
60
|
+
MockCLI.expects(:password_prompt).returns(:the_password)
|
61
|
+
@cli.args << "-p"
|
62
|
+
@cli.parse_options!
|
63
|
+
assert_equal :the_password, @cli.options[:password]
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_parse_options_without_p_should_set_proc_for_password
|
67
|
+
@cli.args << "-e" << "sample"
|
68
|
+
@cli.parse_options!
|
69
|
+
assert_instance_of Proc, @cli.options[:password]
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_parse_options_with_q_should_set_verbose_to_0
|
73
|
+
@cli.args << "-q"
|
74
|
+
@cli.parse_options!
|
75
|
+
assert_equal 0, @cli.options[:verbose]
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_parse_options_with_S_should_set_pre_vars
|
79
|
+
@cli.args << "-S" << "foo=bar"
|
80
|
+
@cli.parse_options!
|
81
|
+
assert_equal "bar", @cli.options[:pre_vars][:foo]
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_parse_options_with_s_should_set_vars
|
85
|
+
@cli.args << "-s" << "foo=bar"
|
86
|
+
@cli.parse_options!
|
87
|
+
assert_equal "bar", @cli.options[:vars][:foo]
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_parse_options_with_T_should_set_tasks_option_and_set_verbose_off
|
91
|
+
@cli.args << "-T"
|
92
|
+
@cli.parse_options!
|
93
|
+
assert @cli.options[:tasks]
|
94
|
+
assert_equal 0, @cli.options[:verbose]
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_parse_options_with_V_should_show_version_and_exit
|
98
|
+
@cli.args << "-V"
|
99
|
+
@cli.expects(:puts).with { |s| s.include?(Capistrano::Version::STRING) }
|
100
|
+
@cli.expects(:exit).raises(ExitException)
|
101
|
+
assert_raises(ExitException) { @cli.parse_options! }
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_parse_options_with_v_should_set_verbose_to_1
|
105
|
+
@cli.args << "-v"
|
106
|
+
@cli.parse_options!
|
107
|
+
assert_equal 1, @cli.options[:verbose]
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_parse_options_with_multiple_v_should_set_verbose_accordingly
|
111
|
+
@cli.args << "-vvvvvvv"
|
112
|
+
@cli.parse_options!
|
113
|
+
assert_equal 7, @cli.options[:verbose]
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_parse_options_without_X_should_set_sysconf
|
117
|
+
@cli.args << "-v"
|
118
|
+
@cli.parse_options!
|
119
|
+
assert @cli.options.key?(:sysconf)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_parse_options_with_X_should_unset_sysconf
|
123
|
+
@cli.args << "-X"
|
124
|
+
@cli.parse_options!
|
125
|
+
assert !@cli.options.key?(:sysconf)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_parse_options_without_x_should_set_dotfile
|
129
|
+
@cli.args << "-v"
|
130
|
+
@cli.parse_options!
|
131
|
+
assert @cli.options.key?(:dotfile)
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_parse_options_with_x_should_unset_dotfile
|
135
|
+
@cli.args << "-x"
|
136
|
+
@cli.parse_options!
|
137
|
+
assert !@cli.options.key?(:dotfile)
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_parse_options_without_q_or_v_should_set_verbose_to_3
|
141
|
+
@cli.args << "-x"
|
142
|
+
@cli.parse_options!
|
143
|
+
assert_equal 3, @cli.options[:verbose]
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_should_search_for_default_recipes_if_f_not_given
|
147
|
+
@cli.expects(:look_for_default_recipe_file!)
|
148
|
+
@cli.args << "-v"
|
149
|
+
@cli.parse_options!
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_should_not_search_for_default_recipes_if_f_given
|
153
|
+
@cli.expects(:look_for_default_recipe_file!).never
|
154
|
+
@cli.args << "-f" << "hello"
|
155
|
+
@cli.parse_options!
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_F_should_search_for_default_recipes_even_if_f_is_given
|
159
|
+
@cli.expects(:look_for_default_recipe_file!)
|
160
|
+
@cli.args << "-Ff" << "hello"
|
161
|
+
@cli.parse_options!
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_should_extract_env_vars_from_command_line
|
165
|
+
assert_nil ENV["HELLO"]
|
166
|
+
assert_nil ENV["ANOTHER"]
|
167
|
+
|
168
|
+
@cli.args << "HELLO=world" << "hello" << "ANOTHER=value"
|
169
|
+
@cli.parse_options!
|
170
|
+
|
171
|
+
assert_equal "world", ENV["HELLO"]
|
172
|
+
assert_equal "value", ENV["ANOTHER"]
|
173
|
+
ensure
|
174
|
+
ENV["HELLO"] = ENV["ANOTHER"] = nil
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_remaining_args_should_be_added_to_actions_list
|
178
|
+
@cli.args << "-v" << "HELLO=world" << "-f" << "foo" << "something" << "else"
|
179
|
+
@cli.parse_options!
|
180
|
+
assert_equal %w(something else), @cli.args
|
181
|
+
ensure
|
182
|
+
ENV["HELLO"] = nil
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_search_for_default_recipe_file_should_look_for_Capfile
|
186
|
+
File.stubs(:file?).returns(false)
|
187
|
+
File.expects(:file?).with("Capfile").returns(true)
|
188
|
+
@cli.args << "-v"
|
189
|
+
@cli.parse_options!
|
190
|
+
assert_equal %w(Capfile), @cli.options[:recipes]
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_search_for_default_recipe_file_should_look_for_capfile
|
194
|
+
File.stubs(:file?).returns(false)
|
195
|
+
File.expects(:file?).with("capfile").returns(true)
|
196
|
+
@cli.args << "-v"
|
197
|
+
@cli.parse_options!
|
198
|
+
assert_equal %w(capfile), @cli.options[:recipes]
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_search_for_default_recipe_should_hike_up_the_directory_tree_until_it_finds_default_recipe
|
202
|
+
File.stubs(:file?).returns(false)
|
203
|
+
File.expects(:file?).with("capfile").times(2).returns(false,true)
|
204
|
+
Dir.expects(:pwd).times(3).returns(*%w(/bar/baz /bar/baz /bar))
|
205
|
+
Dir.expects(:chdir).with("..")
|
206
|
+
@cli.args << "-v"
|
207
|
+
@cli.parse_options!
|
208
|
+
assert_equal %w(capfile), @cli.options[:recipes]
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_search_for_default_recipe_should_halt_at_root_directory
|
212
|
+
File.stubs(:file?).returns(false)
|
213
|
+
Dir.expects(:pwd).times(7).returns(*%w(/bar/baz /bar/baz /bar /bar / / /))
|
214
|
+
Dir.expects(:chdir).with("..").times(3)
|
215
|
+
Dir.expects(:chdir).with("/bar/baz")
|
216
|
+
@cli.args << "-v"
|
217
|
+
@cli.parse_options!
|
218
|
+
assert @cli.options[:recipes].empty?
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_parse_should_instantiate_new_cli_and_call_parse_options
|
222
|
+
cli = mock("cli", :parse_options! => nil)
|
223
|
+
MockCLI.expects(:new).with(%w(a b c)).returns(cli)
|
224
|
+
assert_equal cli, MockCLI.parse(%w(a b c))
|
225
|
+
end
|
226
|
+
end
|
data/test/cli/ui_test.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../utils"
|
2
|
+
require 'capistrano/cli/ui'
|
3
|
+
|
4
|
+
class CLIUITest < Test::Unit::TestCase
|
5
|
+
class MockCLI
|
6
|
+
include Capistrano::CLI::UI
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_ui_should_return_highline_instance
|
10
|
+
assert_instance_of HighLine, MockCLI.ui
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_password_prompt_should_have_default_prompt_and_set_echo_false
|
14
|
+
q = mock("question")
|
15
|
+
q.expects(:echo=).with(false)
|
16
|
+
ui = mock("ui")
|
17
|
+
ui.expects(:ask).with("Password: ").yields(q).returns("sayuncle")
|
18
|
+
MockCLI.expects(:ui).returns(ui)
|
19
|
+
assert_equal "sayuncle", MockCLI.password_prompt
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_password_prompt_with_custom_prompt_should_use_custom_prompt
|
23
|
+
ui = mock("ui")
|
24
|
+
ui.expects(:ask).with("Give the passphrase: ").returns("sayuncle")
|
25
|
+
MockCLI.expects(:ui).returns(ui)
|
26
|
+
assert_equal "sayuncle", MockCLI.password_prompt("Give the passphrase: ")
|
27
|
+
end
|
28
|
+
end
|
data/test/cli_test.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "#{File.dirname(__FILE__)}/utils"
|
2
|
+
require 'capistrano/cli'
|
3
|
+
|
4
|
+
class CLI_Test < Test::Unit::TestCase
|
5
|
+
def test_options_ui_and_help_modules_should_integrate_successfully_with_configuration
|
6
|
+
cli = Capistrano::CLI.parse(%w(-T))
|
7
|
+
cli.expects(:puts).at_least_once
|
8
|
+
cli.execute!
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_options_and_execute_modules_should_integrate_successfully_with_configuration
|
12
|
+
path = "#{File.dirname(__FILE__)}/fixtures/cli_integration.rb"
|
13
|
+
cli = Capistrano::CLI.parse(%W(-q -f #{path} testing))
|
14
|
+
config = cli.execute!
|
15
|
+
assert config[:testing_occurred]
|
16
|
+
end
|
17
|
+
end
|
data/test/command_test.rb
CHANGED
@@ -1,43 +1,302 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'stringio'
|
4
|
-
require 'test/unit'
|
1
|
+
require "#{File.dirname(__FILE__)}/utils"
|
5
2
|
require 'capistrano/command'
|
6
3
|
|
7
4
|
class CommandTest < Test::Unit::TestCase
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
def test_command_should_open_channels_on_all_sessions
|
6
|
+
s1 = mock(:open_channel => nil)
|
7
|
+
s2 = mock(:open_channel => nil)
|
8
|
+
s3 = mock(:open_channel => nil)
|
9
|
+
assert_equal "ls", Capistrano::Command.new("ls", [s1, s2, s3]).command
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_command_with_newlines_should_be_properly_escaped
|
13
|
+
cmd = Capistrano::Command.new("ls\necho", [mock(:open_channel => nil)])
|
14
|
+
assert_equal "ls\\\necho", cmd.command
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_command_with_windows_newlines_should_be_properly_escaped
|
18
|
+
cmd = Capistrano::Command.new("ls\r\necho", [mock(:open_channel => nil)])
|
19
|
+
assert_equal "ls\\\necho", cmd.command
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_command_with_env_key_should_have_environment_constructed_and_prepended
|
23
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
24
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
|
25
|
+
end
|
26
|
+
Capistrano::Command.new("ls", [session], :env => { "FOO" => "bar" })
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_env_with_symbolic_key_should_be_accepted_as_a_string
|
30
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
31
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
|
32
|
+
end
|
33
|
+
Capistrano::Command.new("ls", [session], :env => { :FOO => "bar" })
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_env_as_string_should_be_substituted_in_directly
|
37
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
38
|
+
ch.expects(:exec).with(%(env HOWDY=there sh -c "ls"))
|
39
|
+
end
|
40
|
+
Capistrano::Command.new("ls", [session], :env => "HOWDY=there")
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_env_with_symbolic_value_should_be_accepted_as_string
|
44
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
45
|
+
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
|
46
|
+
end
|
47
|
+
Capistrano::Command.new("ls", [session], :env => { "FOO" => :bar })
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_env_value_should_be_escaped
|
51
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
52
|
+
ch.expects(:exec).with(%(env FOO=(\\ \\\"bar\\\"\\ ) sh -c "ls"))
|
53
|
+
end
|
54
|
+
Capistrano::Command.new("ls", [session], :env => { "FOO" => '( "bar" )' })
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_env_with_multiple_keys_should_chain_the_entries_together
|
58
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
59
|
+
ch.expects(:exec).with do |command|
|
60
|
+
command =~ /^env / &&
|
61
|
+
command =~ /\ba=b\b/ &&
|
62
|
+
command =~ /\bc=d\b/ &&
|
63
|
+
command =~ /\be=f\b/ &&
|
64
|
+
command =~ / sh -c "ls"$/
|
65
|
+
end
|
11
66
|
end
|
67
|
+
Capistrano::Command.new("ls", [session], :env => { :a => :b, :c => :d, :e => :f })
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_open_channel_should_set_host_key_on_channel
|
71
|
+
session = mock(:xserver => server("capistrano"))
|
72
|
+
channel = stub_everything
|
73
|
+
|
74
|
+
session.expects(:open_channel).yields(channel)
|
75
|
+
channel.expects(:[]=).with(:host, "capistrano")
|
76
|
+
|
77
|
+
Capistrano::Command.new("ls", [session])
|
12
78
|
end
|
13
79
|
|
14
|
-
|
15
|
-
|
80
|
+
def test_open_channel_should_set_options_key_on_channel
|
81
|
+
session = mock(:xserver => server("capistrano"))
|
82
|
+
channel = stub_everything
|
83
|
+
|
84
|
+
session.expects(:open_channel).yields(channel)
|
85
|
+
channel.expects(:[]=).with(:options, {:data => "here we go"})
|
16
86
|
|
17
|
-
|
18
|
-
|
87
|
+
Capistrano::Command.new("ls", [session], :data => "here we go")
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_open_channel_should_request_pty
|
91
|
+
session = mock(:xserver => server("capistrano"))
|
92
|
+
channel = stub_everything
|
93
|
+
|
94
|
+
session.expects(:open_channel).yields(channel)
|
95
|
+
channel.expects(:request_pty).with(:want_reply => true)
|
96
|
+
|
97
|
+
Capistrano::Command.new("ls", [session])
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_successful_channel_should_send_command
|
101
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
102
|
+
ch.expects(:exec).with(%(sh -c "ls"))
|
19
103
|
end
|
104
|
+
Capistrano::Command.new("ls", [session])
|
20
105
|
end
|
21
106
|
|
22
|
-
def
|
23
|
-
|
107
|
+
def test_successful_channel_with_shell_option_should_send_command_via_specified_shell
|
108
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
109
|
+
ch.expects(:exec).with(%(/bin/bash -c "ls"))
|
110
|
+
end
|
111
|
+
Capistrano::Command.new("ls", [session], :shell => "/bin/bash")
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_successful_channel_should_send_data_if_data_key_is_present
|
115
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
116
|
+
ch.expects(:exec).with(%(sh -c "ls"))
|
117
|
+
ch.expects(:send_data).with("here we go")
|
118
|
+
end
|
119
|
+
Capistrano::Command.new("ls", [session], :data => "here we go")
|
24
120
|
end
|
25
121
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
122
|
+
def test_unsuccessful_channel_should_close_channel
|
123
|
+
session = setup_for_extracting_channel_action(:on_failure) do |ch|
|
124
|
+
ch.expects(:close)
|
125
|
+
end
|
126
|
+
Capistrano::Command.new("ls", [session])
|
30
127
|
end
|
31
128
|
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
129
|
+
def test_on_data_should_invoke_callback_as_stdout
|
130
|
+
session = setup_for_extracting_channel_action(:on_data, "hello")
|
131
|
+
called = false
|
132
|
+
Capistrano::Command.new("ls", [session]) do |ch, stream, data|
|
133
|
+
called = true
|
134
|
+
assert_equal :out, stream
|
135
|
+
assert_equal "hello", data
|
136
|
+
end
|
137
|
+
assert called
|
36
138
|
end
|
37
139
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
140
|
+
def test_on_extended_data_should_invoke_callback_as_stderr
|
141
|
+
session = setup_for_extracting_channel_action(:on_extended_data, 2, "hello")
|
142
|
+
called = false
|
143
|
+
Capistrano::Command.new("ls", [session]) do |ch, stream, data|
|
144
|
+
called = true
|
145
|
+
assert_equal :err, stream
|
146
|
+
assert_equal "hello", data
|
147
|
+
end
|
148
|
+
assert called
|
42
149
|
end
|
150
|
+
|
151
|
+
def test_on_request_should_record_exit_status
|
152
|
+
data = mock(:read_long => 5)
|
153
|
+
session = setup_for_extracting_channel_action(:on_request, "exit-status", nil, data) do |ch|
|
154
|
+
ch.expects(:[]=).with(:status, 5)
|
155
|
+
end
|
156
|
+
Capistrano::Command.new("ls", [session])
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_on_close_should_set_channel_closed
|
160
|
+
session = setup_for_extracting_channel_action(:on_close) do |ch|
|
161
|
+
ch.expects(:[]=).with(:closed, true)
|
162
|
+
end
|
163
|
+
Capistrano::Command.new("ls", [session])
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_stop_should_close_all_open_channels
|
167
|
+
sessions = [mock("session", :open_channel => new_channel(false)),
|
168
|
+
mock("session", :open_channel => new_channel(true)),
|
169
|
+
mock("session", :open_channel => new_channel(false))]
|
170
|
+
|
171
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
172
|
+
cmd.stop!
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_process_should_return_cleanly_if_all_channels_have_zero_exit_status
|
176
|
+
sessions = [mock("session", :open_channel => new_channel(true, 0)),
|
177
|
+
mock("session", :open_channel => new_channel(true, 0)),
|
178
|
+
mock("session", :open_channel => new_channel(true, 0))]
|
179
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
180
|
+
assert_nothing_raised { cmd.process! }
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_process_should_raise_error_if_any_channel_has_non_zero_exit_status
|
184
|
+
sessions = [mock("session", :open_channel => new_channel(true, 0)),
|
185
|
+
mock("session", :open_channel => new_channel(true, 0)),
|
186
|
+
mock("session", :open_channel => new_channel(true, 1))]
|
187
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
188
|
+
assert_raises(Capistrano::CommandError) { cmd.process! }
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_command_error_should_include_accessor_with_host_array
|
192
|
+
sessions = [mock("session", :open_channel => new_channel(true, 0)),
|
193
|
+
mock("session", :open_channel => new_channel(true, 0)),
|
194
|
+
mock("session", :open_channel => new_channel(true, 1))]
|
195
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
196
|
+
|
197
|
+
begin
|
198
|
+
cmd.process!
|
199
|
+
flunk "expected an exception to be raised"
|
200
|
+
rescue Capistrano::CommandError => e
|
201
|
+
assert e.respond_to?(:hosts)
|
202
|
+
assert_equal %w(capistrano), e.hosts.map { |h| h.to_s }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def test_process_should_loop_until_all_channels_are_closed
|
207
|
+
new_channel = Proc.new do |times|
|
208
|
+
ch = mock("channel")
|
209
|
+
returns = [false] * (times-1)
|
210
|
+
ch.stubs(:[]).with(:closed).returns(*(returns + [true]))
|
211
|
+
con = mock("connection")
|
212
|
+
con.expects(:process).with(true).times(times-1)
|
213
|
+
ch.expects(:connection).times(times-1).returns(con)
|
214
|
+
ch.expects(:[]).with(:status).returns(0)
|
215
|
+
ch
|
216
|
+
end
|
217
|
+
|
218
|
+
sessions = [mock("session", :open_channel => new_channel[5]),
|
219
|
+
mock("session", :open_channel => new_channel[10]),
|
220
|
+
mock("session", :open_channel => new_channel[7])]
|
221
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
222
|
+
assert_nothing_raised { cmd.process! }
|
223
|
+
end
|
224
|
+
|
225
|
+
def test_process_should_ping_all_connections_each_second
|
226
|
+
now = Time.now
|
227
|
+
|
228
|
+
new_channel = Proc.new do
|
229
|
+
ch = mock("channel")
|
230
|
+
ch.stubs(:now => now)
|
231
|
+
def ch.[](key)
|
232
|
+
case key
|
233
|
+
when :status then 0
|
234
|
+
when :closed then Time.now - now < 1.1 ? false : true
|
235
|
+
else raise "unknown key: #{key}"
|
236
|
+
end
|
237
|
+
end
|
238
|
+
con = mock("connection")
|
239
|
+
con.stubs(:process)
|
240
|
+
con.expects(:ping!)
|
241
|
+
ch.stubs(:connection).returns(con)
|
242
|
+
ch
|
243
|
+
end
|
244
|
+
|
245
|
+
sessions = [mock("session", :open_channel => new_channel[]),
|
246
|
+
mock("session", :open_channel => new_channel[]),
|
247
|
+
mock("session", :open_channel => new_channel[])]
|
248
|
+
cmd = Capistrano::Command.new("ls", sessions)
|
249
|
+
assert_nothing_raised { cmd.process! }
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_process_should_instantiate_command_and_process!
|
253
|
+
cmd = mock("command", :process! => nil)
|
254
|
+
Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).yields(:command).returns(cmd)
|
255
|
+
parameter = nil
|
256
|
+
Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar") { |cmd| parameter = cmd }
|
257
|
+
assert_equal :command, parameter
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_process_with_host_placeholder_should_substitute_placeholder_with_each_host
|
261
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
262
|
+
ch.expects(:exec).with(%(sh -c "echo capistrano"))
|
263
|
+
end
|
264
|
+
Capistrano::Command.new("echo $CAPISTRANO:HOST$", [session])
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_process_with_unknown_placeholder_should_not_replace_placeholder
|
268
|
+
session = setup_for_extracting_channel_action(:on_success) do |ch|
|
269
|
+
ch.expects(:exec).with(%(sh -c "echo \\$CAPISTRANO:OTHER\\$"))
|
270
|
+
end
|
271
|
+
Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
275
|
+
|
276
|
+
def new_channel(closed, status=nil)
|
277
|
+
ch = mock("channel")
|
278
|
+
ch.expects(:[]).with(:closed).returns(closed)
|
279
|
+
ch.expects(:[]).with(:status).returns(status) if status
|
280
|
+
ch.expects(:close) unless closed
|
281
|
+
ch.stubs(:[]).with(:host).returns("capistrano")
|
282
|
+
ch.stubs(:[]).with(:server).returns(server("capistrano"))
|
283
|
+
ch
|
284
|
+
end
|
285
|
+
|
286
|
+
def setup_for_extracting_channel_action(action, *args)
|
287
|
+
s = server("capistrano")
|
288
|
+
session = mock("session", :xserver => s)
|
289
|
+
|
290
|
+
channel = stub_everything
|
291
|
+
session.expects(:open_channel).yields(channel)
|
292
|
+
|
293
|
+
ch = mock
|
294
|
+
ch.stubs(:[]).with(:server).returns(s)
|
295
|
+
ch.stubs(:[]).with(:host).returns(s.host)
|
296
|
+
channel.expects(action).yields(ch, *args)
|
297
|
+
|
298
|
+
yield ch if block_given?
|
299
|
+
|
300
|
+
session
|
301
|
+
end
|
43
302
|
end
|