Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

root/tags/capistrano_1-99-1/test/command_test.rb

Revision 6706, 9.6 kB (checked in by minam, 2 years ago)

Make the server definition itself available to SSH channels, rather that just the host name. Identify servers by their complete credentials in logs, rather than simply by hostname.

Line 
1 require "#{File.dirname(__FILE__)}/utils"
2 require 'capistrano/command'
3
4 class CommandTest < Test::Unit::TestCase
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     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => { "FOO" => "bar" })
24     assert_equal "FOO=bar ls", cmd.command
25   end
26
27   def test_env_with_symbolic_key_should_be_accepted_as_a_string
28     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => { :FOO => "bar" })
29     assert_equal "FOO=bar ls", cmd.command
30   end
31
32   def test_env_as_string_should_be_substituted_in_directly
33     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => "HOWDY" )
34     assert_equal "HOWDY ls", cmd.command
35   end
36
37   def test_env_with_symbolic_value_should_be_accepted_as_string
38     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => { "FOO" => :bar })
39     assert_equal "FOO=bar ls", cmd.command
40   end
41
42   def test_env_value_should_be_escaped
43     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => { "FOO" => '( "bar" )' })
44     assert_equal "FOO=(\\ \\\"bar\\\"\\ ) ls", cmd.command
45   end
46
47   def test_env_with_multiple_keys_should_chain_the_entries_together
48     cmd = Capistrano::Command.new("ls", [mock(:open_channel => nil)], :env => { :a => :b, :c => :d, :e => :f })
49     env = cmd.command[/^(.*) ls$/, 1]
50     assert_match(/\ba=b\b/, env)
51     assert_match(/\bc=d\b/, env)
52     assert_match(/\be=f\b/, env)
53   end
54
55   def test_open_channel_should_set_host_key_on_channel
56     session = mock(:xserver => server("capistrano"))
57     channel = stub_everything
58
59     session.expects(:open_channel).yields(channel)
60     channel.expects(:[]=).with(:host, "capistrano")
61
62     Capistrano::Command.new("ls", [session])
63   end
64
65   def test_open_channel_should_set_options_key_on_channel
66     session = mock(:xserver => server("capistrano"))
67     channel = stub_everything
68
69     session.expects(:open_channel).yields(channel)
70     channel.expects(:[]=).with(:options, {:data => "here we go"})
71
72     Capistrano::Command.new("ls", [session], :data => "here we go")
73   end
74
75   def test_open_channel_should_request_pty
76     session = mock(:xserver => server("capistrano"))
77     channel = stub_everything
78
79     session.expects(:open_channel).yields(channel)
80     channel.expects(:request_pty).with(:want_reply => true)
81
82     Capistrano::Command.new("ls", [session])
83   end
84
85   def test_successful_channel_should_send_command
86     session = setup_for_extracting_channel_action(:on_success) do |ch|
87       ch.expects(:exec).with("ls")
88     end
89     Capistrano::Command.new("ls", [session])
90   end
91
92   def test_successful_channel_should_send_data_if_data_key_is_present
93     session = setup_for_extracting_channel_action(:on_success) do |ch|
94       ch.expects(:exec).with("ls")
95       ch.expects(:send_data).with("here we go")
96     end
97     Capistrano::Command.new("ls", [session], :data => "here we go")
98   end
99
100   def test_unsuccessful_channel_should_close_channel
101     session = setup_for_extracting_channel_action(:on_failure) do |ch|
102       ch.expects(:close)
103     end
104     Capistrano::Command.new("ls", [session])
105   end
106
107   def test_on_data_should_invoke_callback_as_stdout
108     session = setup_for_extracting_channel_action(:on_data, "hello")
109     called = false
110     Capistrano::Command.new("ls", [session]) do |ch, stream, data|
111       called = true
112       assert_equal :out, stream
113       assert_equal "hello", data
114     end
115     assert called
116   end
117
118   def test_on_extended_data_should_invoke_callback_as_stderr
119     session = setup_for_extracting_channel_action(:on_extended_data, 2, "hello")
120     called = false
121     Capistrano::Command.new("ls", [session]) do |ch, stream, data|
122       called = true
123       assert_equal :err, stream
124       assert_equal "hello", data
125     end
126     assert called
127   end
128
129   def test_on_request_should_record_exit_status
130     data = mock(:read_long => 5)
131     session = setup_for_extracting_channel_action(:on_request, "exit-status", nil, data) do |ch|
132       ch.expects(:[]=).with(:status, 5)
133     end
134     Capistrano::Command.new("ls", [session])
135   end
136
137   def test_on_close_should_set_channel_closed
138     session = setup_for_extracting_channel_action(:on_close) do |ch|
139       ch.expects(:[]=).with(:closed, true)
140     end
141     Capistrano::Command.new("ls", [session])
142   end
143
144   def test_stop_should_close_all_open_channels
145     sessions = [mock("session", :open_channel => new_channel(false)),
146                 mock("session", :open_channel => new_channel(true)),
147                 mock("session", :open_channel => new_channel(false))]
148
149     cmd = Capistrano::Command.new("ls", sessions)
150     cmd.stop!
151   end
152
153   def test_process_should_return_cleanly_if_all_channels_have_zero_exit_status
154     sessions = [mock("session", :open_channel => new_channel(true, 0)),
155                 mock("session", :open_channel => new_channel(true, 0)),
156                 mock("session", :open_channel => new_channel(true, 0))]
157     cmd = Capistrano::Command.new("ls", sessions)
158     assert_nothing_raised { cmd.process! }
159   end
160
161   def test_process_should_raise_error_if_any_channel_has_non_zero_exit_status
162     sessions = [mock("session", :open_channel => new_channel(true, 0)),
163                 mock("session", :open_channel => new_channel(true, 0)),
164                 mock("session", :open_channel => new_channel(true, 1))]
165     cmd = Capistrano::Command.new("ls", sessions)
166     assert_raises(Capistrano::CommandError) { cmd.process! }
167   end
168
169   def test_command_error_should_include_accessor_with_host_array
170     sessions = [mock("session", :open_channel => new_channel(true, 0)),
171                 mock("session", :open_channel => new_channel(true, 0)),
172                 mock("session", :open_channel => new_channel(true, 1))]
173     cmd = Capistrano::Command.new("ls", sessions)
174
175     begin
176       cmd.process!
177       flunk "expected an exception to be raised"
178     rescue Capistrano::CommandError => e
179       assert e.respond_to?(:hosts)
180       assert_equal %w(capistrano), e.hosts.map { |h| h.to_s }
181     end
182   end
183
184   def test_process_should_loop_until_all_channels_are_closed
185     new_channel = Proc.new do |times|
186       ch = mock("channel")
187       returns = [false] * (times-1)
188       ch.stubs(:[]).with(:closed).returns(lambda { returns.empty? ? true : returns.pop })
189       con = mock("connection")
190       con.expects(:process).with(true).times(times-1)
191       ch.expects(:connection).times(times-1).returns(con)
192       ch.expects(:[]).with(:status).returns(0)
193       ch
194     end
195
196     sessions = [mock("session", :open_channel => new_channel[5]),
197                 mock("session", :open_channel => new_channel[10]),
198                 mock("session", :open_channel => new_channel[7])]
199     cmd = Capistrano::Command.new("ls", sessions)
200     assert_nothing_raised { cmd.process! }
201   end
202
203   def test_process_should_ping_all_connections_each_second
204     now = Time.now
205
206     new_channel = Proc.new do
207       ch = mock("channel")
208       ch.stubs(:[]).with(:closed).returns(lambda { Time.now - now < 1.1 ? false : true })
209       ch.stubs(:[]).with(:status).returns(0)
210       con = mock("connection")
211       con.stubs(:process)
212       con.expects(:ping!)
213       ch.stubs(:connection).returns(con)
214       ch
215     end
216
217     sessions = [mock("session", :open_channel => new_channel[]),
218                 mock("session", :open_channel => new_channel[]),
219                 mock("session", :open_channel => new_channel[])]
220     cmd = Capistrano::Command.new("ls", sessions)
221     assert_nothing_raised { cmd.process! }
222   end
223
224   def test_process_should_instantiate_command_and_process!
225     cmd = mock("command", :process! => nil)
226     Capistrano::Command.expects(:new).with("ls -l", %w(a b c), {:foo => "bar"}).yields(:command).returns(cmd)
227     parameter = nil
228     Capistrano::Command.process("ls -l", %w(a b c), :foo => "bar") { |cmd| parameter = cmd }
229     assert_equal :command, parameter
230   end
231
232   def test_process_with_host_placeholder_should_substitute_placeholder_with_each_host
233     session = setup_for_extracting_channel_action(:on_success) do |ch|
234       ch.expects(:exec).with("echo capistrano")
235     end
236     Capistrano::Command.new("echo $CAPISTRANO:HOST$", [session])
237   end
238
239   def test_process_with_unknown_placeholder_should_not_replace_placeholder
240     session = setup_for_extracting_channel_action(:on_success) do |ch|
241       ch.expects(:exec).with("echo $CAPISTRANO:OTHER$")
242     end
243     Capistrano::Command.new("echo $CAPISTRANO:OTHER$", [session])
244   end
245
246   private
247
248     def new_channel(closed, status=nil)
249       ch = mock("channel")
250       ch.expects(:[]).with(:closed).returns(closed)
251       ch.expects(:[]).with(:status).returns(status) if status
252       ch.expects(:close) unless closed
253       ch.stubs(:[]).with(:host).returns("capistrano")
254       ch.stubs(:[]).with(:server).returns(server("capistrano"))
255       ch
256     end
257
258     def setup_for_extracting_channel_action(action, *args)
259       s = server("capistrano")
260       session = mock("session", :xserver => s)
261
262       channel = stub_everything
263       session.expects(:open_channel).yields(channel)
264
265       ch = mock
266       ch.stubs(:[]).with(:server).returns(s)
267       ch.stubs(:[]).with(:host).returns(s.host)
268       channel.expects(action).yields(ch, *args)
269
270       yield ch if block_given?
271
272       session
273     end
274 end
Note: See TracBrowser for help on using the browser.