capistrano 2.0.0 → 2.15.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 (125) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +715 -18
  5. data/Gemfile +12 -0
  6. data/README.md +94 -0
  7. data/Rakefile +11 -0
  8. data/bin/cap +0 -0
  9. data/bin/capify +37 -22
  10. data/capistrano.gemspec +40 -0
  11. data/lib/capistrano/callback.rb +5 -1
  12. data/lib/capistrano/cli/execute.rb +10 -7
  13. data/lib/capistrano/cli/help.rb +39 -16
  14. data/lib/capistrano/cli/help.txt +44 -16
  15. data/lib/capistrano/cli/options.rb +71 -11
  16. data/lib/capistrano/cli/ui.rb +13 -1
  17. data/lib/capistrano/cli.rb +5 -5
  18. data/lib/capistrano/command.rb +215 -58
  19. data/lib/capistrano/configuration/actions/file_transfer.rb +29 -14
  20. data/lib/capistrano/configuration/actions/inspect.rb +3 -3
  21. data/lib/capistrano/configuration/actions/invocation.rb +212 -22
  22. data/lib/capistrano/configuration/alias_task.rb +26 -0
  23. data/lib/capistrano/configuration/callbacks.rb +26 -27
  24. data/lib/capistrano/configuration/connections.rb +130 -52
  25. data/lib/capistrano/configuration/execution.rb +34 -18
  26. data/lib/capistrano/configuration/loading.rb +91 -6
  27. data/lib/capistrano/configuration/log_formatters.rb +75 -0
  28. data/lib/capistrano/configuration/namespaces.rb +45 -12
  29. data/lib/capistrano/configuration/roles.rb +28 -2
  30. data/lib/capistrano/configuration/servers.rb +51 -10
  31. data/lib/capistrano/configuration/variables.rb +3 -3
  32. data/lib/capistrano/configuration.rb +20 -4
  33. data/lib/capistrano/errors.rb +12 -8
  34. data/lib/capistrano/ext/multistage.rb +62 -0
  35. data/lib/capistrano/ext/string.rb +5 -0
  36. data/lib/capistrano/extensions.rb +1 -1
  37. data/lib/capistrano/fix_rake_deprecated_dsl.rb +8 -0
  38. data/lib/capistrano/logger.rb +112 -5
  39. data/lib/capistrano/processable.rb +55 -0
  40. data/lib/capistrano/recipes/compat.rb +2 -2
  41. data/lib/capistrano/recipes/deploy/assets.rb +185 -0
  42. data/lib/capistrano/recipes/deploy/dependencies.rb +2 -2
  43. data/lib/capistrano/recipes/deploy/local_dependency.rb +10 -2
  44. data/lib/capistrano/recipes/deploy/remote_dependency.rb +54 -2
  45. data/lib/capistrano/recipes/deploy/scm/accurev.rb +169 -0
  46. data/lib/capistrano/recipes/deploy/scm/base.rb +31 -11
  47. data/lib/capistrano/recipes/deploy/scm/bzr.rb +14 -14
  48. data/lib/capistrano/recipes/deploy/scm/cvs.rb +10 -8
  49. data/lib/capistrano/recipes/deploy/scm/darcs.rb +12 -1
  50. data/lib/capistrano/recipes/deploy/scm/git.rb +293 -0
  51. data/lib/capistrano/recipes/deploy/scm/mercurial.rb +23 -15
  52. data/lib/capistrano/recipes/deploy/scm/none.rb +55 -0
  53. data/lib/capistrano/recipes/deploy/scm/perforce.rb +54 -28
  54. data/lib/capistrano/recipes/deploy/scm/subversion.rb +35 -17
  55. data/lib/capistrano/recipes/deploy/scm.rb +1 -1
  56. data/lib/capistrano/recipes/deploy/strategy/base.rb +32 -4
  57. data/lib/capistrano/recipes/deploy/strategy/copy.rb +238 -43
  58. data/lib/capistrano/recipes/deploy/strategy/remote.rb +1 -1
  59. data/lib/capistrano/recipes/deploy/strategy/remote_cache.rb +11 -1
  60. data/lib/capistrano/recipes/deploy/strategy/unshared_remote_cache.rb +21 -0
  61. data/lib/capistrano/recipes/deploy/strategy.rb +1 -1
  62. data/lib/capistrano/recipes/deploy.rb +265 -123
  63. data/lib/capistrano/recipes/standard.rb +1 -1
  64. data/lib/capistrano/role.rb +102 -0
  65. data/lib/capistrano/server_definition.rb +6 -1
  66. data/lib/capistrano/shell.rb +30 -33
  67. data/lib/capistrano/ssh.rb +46 -60
  68. data/lib/capistrano/task_definition.rb +16 -8
  69. data/lib/capistrano/transfer.rb +218 -0
  70. data/lib/capistrano/version.rb +6 -17
  71. data/lib/capistrano.rb +4 -1
  72. data/test/cli/execute_test.rb +3 -3
  73. data/test/cli/help_test.rb +33 -7
  74. data/test/cli/options_test.rb +109 -6
  75. data/test/cli/ui_test.rb +2 -2
  76. data/test/cli_test.rb +3 -3
  77. data/test/command_test.rb +144 -124
  78. data/test/configuration/actions/file_transfer_test.rb +41 -20
  79. data/test/configuration/actions/inspect_test.rb +21 -7
  80. data/test/configuration/actions/invocation_test.rb +91 -30
  81. data/test/configuration/alias_task_test.rb +118 -0
  82. data/test/configuration/callbacks_test.rb +41 -46
  83. data/test/configuration/connections_test.rb +187 -36
  84. data/test/configuration/execution_test.rb +18 -2
  85. data/test/configuration/loading_test.rb +17 -4
  86. data/test/configuration/namespace_dsl_test.rb +54 -5
  87. data/test/configuration/roles_test.rb +114 -4
  88. data/test/configuration/servers_test.rb +97 -4
  89. data/test/configuration/variables_test.rb +12 -2
  90. data/test/configuration_test.rb +9 -13
  91. data/test/deploy/local_dependency_test.rb +76 -0
  92. data/test/deploy/remote_dependency_test.rb +146 -0
  93. data/test/deploy/scm/accurev_test.rb +23 -0
  94. data/test/deploy/scm/base_test.rb +1 -1
  95. data/test/deploy/scm/bzr_test.rb +51 -0
  96. data/test/deploy/scm/darcs_test.rb +37 -0
  97. data/test/deploy/scm/git_test.rb +221 -0
  98. data/test/deploy/scm/mercurial_test.rb +134 -0
  99. data/test/deploy/scm/none_test.rb +35 -0
  100. data/test/deploy/scm/perforce_test.rb +23 -0
  101. data/test/deploy/scm/subversion_test.rb +40 -0
  102. data/test/deploy/strategy/copy_test.rb +240 -26
  103. data/test/extensions_test.rb +2 -2
  104. data/test/logger_formatting_test.rb +149 -0
  105. data/test/logger_test.rb +13 -2
  106. data/test/recipes_test.rb +25 -0
  107. data/test/role_test.rb +11 -0
  108. data/test/server_definition_test.rb +15 -2
  109. data/test/shell_test.rb +33 -1
  110. data/test/ssh_test.rb +40 -24
  111. data/test/task_definition_test.rb +18 -2
  112. data/test/transfer_test.rb +168 -0
  113. data/test/utils.rb +27 -33
  114. metadata +215 -102
  115. data/MIT-LICENSE +0 -20
  116. data/README +0 -43
  117. data/examples/sample.rb +0 -14
  118. data/lib/capistrano/gateway.rb +0 -131
  119. data/lib/capistrano/recipes/deploy/templates/maintenance.rhtml +0 -53
  120. data/lib/capistrano/recipes/templates/maintenance.rhtml +0 -53
  121. data/lib/capistrano/recipes/upgrade.rb +0 -33
  122. data/lib/capistrano/upload.rb +0 -146
  123. data/test/gateway_test.rb +0 -167
  124. data/test/upload_test.rb +0 -131
  125. data/test/version_test.rb +0 -24
data/test/command_test.rb CHANGED
@@ -1,129 +1,127 @@
1
- require "#{File.dirname(__FILE__)}/utils"
1
+ require "utils"
2
2
  require 'capistrano/command'
3
+ require 'capistrano/configuration'
3
4
 
4
5
  class CommandTest < Test::Unit::TestCase
5
6
  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
7
+ s1, s2, s3 = mock_session, mock_session, mock_session
8
+ assert_equal "ls", Capistrano::Command.new("ls", [s1, s2, s3]).tree.fallback.command
10
9
  end
11
10
 
12
11
  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
12
+ cmd = Capistrano::Command.new("ls\necho", [mock_session])
13
+ assert_equal "ls\\\necho", cmd.tree.fallback.command
15
14
  end
16
15
 
17
16
  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
17
+ cmd = Capistrano::Command.new("ls\r\necho", [mock_session])
18
+ assert_equal "ls\\\necho", cmd.tree.fallback.command
19
+ end
20
+
21
+ def test_command_with_pty_should_request_pty_and_register_success_callback
22
+ session = setup_for_extracting_channel_action(:request_pty, true) do |ch|
23
+ ch.expects(:exec).with(%(sh -c 'ls'))
24
+ end
25
+ Capistrano::Command.new("ls", [session], :pty => true)
20
26
  end
21
27
 
22
28
  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"))
29
+ session = setup_for_extracting_channel_action do |ch|
30
+ ch.expects(:request_pty).never
31
+ ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
25
32
  end
26
33
  Capistrano::Command.new("ls", [session], :env => { "FOO" => "bar" })
27
34
  end
28
35
 
29
36
  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"))
37
+ session = setup_for_extracting_channel_action do |ch|
38
+ ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
32
39
  end
33
40
  Capistrano::Command.new("ls", [session], :env => { :FOO => "bar" })
34
41
  end
35
42
 
36
43
  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"))
44
+ session = setup_for_extracting_channel_action do |ch|
45
+ ch.expects(:exec).with(%(env HOWDY=there sh -c 'ls'))
39
46
  end
40
47
  Capistrano::Command.new("ls", [session], :env => "HOWDY=there")
41
48
  end
42
49
 
43
50
  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"))
51
+ session = setup_for_extracting_channel_action do |ch|
52
+ ch.expects(:exec).with(%(env FOO=bar sh -c 'ls'))
46
53
  end
47
54
  Capistrano::Command.new("ls", [session], :env => { "FOO" => :bar })
48
55
  end
49
56
 
50
57
  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"))
58
+ session = setup_for_extracting_channel_action do |ch|
59
+ ch.expects(:exec).with(%(env FOO=(\\ \\\"bar\\\"\\ ) sh -c 'ls'))
53
60
  end
54
61
  Capistrano::Command.new("ls", [session], :env => { "FOO" => '( "bar" )' })
55
62
  end
56
63
 
57
64
  def test_env_with_multiple_keys_should_chain_the_entries_together
58
- session = setup_for_extracting_channel_action(:on_success) do |ch|
65
+ session = setup_for_extracting_channel_action do |ch|
59
66
  ch.expects(:exec).with do |command|
60
67
  command =~ /^env / &&
61
68
  command =~ /\ba=b\b/ &&
62
69
  command =~ /\bc=d\b/ &&
63
70
  command =~ /\be=f\b/ &&
64
- command =~ / sh -c "ls"$/
71
+ command =~ / sh -c 'ls'$/
65
72
  end
66
73
  end
67
74
  Capistrano::Command.new("ls", [session], :env => { :a => :b, :c => :d, :e => :f })
68
75
  end
69
76
 
70
77
  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
-
78
+ channel = nil
79
+ session = setup_for_extracting_channel_action { |ch| channel = ch }
77
80
  Capistrano::Command.new("ls", [session])
81
+ assert_equal "capistrano", channel[:host]
78
82
  end
79
83
 
80
84
  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"})
86
-
85
+ channel = nil
86
+ session = setup_for_extracting_channel_action { |ch| channel = ch }
87
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])
88
+ assert_equal({ :data => 'here we go' }, channel[:options])
98
89
  end
99
90
 
100
91
  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"))
92
+ session = setup_for_extracting_channel_action do |ch|
93
+ ch.expects(:exec).with(%(sh -c 'ls'))
103
94
  end
104
95
  Capistrano::Command.new("ls", [session])
105
96
  end
106
97
 
107
98
  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"))
99
+ session = setup_for_extracting_channel_action do |ch|
100
+ ch.expects(:exec).with(%(/bin/bash -c 'ls'))
110
101
  end
111
102
  Capistrano::Command.new("ls", [session], :shell => "/bin/bash")
112
103
  end
113
104
 
105
+ def test_successful_channel_with_shell_false_should_send_command_without_shell
106
+ session = setup_for_extracting_channel_action do |ch|
107
+ ch.expects(:exec).with(%(echo `hostname`))
108
+ end
109
+ Capistrano::Command.new("echo `hostname`", [session], :shell => false)
110
+ end
111
+
114
112
  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"))
113
+ session = setup_for_extracting_channel_action do |ch|
114
+ ch.expects(:exec).with(%(sh -c 'ls'))
117
115
  ch.expects(:send_data).with("here we go")
118
116
  end
119
117
  Capistrano::Command.new("ls", [session], :data => "here we go")
120
118
  end
121
119
 
122
- def test_unsuccessful_channel_should_close_channel
123
- session = setup_for_extracting_channel_action(:on_failure) do |ch|
120
+ def test_unsuccessful_pty_request_should_close_channel
121
+ session = setup_for_extracting_channel_action(:request_pty, false) do |ch|
124
122
  ch.expects(:close)
125
123
  end
126
- Capistrano::Command.new("ls", [session])
124
+ Capistrano::Command.new("ls", [session], :pty => true)
127
125
  end
128
126
 
129
127
  def test_on_data_should_invoke_callback_as_stdout
@@ -150,48 +148,58 @@ class CommandTest < Test::Unit::TestCase
150
148
 
151
149
  def test_on_request_should_record_exit_status
152
150
  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
151
+ channel = nil
152
+ session = setup_for_extracting_channel_action([:on_request, "exit-status"], data) { |ch| channel = ch }
156
153
  Capistrano::Command.new("ls", [session])
154
+ assert_equal 5, channel[:status]
155
+ end
156
+
157
+ def test_on_request_should_log_exit_signal_if_logger_present
158
+ data = mock(:read_string => "TERM")
159
+ logger = stub_everything
160
+
161
+ session = setup_for_extracting_channel_action([:on_request, "exit-signal"], data)
162
+ logger.expects(:important).with("command received signal TERM", server("capistrano"))
163
+
164
+ Capistrano::Command.new("puppet", [session], :logger => logger)
157
165
  end
158
166
 
159
167
  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
168
+ channel = nil
169
+ session = setup_for_extracting_channel_action(:on_close) { |ch| channel = ch }
163
170
  Capistrano::Command.new("ls", [session])
171
+ assert channel[:closed]
164
172
  end
165
173
 
166
174
  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))]
175
+ sessions = [mock_session(new_channel(false)),
176
+ mock_session(new_channel(true)),
177
+ mock_session(new_channel(false))]
170
178
 
171
179
  cmd = Capistrano::Command.new("ls", sessions)
172
180
  cmd.stop!
173
181
  end
174
182
 
175
183
  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))]
184
+ sessions = [mock_session(new_channel(true, 0)),
185
+ mock_session(new_channel(true, 0)),
186
+ mock_session(new_channel(true, 0))]
179
187
  cmd = Capistrano::Command.new("ls", sessions)
180
188
  assert_nothing_raised { cmd.process! }
181
189
  end
182
190
 
183
191
  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))]
192
+ sessions = [mock_session(new_channel(true, 0)),
193
+ mock_session(new_channel(true, 0)),
194
+ mock_session(new_channel(true, 1))]
187
195
  cmd = Capistrano::Command.new("ls", sessions)
188
196
  assert_raises(Capistrano::CommandError) { cmd.process! }
189
197
  end
190
198
 
191
199
  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))]
200
+ sessions = [mock_session(new_channel(true, 0)),
201
+ mock_session(new_channel(true, 0)),
202
+ mock_session(new_channel(true, 1))]
195
203
  cmd = Capistrano::Command.new("ls", sessions)
196
204
 
197
205
  begin
@@ -207,95 +215,107 @@ class CommandTest < Test::Unit::TestCase
207
215
  new_channel = Proc.new do |times|
208
216
  ch = mock("channel")
209
217
  returns = [false] * (times-1)
218
+ ch.stubs(:to_ary)
210
219
  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
220
  ch.expects(:[]).with(:status).returns(0)
215
221
  ch
216
222
  end
217
223
 
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])]
224
+ sessions = [mock_session(new_channel[5]),
225
+ mock_session(new_channel[10]),
226
+ mock_session(new_channel[7])]
221
227
  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
228
+ assert_nothing_raised do
229
+ cmd.process!
243
230
  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
231
  end
251
232
 
252
233
  def test_process_should_instantiate_command_and_process!
253
234
  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
235
+ Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).returns(cmd)
236
+ Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar")
258
237
  end
259
238
 
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"))
239
+ def test_process_with_host_placeholder_should_substitute_host_placeholder_with_each_host
240
+ session = setup_for_extracting_channel_action do |ch|
241
+ ch.expects(:exec).with(%(sh -c 'echo capistrano'))
263
242
  end
264
243
  Capistrano::Command.new("echo $CAPISTRANO:HOST$", [session])
265
244
  end
266
245
 
246
+ class MockConfig
247
+ include Capistrano::Configuration::Roles
248
+ end
249
+
250
+ def test_hostroles_substitution
251
+ @config = MockConfig.new
252
+ @config.server "capistrano", :db, :worker
253
+ server = @config.roles[:db].servers.first
254
+ channel = {:server => server, :host => 'capistrano'}
255
+ tree = Capistrano::Command::Tree.new(@config) { |t| t.else("echo $CAPISTRANO:HOSTROLES$") }
256
+ result = Capistrano::Command.new(tree, []).send(:replace_placeholders, "echo $CAPISTRANO:HOSTROLES$", channel)
257
+ assert result == "echo db,worker" || result == "echo worker,db"
258
+ end
259
+
267
260
  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\\$"))
261
+ session = setup_for_extracting_channel_action do |ch|
262
+ ch.expects(:exec).with(%(sh -c 'echo $CAPISTRANO:OTHER$'))
270
263
  end
271
264
  Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
272
265
  end
273
266
 
267
+ def test_input_stream_closed_when_eof_option_is_true
268
+ channel = nil
269
+ session = setup_for_extracting_channel_action { |ch| channel = ch }
270
+ channel.expects(:eof!)
271
+ Capistrano::Command.new("cat", [session], :data => "here we go", :eof => true)
272
+ assert_equal({ :data => 'here we go', :eof => true }, channel[:options])
273
+ end
274
+
274
275
  private
275
276
 
277
+ def mock_session(channel=nil)
278
+ stub('session',
279
+ :open_channel => channel,
280
+ :preprocess => true,
281
+ :postprocess => true,
282
+ :listeners => {},
283
+ :xserver => server("capistrano"))
284
+ end
285
+
286
+ class MockChannel < Hash
287
+ def close
288
+ end
289
+ end
290
+
276
291
  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
292
+ ch = MockChannel.new
293
+ ch.update({ :closed => closed, :host => "capistrano", :server => server("capistrano") })
294
+ ch[:status] = status if status
280
295
  ch.expects(:close) unless closed
281
- ch.stubs(:[]).with(:host).returns("capistrano")
282
- ch.stubs(:[]).with(:server).returns(server("capistrano"))
283
296
  ch
284
297
  end
285
298
 
286
- def setup_for_extracting_channel_action(action, *args)
299
+ def setup_for_extracting_channel_action(action=nil, *args)
287
300
  s = server("capistrano")
288
301
  session = mock("session", :xserver => s)
289
302
 
290
- channel = stub_everything
303
+ channel = {}
291
304
  session.expects(:open_channel).yields(channel)
292
305
 
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)
306
+ channel.stubs(:on_data)
307
+ channel.stubs(:on_extended_data)
308
+ channel.stubs(:on_request)
309
+ channel.stubs(:on_close)
310
+ channel.stubs(:exec)
311
+ channel.stubs(:send_data)
312
+
313
+ if action
314
+ action = Array(action)
315
+ channel.expects(action.first).with(*action[1..-1]).yields(channel, *args)
316
+ end
297
317
 
298
- yield ch if block_given?
318
+ yield channel if block_given?
299
319
 
300
320
  session
301
321
  end
@@ -1,9 +1,10 @@
1
- require "#{File.dirname(__FILE__)}/../../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/actions/file_transfer'
3
3
 
4
4
  class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
5
5
  class MockConfig
6
6
  include Capistrano::Configuration::Actions::FileTransfer
7
+ attr_accessor :sessions, :dry_run
7
8
  end
8
9
 
9
10
  def setup
@@ -11,30 +12,50 @@ class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
11
12
  @config.stubs(:logger).returns(stub_everything)
12
13
  end
13
14
 
14
- def test_put_should_pass_options_to_execute_on_servers
15
- @config.expects(:execute_on_servers).with(:foo => "bar")
16
- @config.put("some data", "test.txt", :foo => "bar")
15
+ def test_put_should_delegate_to_upload
16
+ @config.expects(:upload).with { |from, to, opts|
17
+ from.string == "some data" && to == "test.txt" && opts == { :mode => 0777 } }
18
+ @config.expects(:run).never
19
+ @config.put("some data", "test.txt", :mode => 0777)
17
20
  end
18
21
 
19
- def test_put_should_delegate_to_Upload_process
20
- @config.expects(:execute_on_servers).yields(%w(s1 s2 s3).map { |s| mock(:host => s) })
21
- @config.expects(:sessions).times(3).returns(Hash.new{|h,k| h[k] = k.host.to_sym})
22
- Capistrano::Upload.expects(:process).with([:s1,:s2,:s3], "test.txt", :data => "some data", :mode => 0777, :logger => @config.logger)
23
- @config.put("some data", "test.txt", :mode => 0777)
22
+ def test_get_should_delegate_to_download_with_once
23
+ @config.expects(:download).with("testr.txt", "testl.txt", :foo => "bar", :once => true)
24
+ @config.get("testr.txt", "testl.txt", :foo => "bar")
24
25
  end
25
26
 
26
- def test_get_should_pass_options_execute_on_servers_including_once
27
- @config.expects(:execute_on_servers).with(:foo => "bar", :once => true)
28
- @config.get("test.txt", "test.txt", :foo => "bar")
27
+ def test_upload_should_delegate_to_transfer
28
+ @config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
29
+ @config.upload("testl.txt", "testr.txt", :foo => "bar")
29
30
  end
30
31
 
31
- def test_get_should_use_sftp_get_file_to_local_path
32
- sftp = mock("sftp", :state => :closed, :connect => true)
33
- sftp.expects(:get_file).with("remote.txt", "local.txt")
32
+ def test_upload_without_mode_should_not_try_to_chmod
33
+ @config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
34
+ @config.expects(:run).never
35
+ @config.upload("testl.txt", "testr.txt", :foo => "bar")
36
+ end
37
+
38
+ def test_upload_with_mode_should_try_to_chmod
39
+ @config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
40
+ @config.expects(:run).with("chmod 775 testr.txt", {:foo => "bar"})
41
+ @config.upload("testl.txt", "testr.txt", :mode => 0775, :foo => "bar")
42
+ end
43
+
44
+ def test_upload_with_symbolic_mode_should_try_to_chmod
45
+ @config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
46
+ @config.expects(:run).with("chmod g+w testr.txt", {:foo => "bar"})
47
+ @config.upload("testl.txt", "testr.txt", :mode => "g+w", :foo => "bar")
48
+ end
49
+
50
+ def test_download_should_delegate_to_transfer
51
+ @config.expects(:transfer).with(:down, "testr.txt", "testl.txt", :foo => "bar")
52
+ @config.download("testr.txt", "testl.txt", :foo => "bar")
53
+ end
34
54
 
35
- s = server("capistrano")
36
- @config.expects(:execute_on_servers).yields([s])
37
- @config.expects(:sessions).returns(s => mock("session", :sftp => sftp))
38
- @config.get("remote.txt", "local.txt")
55
+ def test_transfer_should_invoke_transfer_on_matching_servers
56
+ @config.sessions = { :a => 1, :b => 2, :c => 3, :d => 4 }
57
+ @config.expects(:execute_on_servers).with(:foo => "bar").yields([:a, :b, :c])
58
+ Capistrano::Transfer.expects(:process).with(:up, "testl.txt", "testr.txt", [1,2,3], {:foo => "bar", :logger => @config.logger})
59
+ @config.transfer(:up, "testl.txt", "testr.txt", :foo => "bar")
39
60
  end
40
- end
61
+ end
@@ -1,4 +1,4 @@
1
- require "#{File.dirname(__FILE__)}/../../utils"
1
+ require "utils"
2
2
  require 'capistrano/configuration/actions/inspect'
3
3
 
4
4
  class ConfigurationActionsInspectTest < Test::Unit::TestCase
@@ -9,13 +9,19 @@ class ConfigurationActionsInspectTest < Test::Unit::TestCase
9
9
  def setup
10
10
  @config = MockConfig.new
11
11
  @config.stubs(:logger).returns(stub_everything)
12
+ @config.stubs(:sudo).returns('sudo')
12
13
  end
13
14
 
14
15
  def test_stream_should_pass_options_through_to_run
15
- @config.expects(:invoke_command).with("tail -f foo.log", :once => true)
16
+ @config.expects(:invoke_command).with("tail -f foo.log", :once => true, :eof => true)
16
17
  @config.stream("tail -f foo.log", :once => true)
17
18
  end
18
19
 
20
+ def test_stream_with_sudo_should_avoid_closing_stdin
21
+ @config.expects(:invoke_command).with("sudo tail -f foo.log", :once => true, :eof => false)
22
+ @config.stream("sudo tail -f foo.log", :once => true)
23
+ end
24
+
19
25
  def test_stream_should_emit_stdout_via_puts
20
26
  @config.expects(:invoke_command).yields(mock("channel"), :out, "something streamed")
21
27
  @config.expects(:puts).with("something streamed")
@@ -33,13 +39,21 @@ class ConfigurationActionsInspectTest < Test::Unit::TestCase
33
39
  end
34
40
 
35
41
  def test_capture_should_pass_options_merged_with_once_to_run
36
- @config.expects(:invoke_command).with("hostname", :foo => "bar", :once => true)
42
+ @config.expects(:invoke_command).with("hostname", :foo => "bar", :once => true, :eof => true)
37
43
  @config.capture("hostname", :foo => "bar")
38
44
  end
39
45
 
40
- def test_capture_with_stderr_result_should_raise_capture_error
41
- @config.expects(:invoke_command).yields(mock("channel"), :err, "boom")
42
- assert_raises(Capistrano::CaptureError) { @config.capture("hostname") }
46
+ def test_capture_with_sudo_should_avoid_closing_stdin
47
+ @config.expects(:invoke_command).with("sudo hostname", :foo => "bar", :once => true, :eof => false)
48
+ @config.capture("sudo hostname", :foo => "bar")
49
+ end
50
+
51
+ def test_capture_with_stderr_should_emit_stderr_via_warn
52
+ ch = mock("channel")
53
+ ch.expects(:[]).with(:server).returns(server("capistrano"))
54
+ @config.expects(:invoke_command).yields(ch, :err, "boom")
55
+ @config.expects(:warn).with("[err :: capistrano] boom")
56
+ @config.capture("hostname")
43
57
  end
44
58
 
45
59
  def test_capture_with_stdout_should_aggregate_and_return_stdout
@@ -59,4 +73,4 @@ class ConfigurationActionsInspectTest < Test::Unit::TestCase
59
73
  @config.channel = channel
60
74
  @config.script = output
61
75
  end
62
- end
76
+ end