public
Description: Remote multi-server automation tool. This repository is no longer being actively maintained. Please ask on the mailing list to find someone who has a well-maintained fork. Thanks!
Homepage: http://www.capify.org
Clone URL: git://github.com/jamis/capistrano.git
capistrano / test / configuration / actions / invocation_test.rb
100644 203 lines (165 sloc) 7.388 kb
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
require "utils"
require 'capistrano/configuration/actions/invocation'
 
class ConfigurationActionsInvocationTest < Test::Unit::TestCase
  class MockConfig
    attr_reader :options
    attr_accessor :debug
 
    def initialize
      @options = {}
    end
 
    def [](*args)
      @options[*args]
    end
 
    def set(name, value)
      @options[name] = value
    end
 
    def fetch(*args)
      @options.fetch(*args)
    end
 
    include Capistrano::Configuration::Actions::Invocation
  end
 
  def setup
    @config = MockConfig.new
    @original_io_proc = MockConfig.default_io_proc
    @config.stubs(:logger).returns(stub_everything)
  end
 
  def teardown
    MockConfig.default_io_proc = @original_io_proc
  end
 
  def test_run_options_should_be_passed_to_execute_on_servers
    @config.expects(:execute_on_servers).with(:foo => "bar")
    @config.run "ls", :foo => "bar"
  end
 
  def test_run_without_block_should_use_default_io_proc
    @config.expects(:execute_on_servers).yields(%w(s1 s2 s3).map { |s| server(s) })
    @config.expects(:sessions).returns(Hash.new { |h,k| h[k] = k.host.to_sym }).times(3)
    prepare_command("ls", [:s1, :s2, :s3], {:logger => @config.logger})
    MockConfig.default_io_proc = inspectable_proc
    @config.run "ls"
  end
 
  def test_run_with_block_should_use_block
    @config.expects(:execute_on_servers).yields(%w(s1 s2 s3).map { |s| mock(:host => s) })
    @config.expects(:sessions).returns(Hash.new { |h,k| h[k] = k.host.to_sym }).times(3)
    prepare_command("ls", [:s1, :s2, :s3], {:logger => @config.logger})
    MockConfig.default_io_proc = Proc.new { |a,b,c| raise "shouldn't get here" }
    @config.run("ls", &inspectable_proc)
  end
 
  def test_add_default_command_options_should_return_bare_options_if_there_is_no_env_or_shell_specified
    assert_equal({:foo => "bar"}, @config.add_default_command_options(:foo => "bar"))
  end
 
  def test_add_default_command_options_should_merge_default_environment_as_env
    @config[:default_environment][:bang] = "baz"
    assert_equal({:foo => "bar", :env => { :bang => "baz" }}, @config.add_default_command_options(:foo => "bar"))
  end
 
  def test_add_default_command_options_should_merge_env_with_default_environment
    @config[:default_environment][:bang] = "baz"
    @config[:default_environment][:bacon] = "crunchy"
    assert_equal({:foo => "bar", :env => { :bang => "baz", :bacon => "chunky", :flip => "flop" }}, @config.add_default_command_options(:foo => "bar", :env => {:bacon => "chunky", :flip => "flop"}))
  end
 
  def test_add_default_command_options_should_use_default_shell_if_present
    @config.set :default_shell, "/bin/bash"
    assert_equal({:foo => "bar", :shell => "/bin/bash"}, @config.add_default_command_options(:foo => "bar"))
  end
 
  def test_add_default_command_options_should_use_shell_in_preference_of_default_shell
    @config.set :default_shell, "/bin/bash"
    assert_equal({:foo => "bar", :shell => "/bin/sh"}, @config.add_default_command_options(:foo => "bar", :shell => "/bin/sh"))
  end
 
  def test_default_io_proc_should_log_stdout_arguments_as_info
    ch = { :host => "capistrano",
           :server => server("capistrano"),
           :options => { :logger => mock("logger") } }
    ch[:options][:logger].expects(:info).with("data stuff", "out :: capistrano")
    MockConfig.default_io_proc[ch, :out, "data stuff"]
  end
 
  def test_default_io_proc_should_log_stderr_arguments_as_important
    ch = { :host => "capistrano",
           :server => server("capistrano"),
           :options => { :logger => mock("logger") } }
    ch[:options][:logger].expects(:important).with("data stuff", "err :: capistrano")
    MockConfig.default_io_proc[ch, :err, "data stuff"]
  end
 
  def test_sudo_should_default_to_sudo
    @config.expects(:run).with("ls", :command_prefix => "sudo -p 'sudo password: '")
    @config.sudo "ls"
  end
 
  def test_sudo_should_use_sudo_variable_definition
    @config.expects(:run).with("ls", :command_prefix => "/opt/local/bin/sudo -p 'sudo password: '")
    @config.options[:sudo] = "/opt/local/bin/sudo"
    @config.sudo "ls"
  end
 
  def test_sudo_should_interpret_as_option_as_user
    @config.expects(:run).with("ls", :command_prefix => "sudo -p 'sudo password: ' -u app")
    @config.sudo "ls", :as => "app"
  end
 
  def test_sudo_should_pass_options_through_to_run
    @config.expects(:run).with("ls", :command_prefix => "sudo -p 'sudo password: '", :foo => "bar")
    @config.sudo "ls", :foo => "bar"
  end
 
  def test_sudo_should_interpret_sudo_prompt_variable_as_custom_prompt
    @config.set :sudo_prompt, "give it to me: "
    @config.expects(:run).with("ls", :command_prefix => "sudo -p 'give it to me: '")
    @config.sudo "ls"
  end
 
  def test_sudo_behavior_callback_should_send_password_when_prompted_with_default_sudo_prompt
    ch = mock("channel")
    ch.expects(:send_data).with("g00b3r\n")
    @config.options[:password] = "g00b3r"
    @config.sudo_behavior_callback(nil)[ch, nil, "sudo password: "]
  end
 
  def test_sudo_behavior_callback_should_send_password_when_prompted_with_custom_sudo_prompt
    ch = mock("channel")
    ch.expects(:send_data).with("g00b3r\n")
    @config.set :sudo_prompt, "give it to me: "
    @config.options[:password] = "g00b3r"
    @config.sudo_behavior_callback(nil)[ch, nil, "give it to me: "]
  end
 
  def test_sudo_behavior_callback_with_incorrect_password_on_first_prompt
    ch = mock("channel")
    ch.stubs(:[]).with(:host).returns("capistrano")
    ch.stubs(:[]).with(:server).returns(server("capistrano"))
    @config.expects(:reset!).with(:password)
    @config.sudo_behavior_callback(nil)[ch, nil, "blah blah try again blah blah"]
  end
 
  def test_sudo_behavior_callback_with_incorrect_password_on_subsequent_prompts
    callback = @config.sudo_behavior_callback(nil)
 
    ch = mock("channel")
    ch.stubs(:[]).with(:host).returns("capistrano")
    ch.stubs(:[]).with(:server).returns(server("capistrano"))
    ch2 = mock("channel")
    ch2.stubs(:[]).with(:host).returns("cap2")
    ch2.stubs(:[]).with(:server).returns(server("cap2"))
 
    @config.expects(:reset!).with(:password).times(2)
 
    callback[ch, nil, "blah blah try again blah blah"]
    callback[ch2, nil, "blah blah try again blah blah"] # shouldn't call reset!
    callback[ch, nil, "blah blah try again blah blah"]
  end
 
  def test_sudo_behavior_callback_should_defer_to_fallback_for_other_output
    callback = @config.sudo_behavior_callback(inspectable_proc)
 
    a = mock("channel", :called => true)
    b = mock("stream", :called => true)
    c = mock("data", :called => true)
 
    callback[a, b, c]
  end
 
  def test_invoke_command_should_default_to_run
    @config.expects(:run).with("ls", :once => true)
    @config.invoke_command("ls", :once => true)
  end
 
  def test_invoke_command_should_delegate_to_method_identified_by_via
    @config.expects(:foobar).with("ls", :once => true)
    @config.invoke_command("ls", :once => true, :via => :foobar)
  end
 
  private
 
    def inspectable_proc
      Proc.new do |ch, stream, data|
        ch.called
        stream.called
        data.called
      end
    end
 
    def prepare_command(command, sessions, options)
      a = mock("channel", :called => true)
      b = mock("stream", :called => true)
      c = mock("data", :called => true)
      Capistrano::Command.expects(:process).with(command, sessions, options).yields(a, b, c)
    end
end