-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
command_test.rb
309 lines (263 loc) · 10.8 KB
/
command_test.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
require "utils"
require 'capistrano/command'
class CommandTest < Test::Unit::TestCase
def test_command_should_open_channels_on_all_sessions
s1 = mock(:open_channel => nil)
s2 = mock(:open_channel => nil)
s3 = mock(:open_channel => nil)
assert_equal "ls", Capistrano::Command.new("ls", [s1, s2, s3]).command
end
def test_command_with_newlines_should_be_properly_escaped
cmd = Capistrano::Command.new("ls\necho", [mock(:open_channel => nil)])
assert_equal "ls\\\necho", cmd.command
end
def test_command_with_windows_newlines_should_be_properly_escaped
cmd = Capistrano::Command.new("ls\r\necho", [mock(:open_channel => nil)])
assert_equal "ls\\\necho", cmd.command
end
def test_command_with_pty_should_request_pty_and_register_success_callback
session = setup_for_extracting_channel_action(:on_success) do |ch|
ch.expects(:request_pty).with(:want_reply => true)
ch.expects(:exec).with(%(sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :pty => true)
end
def test_command_with_env_key_should_have_environment_constructed_and_prepended
session = setup_for_extracting_channel_action do |ch|
ch.expects(:request_pty).never
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :env => { "FOO" => "bar" })
end
def test_env_with_symbolic_key_should_be_accepted_as_a_string
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :env => { :FOO => "bar" })
end
def test_env_as_string_should_be_substituted_in_directly
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(env HOWDY=there sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :env => "HOWDY=there")
end
def test_env_with_symbolic_value_should_be_accepted_as_string
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(env FOO=bar sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :env => { "FOO" => :bar })
end
def test_env_value_should_be_escaped
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(env FOO=(\\ \\\"bar\\\"\\ ) sh -c "ls"))
end
Capistrano::Command.new("ls", [session], :env => { "FOO" => '( "bar" )' })
end
def test_env_with_multiple_keys_should_chain_the_entries_together
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with do |command|
command =~ /^env / &&
command =~ /\ba=b\b/ &&
command =~ /\bc=d\b/ &&
command =~ /\be=f\b/ &&
command =~ / sh -c "ls"$/
end
end
Capistrano::Command.new("ls", [session], :env => { :a => :b, :c => :d, :e => :f })
end
def test_open_channel_should_set_host_key_on_channel
session = mock(:xserver => server("capistrano"))
channel = stub_everything
session.expects(:open_channel).yields(channel)
channel.expects(:[]=).with(:host, "capistrano")
channel.stubs(:[]).with(:host).returns("capistrano")
Capistrano::Command.new("ls", [session])
end
def test_open_channel_should_set_options_key_on_channel
session = mock(:xserver => server("capistrano"))
channel = stub_everything
session.expects(:open_channel).yields(channel)
channel.expects(:[]=).with(:options, {:data => "here we go"})
channel.stubs(:[]).with(:host).returns("capistrano")
Capistrano::Command.new("ls", [session], :data => "here we go")
end
def test_successful_channel_should_send_command
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(sh -c "ls"))
end
Capistrano::Command.new("ls", [session])
end
def test_successful_channel_with_shell_option_should_send_command_via_specified_shell
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(/bin/bash -c "ls"))
end
Capistrano::Command.new("ls", [session], :shell => "/bin/bash")
end
def test_successful_channel_with_shell_false_should_send_command_without_shell
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(echo `hostname`))
end
Capistrano::Command.new("echo `hostname`", [session], :shell => false)
end
def test_successful_channel_should_send_data_if_data_key_is_present
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(sh -c "ls"))
ch.expects(:send_data).with("here we go")
end
Capistrano::Command.new("ls", [session], :data => "here we go")
end
def test_unsuccessful_pty_request_should_close_channel
session = setup_for_extracting_channel_action(:on_failure) do |ch|
ch.expects(:close)
end
Capistrano::Command.new("ls", [session], :pty => true)
end
def test_on_data_should_invoke_callback_as_stdout
session = setup_for_extracting_channel_action(:on_data, "hello")
called = false
Capistrano::Command.new("ls", [session]) do |ch, stream, data|
called = true
assert_equal :out, stream
assert_equal "hello", data
end
assert called
end
def test_on_extended_data_should_invoke_callback_as_stderr
session = setup_for_extracting_channel_action(:on_extended_data, 2, "hello")
called = false
Capistrano::Command.new("ls", [session]) do |ch, stream, data|
called = true
assert_equal :err, stream
assert_equal "hello", data
end
assert called
end
def test_on_request_should_record_exit_status
data = mock(:read_long => 5)
session = setup_for_extracting_channel_action(:on_request, "exit-status", nil, data) do |ch|
ch.expects(:[]=).with(:status, 5)
end
Capistrano::Command.new("ls", [session])
end
def test_on_close_should_set_channel_closed
session = setup_for_extracting_channel_action(:on_close) do |ch|
ch.expects(:[]=).with(:closed, true)
end
Capistrano::Command.new("ls", [session])
end
def test_stop_should_close_all_open_channels
sessions = [mock("session", :open_channel => new_channel(false)),
mock("session", :open_channel => new_channel(true)),
mock("session", :open_channel => new_channel(false))]
cmd = Capistrano::Command.new("ls", sessions)
cmd.stop!
end
def test_process_should_return_cleanly_if_all_channels_have_zero_exit_status
sessions = [mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 0))]
cmd = Capistrano::Command.new("ls", sessions)
assert_nothing_raised { cmd.process! }
end
def test_process_should_raise_error_if_any_channel_has_non_zero_exit_status
sessions = [mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 1))]
cmd = Capistrano::Command.new("ls", sessions)
assert_raises(Capistrano::CommandError) { cmd.process! }
end
def test_command_error_should_include_accessor_with_host_array
sessions = [mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 0)),
mock("session", :open_channel => new_channel(true, 1))]
cmd = Capistrano::Command.new("ls", sessions)
begin
cmd.process!
flunk "expected an exception to be raised"
rescue Capistrano::CommandError => e
assert e.respond_to?(:hosts)
assert_equal %w(capistrano), e.hosts.map { |h| h.to_s }
end
end
def test_process_should_loop_until_all_channels_are_closed
new_channel = Proc.new do |times|
ch = mock("channel")
returns = [false] * (times-1)
ch.stubs(:[]).with(:closed).returns(*(returns + [true]))
con = mock("connection")
con.expects(:process).with(true).times(times-1)
ch.expects(:connection).times(times-1).returns(con)
ch.expects(:[]).with(:status).returns(0)
ch
end
sessions = [mock("session", :open_channel => new_channel[5]),
mock("session", :open_channel => new_channel[10]),
mock("session", :open_channel => new_channel[7])]
cmd = Capistrano::Command.new("ls", sessions)
assert_nothing_raised { cmd.process! }
end
def test_process_should_ping_all_connections_each_second
now = Time.now
new_channel = Proc.new do
ch = mock("channel")
ch.stubs(:now => now)
def ch.[](key)
case key
when :status then 0
when :closed then Time.now - now < 1.1 ? false : true
else raise "unknown key: #{key}"
end
end
con = mock("connection")
con.stubs(:process)
con.expects(:ping!)
ch.stubs(:connection).returns(con)
ch
end
sessions = [mock("session", :open_channel => new_channel[]),
mock("session", :open_channel => new_channel[]),
mock("session", :open_channel => new_channel[])]
cmd = Capistrano::Command.new("ls", sessions)
assert_nothing_raised { cmd.process! }
end
def test_process_should_instantiate_command_and_process!
cmd = mock("command", :process! => nil)
Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).yields(:command).returns(cmd)
parameter = nil
Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar") { |cmd| parameter = cmd }
assert_equal :command, parameter
end
def test_process_with_host_placeholder_should_substitute_placeholder_with_each_host
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(sh -c "echo capistrano"))
end
Capistrano::Command.new("echo $CAPISTRANO:HOST$", [session])
end
def test_process_with_unknown_placeholder_should_not_replace_placeholder
session = setup_for_extracting_channel_action do |ch|
ch.expects(:exec).with(%(sh -c "echo \\$CAPISTRANO:OTHER\\$"))
end
Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
end
private
def new_channel(closed, status=nil)
ch = mock("channel")
ch.expects(:[]).with(:closed).returns(closed)
ch.expects(:[]).with(:status).returns(status) if status
ch.expects(:close) unless closed
ch.stubs(:[]).with(:host).returns("capistrano")
ch.stubs(:[]).with(:server).returns(server("capistrano"))
ch
end
def setup_for_extracting_channel_action(action=nil, *args)
s = server("capistrano")
session = mock("session", :xserver => s)
channel = stub_everything
session.expects(:open_channel).yields(channel)
channel.stubs(:[]).with(:server).returns(s)
channel.stubs(:[]).with(:host).returns(s.host)
channel.expects(action).yields(channel, *args) if action
yield channel if block_given?
session
end
end