capistrano 1.4.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/CHANGELOG +140 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README +22 -14
  4. data/bin/cap +1 -8
  5. data/bin/capify +77 -0
  6. data/examples/sample.rb +10 -109
  7. data/lib/capistrano.rb +1 -0
  8. data/lib/capistrano/callback.rb +41 -0
  9. data/lib/capistrano/cli.rb +17 -317
  10. data/lib/capistrano/cli/execute.rb +82 -0
  11. data/lib/capistrano/cli/help.rb +102 -0
  12. data/lib/capistrano/cli/help.txt +53 -0
  13. data/lib/capistrano/cli/options.rb +183 -0
  14. data/lib/capistrano/cli/ui.rb +28 -0
  15. data/lib/capistrano/command.rb +62 -29
  16. data/lib/capistrano/configuration.rb +25 -226
  17. data/lib/capistrano/configuration/actions/file_transfer.rb +35 -0
  18. data/lib/capistrano/configuration/actions/inspect.rb +46 -0
  19. data/lib/capistrano/configuration/actions/invocation.rb +127 -0
  20. data/lib/capistrano/configuration/callbacks.rb +148 -0
  21. data/lib/capistrano/configuration/connections.rb +159 -0
  22. data/lib/capistrano/configuration/execution.rb +126 -0
  23. data/lib/capistrano/configuration/loading.rb +112 -0
  24. data/lib/capistrano/configuration/namespaces.rb +190 -0
  25. data/lib/capistrano/configuration/roles.rb +51 -0
  26. data/lib/capistrano/configuration/servers.rb +75 -0
  27. data/lib/capistrano/configuration/variables.rb +127 -0
  28. data/lib/capistrano/errors.rb +15 -0
  29. data/lib/capistrano/extensions.rb +27 -8
  30. data/lib/capistrano/gateway.rb +54 -29
  31. data/lib/capistrano/logger.rb +11 -11
  32. data/lib/capistrano/recipes/compat.rb +32 -0
  33. data/lib/capistrano/recipes/deploy.rb +483 -0
  34. data/lib/capistrano/recipes/deploy/dependencies.rb +44 -0
  35. data/lib/capistrano/recipes/deploy/local_dependency.rb +46 -0
  36. data/lib/capistrano/recipes/deploy/remote_dependency.rb +65 -0
  37. data/lib/capistrano/recipes/deploy/scm.rb +19 -0
  38. data/lib/capistrano/recipes/deploy/scm/base.rb +180 -0
  39. data/lib/capistrano/recipes/deploy/scm/bzr.rb +86 -0
  40. data/lib/capistrano/recipes/deploy/scm/cvs.rb +151 -0
  41. data/lib/capistrano/recipes/deploy/scm/darcs.rb +85 -0
  42. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +129 -0
  43. data/lib/capistrano/recipes/deploy/scm/perforce.rb +126 -0
  44. data/lib/capistrano/recipes/deploy/scm/subversion.rb +103 -0
  45. data/lib/capistrano/recipes/deploy/strategy.rb +19 -0
  46. data/lib/capistrano/recipes/deploy/strategy/base.rb +64 -0
  47. data/lib/capistrano/recipes/deploy/strategy/checkout.rb +20 -0
  48. data/lib/capistrano/recipes/deploy/strategy/copy.rb +143 -0
  49. data/lib/capistrano/recipes/deploy/strategy/export.rb +20 -0
  50. data/lib/capistrano/recipes/deploy/strategy/remote.rb +52 -0
  51. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +47 -0
  52. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +53 -0
  53. data/lib/capistrano/recipes/standard.rb +26 -276
  54. data/lib/capistrano/recipes/templates/maintenance.rhtml +1 -1
  55. data/lib/capistrano/recipes/upgrade.rb +33 -0
  56. data/lib/capistrano/server_definition.rb +51 -0
  57. data/lib/capistrano/shell.rb +125 -81
  58. data/lib/capistrano/ssh.rb +80 -36
  59. data/lib/capistrano/task_definition.rb +69 -0
  60. data/lib/capistrano/upload.rb +146 -0
  61. data/lib/capistrano/version.rb +13 -17
  62. data/test/cli/execute_test.rb +132 -0
  63. data/test/cli/help_test.rb +139 -0
  64. data/test/cli/options_test.rb +226 -0
  65. data/test/cli/ui_test.rb +28 -0
  66. data/test/cli_test.rb +17 -0
  67. data/test/command_test.rb +284 -25
  68. data/test/configuration/actions/file_transfer_test.rb +40 -0
  69. data/test/configuration/actions/inspect_test.rb +62 -0
  70. data/test/configuration/actions/invocation_test.rb +195 -0
  71. data/test/configuration/callbacks_test.rb +206 -0
  72. data/test/configuration/connections_test.rb +288 -0
  73. data/test/configuration/execution_test.rb +159 -0
  74. data/test/configuration/loading_test.rb +119 -0
  75. data/test/configuration/namespace_dsl_test.rb +283 -0
  76. data/test/configuration/roles_test.rb +47 -0
  77. data/test/configuration/servers_test.rb +90 -0
  78. data/test/configuration/variables_test.rb +180 -0
  79. data/test/configuration_test.rb +60 -212
  80. data/test/deploy/scm/base_test.rb +55 -0
  81. data/test/deploy/strategy/copy_test.rb +146 -0
  82. data/test/extensions_test.rb +69 -0
  83. data/test/fixtures/cli_integration.rb +5 -0
  84. data/test/fixtures/custom.rb +2 -2
  85. data/test/gateway_test.rb +167 -0
  86. data/test/logger_test.rb +123 -0
  87. data/test/server_definition_test.rb +108 -0
  88. data/test/shell_test.rb +64 -0
  89. data/test/ssh_test.rb +67 -154
  90. data/test/task_definition_test.rb +101 -0
  91. data/test/upload_test.rb +131 -0
  92. data/test/utils.rb +31 -39
  93. data/test/version_test.rb +24 -0
  94. metadata +145 -98
  95. data/THANKS +0 -4
  96. data/lib/capistrano/actor.rb +0 -567
  97. data/lib/capistrano/generators/rails/deployment/deployment_generator.rb +0 -25
  98. data/lib/capistrano/generators/rails/deployment/templates/capistrano.rake +0 -49
  99. data/lib/capistrano/generators/rails/deployment/templates/deploy.rb +0 -122
  100. data/lib/capistrano/generators/rails/loader.rb +0 -20
  101. data/lib/capistrano/scm/base.rb +0 -61
  102. data/lib/capistrano/scm/baz.rb +0 -118
  103. data/lib/capistrano/scm/bzr.rb +0 -70
  104. data/lib/capistrano/scm/cvs.rb +0 -129
  105. data/lib/capistrano/scm/darcs.rb +0 -27
  106. data/lib/capistrano/scm/mercurial.rb +0 -83
  107. data/lib/capistrano/scm/perforce.rb +0 -139
  108. data/lib/capistrano/scm/subversion.rb +0 -128
  109. data/lib/capistrano/transfer.rb +0 -97
  110. data/lib/capistrano/utils.rb +0 -26
  111. data/test/actor_test.rb +0 -402
  112. data/test/scm/cvs_test.rb +0 -196
  113. 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
@@ -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
@@ -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
@@ -1,43 +1,302 @@
1
- $:.unshift File.dirname(__FILE__) + "/../lib"
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
- class MockSession
9
- def open_channel
10
- { :closed => true, :status => 0 }
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
- class MockActor
15
- attr_reader :sessions
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
- def initialize
18
- @sessions = Hash.new { |h,k| h[k] = MockSession.new }
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 setup
23
- @actor = MockActor.new
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 test_command_executes_on_all_servers
27
- command = Capistrano::Command.new(%w(server1 server2 server3),
28
- "hello", nil, {}, @actor)
29
- assert_equal %w(server1 server2 server3), @actor.sessions.keys.sort
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 test_command_with_newlines
33
- command = Capistrano::Command.new(%w(server1), "hello\nworld", nil, {},
34
- @actor)
35
- assert_equal "hello\\\nworld", command.command
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 test_command_with_windows_newlines
39
- command = Capistrano::Command.new(%w(server1), "hello\r\nworld", nil, {},
40
- @actor)
41
- assert_equal "hello\\\nworld", command.command
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