mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
tests all pass
This commit is contained in:
parent
b4bd52826c
commit
8f0f99565e
11 changed files with 290 additions and 260 deletions
1
Rakefile
1
Rakefile
|
@ -19,6 +19,7 @@ desc "Build documentation"
|
|||
task :doc => [ :rdoc ]
|
||||
|
||||
Rake::TestTask.new do |t|
|
||||
t.libs << "test"
|
||||
t.test_files = Dir["test/**/*_test.rb"]
|
||||
t.verbose = true
|
||||
end
|
||||
|
|
|
@ -9,7 +9,9 @@ module Capistrano
|
|||
# by the current task. If <tt>:mode</tt> is specified it is used to
|
||||
# set the mode on the file.
|
||||
def put(data, path, options={})
|
||||
upload(StringIO.new(data), path, options)
|
||||
opts = options.dup
|
||||
opts[:permissions] = opts.delete(:mode)
|
||||
upload(StringIO.new(data), path, opts)
|
||||
end
|
||||
|
||||
# Get file remote_path from FIRST server targeted by
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
require 'enumerator'
|
||||
require 'net/ssh/gateway'
|
||||
require 'capistrano/ssh'
|
||||
require 'capistrano/errors'
|
||||
|
||||
module Capistrano
|
||||
class Configuration
|
||||
|
@ -24,8 +25,11 @@ module Capistrano
|
|||
def initialize(gateway, options)
|
||||
Thread.abort_on_exception = true
|
||||
server = ServerDefinition.new(gateway)
|
||||
@gateway = Net::SSH::Gateway.new(server.host, server.user || ServerDefinition.default_user, server.options)
|
||||
|
||||
@options = options
|
||||
@gateway = SSH.connection_strategy(server, options) do |host, user, connect_options|
|
||||
Net::SSH::Gateway.new(host, user, connect_options)
|
||||
end
|
||||
end
|
||||
|
||||
def connect_to(server)
|
||||
|
@ -177,8 +181,6 @@ module Capistrano
|
|||
def safely_establish_connection_to(server, failures=nil)
|
||||
sessions[server] ||= connection_factory.connect_to(server)
|
||||
rescue Exception => err
|
||||
puts err
|
||||
puts err.backtrace
|
||||
raise unless failures
|
||||
failures << { :server => server, :error => err }
|
||||
end
|
||||
|
|
|
@ -39,7 +39,22 @@ module Capistrano
|
|||
# constructor. Values in +options+ are then merged into it, and any
|
||||
# connection information in +server+ is added last, so that +server+ info
|
||||
# takes precedence over +options+, which takes precendence over ssh_options.
|
||||
def self.connect(server, options={}, &block)
|
||||
def self.connect(server, options={})
|
||||
connection_strategy(server, options) do |host, user, connection_options|
|
||||
connection = Net::SSH.start(host, user, connection_options)
|
||||
Server.apply_to(connection, server)
|
||||
end
|
||||
end
|
||||
|
||||
# Abstracts the logic for establishing an SSH connection (which includes
|
||||
# testing for connection failures and retrying with a password, and so forth,
|
||||
# mostly made complicated because of the fact that some of these variables
|
||||
# might be lazily evaluated and try to do something like prompt the user,
|
||||
# which should only happen when absolutely necessary.
|
||||
#
|
||||
# This will yield the hostname, username, and a hash of connection options
|
||||
# to the given block, which should return a new connection.
|
||||
def self.connection_strategy(server, options={}, &block)
|
||||
methods = [ %w(publickey hostbased), %w(password keyboard-interactive) ]
|
||||
password_value = nil
|
||||
|
||||
|
@ -47,15 +62,15 @@ module Capistrano
|
|||
user = server.user || options[:user] || ssh_options[:username] || ServerDefinition.default_user
|
||||
ssh_options[:port] = server.port || options[:port] || ssh_options[:port] || DEFAULT_PORT
|
||||
|
||||
ssh_options.delete(:username)
|
||||
|
||||
begin
|
||||
connection_options = ssh_options.merge(
|
||||
:password => password_value,
|
||||
:auth_methods => ssh_options[:auth_methods] || methods.shift
|
||||
)
|
||||
|
||||
connection = Net::SSH.start(server.host, user, connection_options, &block)
|
||||
Server.apply_to(connection, server)
|
||||
|
||||
yield server.host, user, connection_options
|
||||
rescue Net::SSH::AuthenticationFailed
|
||||
raise if methods.empty? || ssh_options[:auth_methods]
|
||||
password_value = options[:password]
|
||||
|
|
|
@ -31,9 +31,11 @@ module Capistrano
|
|||
@options = options
|
||||
@callback = callback
|
||||
|
||||
@transport = options.fetch(:transport, :sftp)
|
||||
@transport = options.fetch(:via, :sftp)
|
||||
@logger = options.delete(:logger)
|
||||
|
||||
|
||||
@session_map = {}
|
||||
|
||||
prepare_transfers
|
||||
end
|
||||
|
||||
|
@ -91,16 +93,18 @@ module Capistrano
|
|||
|
||||
private
|
||||
|
||||
def prepare_transfers
|
||||
@session_map = {}
|
||||
def session_map
|
||||
@session_map
|
||||
end
|
||||
|
||||
def prepare_transfers
|
||||
logger.info "#{transport} #{operation} #{from} -> #{to}" if logger
|
||||
|
||||
@transfers = sessions.map do |session|
|
||||
session_from = normalize(from, session)
|
||||
session_to = normalize(to, session)
|
||||
|
||||
@session_map[session] = case transport
|
||||
session_map[session] = case transport
|
||||
when :sftp
|
||||
prepare_sftp_transfer(session_from, session_to, session)
|
||||
when :scp
|
||||
|
@ -112,24 +116,21 @@ module Capistrano
|
|||
end
|
||||
|
||||
def prepare_scp_transfer(from, to, session)
|
||||
scp = Net::SCP.new(session)
|
||||
|
||||
real_callback = callback || Proc.new do |channel, name, sent, total|
|
||||
logger.trace "[#{channel[:host]}] #{name}" if logger && sent == 0
|
||||
end
|
||||
|
||||
channel = case direction
|
||||
when :up
|
||||
scp.upload(from, to, options, &real_callback)
|
||||
session.scp.upload(from, to, options, &real_callback)
|
||||
when :down
|
||||
scp.download(from, to, options, &real_callback)
|
||||
session.scp.download(from, to, options, &real_callback)
|
||||
else
|
||||
raise ArgumentError, "unsupported transfer direction: #{direction.inspect}"
|
||||
end
|
||||
|
||||
channel[:server] = session.xserver
|
||||
channel[:host] = session.xserver.host
|
||||
channel[:channel] = channel
|
||||
channel[:server] = session.xserver
|
||||
channel[:host] = session.xserver.host
|
||||
|
||||
return channel
|
||||
end
|
||||
|
@ -138,7 +139,7 @@ module Capistrano
|
|||
attr_reader :operation
|
||||
|
||||
def initialize(session, &callback)
|
||||
Net::SFTP::Session.new(session) do |sftp|
|
||||
session.sftp(false).connect do |sftp|
|
||||
@operation = callback.call(sftp)
|
||||
end
|
||||
end
|
||||
|
@ -170,15 +171,12 @@ module Capistrano
|
|||
elsif event == :finish
|
||||
logger.trace "[#{op[:host]}] done"
|
||||
end
|
||||
|
||||
op[:channel].close if event == :finish
|
||||
end
|
||||
|
||||
opts = options.dup
|
||||
opts[:properties] = (opts[:properties] || {}).merge(
|
||||
:server => session.xserver,
|
||||
:host => session.xserver.host,
|
||||
:channel => sftp.channel)
|
||||
:host => session.xserver.host)
|
||||
|
||||
case direction
|
||||
when :up
|
||||
|
@ -205,12 +203,14 @@ module Capistrano
|
|||
end
|
||||
|
||||
def handle_error(error)
|
||||
transfer = @session_map[error.session]
|
||||
transfer[:channel].close
|
||||
transfer = session_map[error.session]
|
||||
transfer[:error] = error
|
||||
transfer[:failed] = true
|
||||
|
||||
transfer.abort! if transport == :sftp
|
||||
case transport
|
||||
when :sftp then transfer.abort!
|
||||
when :scp then transfer.close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -20,8 +20,7 @@ class CommandTest < Test::Unit::TestCase
|
|||
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)
|
||||
session = setup_for_extracting_channel_action(:request_pty, true) do |ch|
|
||||
ch.expects(:exec).with(%(sh -c "ls"))
|
||||
end
|
||||
Capistrano::Command.new("ls", [session], :pty => true)
|
||||
|
@ -128,7 +127,7 @@ class CommandTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_unsuccessful_pty_request_should_close_channel
|
||||
session = setup_for_extracting_channel_action(:on_failure) do |ch|
|
||||
session = setup_for_extracting_channel_action(:request_pty, false) do |ch|
|
||||
ch.expects(:close)
|
||||
end
|
||||
Capistrano::Command.new("ls", [session], :pty => true)
|
||||
|
@ -158,7 +157,7 @@ class CommandTest < Test::Unit::TestCase
|
|||
|
||||
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|
|
||||
session = setup_for_extracting_channel_action([:on_request, "exit-status"], data) do |ch|
|
||||
ch.expects(:[]=).with(:status, 5)
|
||||
end
|
||||
Capistrano::Command.new("ls", [session])
|
||||
|
@ -172,34 +171,34 @@ class CommandTest < Test::Unit::TestCase
|
|||
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))]
|
||||
sessions = [mock_session(new_channel(false)),
|
||||
mock_session(new_channel(true)),
|
||||
mock_session(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))]
|
||||
sessions = [mock_session(new_channel(true, 0)),
|
||||
mock_session(new_channel(true, 0)),
|
||||
mock_session(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))]
|
||||
sessions = [mock_session(new_channel(true, 0)),
|
||||
mock_session(new_channel(true, 0)),
|
||||
mock_session(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))]
|
||||
sessions = [mock_session(new_channel(true, 0)),
|
||||
mock_session(new_channel(true, 0)),
|
||||
mock_session(new_channel(true, 1))]
|
||||
cmd = Capistrano::Command.new("ls", sessions)
|
||||
|
||||
begin
|
||||
|
@ -216,43 +215,13 @@ class CommandTest < Test::Unit::TestCase
|
|||
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[])]
|
||||
sessions = [mock_session(new_channel[5]),
|
||||
mock_session(new_channel[10]),
|
||||
mock_session(new_channel[7])]
|
||||
cmd = Capistrano::Command.new("ls", sessions)
|
||||
assert_nothing_raised { cmd.process! }
|
||||
end
|
||||
|
@ -281,6 +250,13 @@ class CommandTest < Test::Unit::TestCase
|
|||
|
||||
private
|
||||
|
||||
def mock_session(channel=nil)
|
||||
stub('session', :open_channel => channel,
|
||||
:preprocess => true,
|
||||
:postprocess => true,
|
||||
:listeners => {})
|
||||
end
|
||||
|
||||
def new_channel(closed, status=nil)
|
||||
ch = mock("channel")
|
||||
ch.expects(:[]).with(:closed).returns(closed)
|
||||
|
@ -300,7 +276,11 @@ class CommandTest < Test::Unit::TestCase
|
|||
|
||||
channel.stubs(:[]).with(:server).returns(s)
|
||||
channel.stubs(:[]).with(:host).returns(s.host)
|
||||
channel.expects(action).yields(channel, *args) if action
|
||||
|
||||
if action
|
||||
action = Array(action)
|
||||
channel.expects(action.first).with(*action[1..-1]).yields(channel, *args)
|
||||
end
|
||||
|
||||
yield channel if block_given?
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'capistrano/configuration/actions/file_transfer'
|
|||
class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
|
||||
class MockConfig
|
||||
include Capistrano::Configuration::Actions::FileTransfer
|
||||
attr_accessor :sessions
|
||||
end
|
||||
|
||||
def setup
|
||||
|
@ -11,30 +12,31 @@ class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
|
|||
@config.stubs(:logger).returns(stub_everything)
|
||||
end
|
||||
|
||||
def test_put_should_pass_options_to_execute_on_servers
|
||||
@config.expects(:execute_on_servers).with(:foo => "bar")
|
||||
@config.put("some data", "test.txt", :foo => "bar")
|
||||
end
|
||||
|
||||
def test_put_should_delegate_to_Upload_process
|
||||
@config.expects(:execute_on_servers).yields(%w(s1 s2 s3).map { |s| mock(:host => s) })
|
||||
@config.expects(:sessions).times(3).returns(Hash.new{|h,k| h[k] = k.host.to_sym})
|
||||
Capistrano::Upload.expects(:process).with([:s1,:s2,:s3], "test.txt", :data => "some data", :mode => 0777, :logger => @config.logger)
|
||||
def test_put_should_delegate_to_upload
|
||||
@config.expects(:upload).with { |from, to, opts|
|
||||
from.string == "some data" && to == "test.txt" && opts == { :permissions => 0777 } }
|
||||
@config.put("some data", "test.txt", :mode => 0777)
|
||||
end
|
||||
|
||||
def test_get_should_pass_options_execute_on_servers_including_once
|
||||
@config.expects(:execute_on_servers).with(:foo => "bar", :once => true)
|
||||
@config.get("test.txt", "test.txt", :foo => "bar")
|
||||
def test_get_should_delegate_to_download_with_once
|
||||
@config.expects(:download).with("testr.txt", "testl.txt", :foo => "bar", :once => true)
|
||||
@config.get("testr.txt", "testl.txt", :foo => "bar")
|
||||
end
|
||||
|
||||
def test_get_should_use_sftp_get_file_to_local_path
|
||||
sftp = mock("sftp", :state => :closed, :connect => true)
|
||||
sftp.expects(:get_file).with("remote.txt", "local.txt")
|
||||
def test_upload_should_delegate_to_transfer
|
||||
@config.expects(:transfer).with(:up, "testl.txt", "testr.txt", :foo => "bar")
|
||||
@config.upload("testl.txt", "testr.txt", :foo => "bar")
|
||||
end
|
||||
|
||||
s = server("capistrano")
|
||||
@config.expects(:execute_on_servers).yields([s])
|
||||
@config.expects(:sessions).returns(s => mock("session", :sftp => sftp))
|
||||
@config.get("remote.txt", "local.txt")
|
||||
def test_download_should_delegate_to_transfer
|
||||
@config.expects(:transfer).with(:down, "testr.txt", "testl.txt", :foo => "bar")
|
||||
@config.download("testr.txt", "testl.txt", :foo => "bar")
|
||||
end
|
||||
|
||||
def test_transfer_should_invoke_transfer_on_matching_servers
|
||||
@config.sessions = { :a => 1, :b => 2, :c => 3, :d => 4 }
|
||||
@config.expects(:execute_on_servers).with(:foo => "bar").yields([:a, :b, :c])
|
||||
Capistrano::Transfer.expects(:process).with(:up, "testl.txt", "testr.txt", [1,2,3], {:foo => "bar", :logger => @config.logger})
|
||||
@config.transfer(:up, "testl.txt", "testr.txt", :foo => "bar")
|
||||
end
|
||||
end
|
|
@ -31,7 +31,7 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
|
|||
@config = MockConfig.new
|
||||
@config.stubs(:logger).returns(stub_everything)
|
||||
@ssh_options = {
|
||||
:user => "jamis",
|
||||
:user => "user",
|
||||
:port => 8080,
|
||||
:password => "g00b3r",
|
||||
:ssh_options => { :debug => :verbose }
|
||||
|
@ -59,17 +59,16 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_connection_factory_should_return_gateway_instance_if_gateway_variable_is_set
|
||||
@config.values[:gateway] = "capistrano"
|
||||
server = server("capistrano")
|
||||
Capistrano::SSH.expects(:connect).with { |s,| s.host == "capistrano" }.yields(stub_everything)
|
||||
assert_instance_of Capistrano::Gateway, @config.connection_factory
|
||||
@config.values[:gateway] = "j@capistrano"
|
||||
Net::SSH::Gateway.expects(:new).with("capistrano", "j", :port => 22, :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything)
|
||||
assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
|
||||
end
|
||||
|
||||
def test_connection_factory_as_gateway_should_honor_config_options
|
||||
@config.values[:gateway] = "capistrano"
|
||||
@config.values.update(@ssh_options)
|
||||
Capistrano::SSH.expects(:connect).with { |s,opts| s.host == "capistrano" && opts == @config }.yields(stub_everything)
|
||||
assert_instance_of Capistrano::Gateway, @config.connection_factory
|
||||
Net::SSH::Gateway.expects(:new).with("capistrano", "user", :debug => :verbose, :port => 8080, :password => nil, :auth_methods => %w(publickey hostbased)).returns(stub_everything)
|
||||
assert_instance_of Capistrano::Configuration::Connections::GatewayConnectionFactory, @config.connection_factory
|
||||
end
|
||||
|
||||
def test_establish_connections_to_should_accept_a_single_nonarray_parameter
|
||||
|
@ -194,11 +193,11 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
|
|||
@config.current_task = mock_task
|
||||
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([server("cap1")])
|
||||
Capistrano::SSH.expects(:connect).raises(Exception)
|
||||
assert_raises(Capistrano::ConnectionError) {
|
||||
assert_raises(Capistrano::ConnectionError) do
|
||||
@config.execute_on_servers do
|
||||
flunk "expected an exception to be raised"
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def test_execute_servers_should_not_raise_connection_error_on_failure_with_on_errors_continue
|
||||
|
@ -243,14 +242,14 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_upload_errors_with_on_errors_continue
|
||||
def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_transfer_errors_with_on_errors_continue
|
||||
cap1 = server("cap1")
|
||||
cap2 = server("cap2")
|
||||
@config.current_task = mock_task(:on_error => :continue)
|
||||
@config.expects(:find_servers_for_task).with(@config.current_task, {}).returns([cap1, cap2])
|
||||
Capistrano::SSH.expects(:connect).times(2).returns(:success)
|
||||
@config.execute_on_servers do |servers|
|
||||
error = Capistrano::UploadError.new
|
||||
error = Capistrano::TransferError.new
|
||||
error.hosts = [cap1]
|
||||
raise error
|
||||
end
|
||||
|
|
|
@ -3,93 +3,93 @@ require 'capistrano/ssh'
|
|||
|
||||
class SSHTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@options = { :username => nil,
|
||||
:password => nil,
|
||||
Capistrano::ServerDefinition.stubs(:default_user).returns("default-user")
|
||||
@options = { :password => nil,
|
||||
:port => 22,
|
||||
:auth_methods => %w(publickey hostbased) }
|
||||
@server = server("capistrano")
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_without_options_or_config_with_public_key_succeeding_should_only_loop_once
|
||||
Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server)
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_without_options_with_public_key_failing_should_try_password
|
||||
Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, :password => "f4b13n")
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_without_options_public_key_and_password_failing_should_raise_error
|
||||
Net::SSH.expects(:start).with(@server.host, @options).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).raises(Net::SSH::AuthenticationFailed)
|
||||
assert_raises(Net::SSH::AuthenticationFailed) do
|
||||
Capistrano::SSH.connect(@server, :password => "f4b13n")
|
||||
end
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_and_user_via_public_key_should_pass_user_to_net_ssh
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis")).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "jamis", @options).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis")
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_and_user_via_password_should_pass_user_to_net_ssh
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis")).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis", :password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "jamis", @options).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, "jamis", @options.merge(:password => "f4b13n", :auth_methods => %w(password keyboard-interactive))).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, :user => "jamis", :password => "f4b13n")
|
||||
end
|
||||
|
||||
def test_connect_with_bare_server_with_explicit_port_should_pass_port_to_net_ssh
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:port => 1234)).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:port => 1234)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, :port => 1234)
|
||||
end
|
||||
|
||||
def test_connect_with_server_with_user_should_pass_user_to_net_ssh
|
||||
server = server("jamis@capistrano")
|
||||
Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis")).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(server.host, "jamis", @options).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(server)
|
||||
end
|
||||
|
||||
def test_connect_with_server_with_port_should_pass_port_to_net_ssh
|
||||
server = server("capistrano:1235")
|
||||
Net::SSH.expects(:start).with(server.host, @options.merge(:port => 1235)).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(server.host, "default-user", @options.merge(:port => 1235)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(server)
|
||||
end
|
||||
|
||||
def test_connect_with_server_with_user_and_port_should_pass_user_and_port_to_net_ssh
|
||||
server = server("jamis@capistrano:1235")
|
||||
Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis", :port => 1235)).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(server)
|
||||
end
|
||||
|
||||
def test_connect_with_server_with_other_ssh_options_should_pass_ssh_options_to_net_ssh
|
||||
server = server("jamis@capistrano:1235", :ssh_options => { :keys => %w(some_valid_key), :auth_methods => %w(a_method), :hmac => 'none' })
|
||||
Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis", :port => 1235, :keys => %w(some_valid_key), :auth_methods => %w(a_method), :hmac => 'none' )).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235, :keys => %w(some_valid_key), :auth_methods => %w(a_method), :hmac => 'none' )).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(server)
|
||||
end
|
||||
|
||||
def test_connect_with_ssh_options_should_use_ssh_options
|
||||
ssh_options = { :username => "JamisMan", :port => 8125 }
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "JamisMan", :port => 8125)).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "JamisMan", @options.merge(:port => 8125)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, {:ssh_options => ssh_options})
|
||||
end
|
||||
|
||||
def test_connect_with_options_and_ssh_options_should_see_options_override_ssh_options
|
||||
ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:username => "jamis", :port => 1235, :forward_agent => true)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, {:ssh_options => ssh_options, :user => "jamis", :port => 1235})
|
||||
Net::SSH.expects(:start).with(@server.host, "jamis", @options.merge(:port => 1235, :forward_agent => true)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server, :ssh_options => ssh_options, :user => "jamis", :port => 1235)
|
||||
end
|
||||
|
||||
def test_connect_with_ssh_options_should_see_server_options_override_ssh_options
|
||||
ssh_options = { :username => "JamisMan", :port => 8125, :forward_agent => true }
|
||||
server = server("jamis@capistrano:1235")
|
||||
Net::SSH.expects(:start).with(server.host, @options.merge(:username => "jamis", :port => 1235, :forward_agent => true)).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(server.host, "jamis", @options.merge(:port => 1235, :forward_agent => true)).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(server, {:ssh_options => ssh_options})
|
||||
end
|
||||
|
||||
def test_connect_should_add_xserver_accessor_to_connection
|
||||
Net::SSH.expects(:start).with(@server.host, @options).returns(success = Object.new)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options).returns(success = Object.new)
|
||||
assert_equal success, Capistrano::SSH.connect(@server)
|
||||
assert success.respond_to?(:xserver)
|
||||
assert success.respond_to?(:xserver)
|
||||
|
@ -97,7 +97,7 @@ class SSHTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_connect_should_not_retry_if_custom_auth_methods_are_given
|
||||
Net::SSH.expects(:start).with(@server.host, @options.merge(:auth_methods => %w(publickey))).raises(Net::SSH::AuthenticationFailed)
|
||||
Net::SSH.expects(:start).with(@server.host, "default-user", @options.merge(:auth_methods => %w(publickey))).raises(Net::SSH::AuthenticationFailed)
|
||||
assert_raises(Net::SSH::AuthenticationFailed) { Capistrano::SSH.connect(@server, :ssh_options => { :auth_methods => %w(publickey) }) }
|
||||
end
|
||||
end
|
||||
|
|
160
test/transfer_test.rb
Normal file
160
test/transfer_test.rb
Normal file
|
@ -0,0 +1,160 @@
|
|||
require 'utils'
|
||||
require 'capistrano/transfer'
|
||||
|
||||
class TransferTest < Test::Unit::TestCase
|
||||
def test_class_process_should_delegate_to_instance_process
|
||||
Capistrano::Transfer.expects(:new).with(:up, "from", "to", %w(a b c), {}).returns(mock('transfer', :process! => nil)).yields
|
||||
yielded = false
|
||||
Capistrano::Transfer.process(:up, "from", "to", %w(a b c), {}) { yielded = true }
|
||||
assert yielded
|
||||
end
|
||||
|
||||
def test_default_transport_is_sftp
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
||||
assert_equal :sftp, transfer.transport
|
||||
end
|
||||
|
||||
def test_active_is_true_when_any_sftp_transfers_are_active
|
||||
returns = [false, false, true]
|
||||
sessions = [session('app1', :sftp), session('app2', :sftp), session('app3', :sftp)].each { |s| s.xsftp.expects(:upload).returns(stub('operation', :active? => returns.shift)) }
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :sftp)
|
||||
assert_equal true, transfer.active?
|
||||
end
|
||||
|
||||
def test_active_is_false_when_all_sftp_transfers_are_not_active
|
||||
sessions = [session('app1', :sftp), session('app2', :sftp)].each { |s| s.xsftp.expects(:upload).returns(stub('operation', :active? => false)) }
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :sftp)
|
||||
assert_equal false, transfer.active?
|
||||
end
|
||||
|
||||
def test_active_is_true_when_any_scp_transfers_are_active
|
||||
returns = [false, false, true]
|
||||
sessions = [session('app1', :scp), session('app2', :scp), session('app3', :scp)].each do |s|
|
||||
channel = stub('channel', :[]= => nil, :active? => returns.shift)
|
||||
s.scp.expects(:upload).returns(channel)
|
||||
end
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :scp)
|
||||
assert_equal true, transfer.active?
|
||||
end
|
||||
|
||||
def test_active_is_false_when_all_scp_transfers_are_not_active
|
||||
sessions = [session('app1', :scp), session('app2', :scp), session('app3', :scp)].each do |s|
|
||||
channel = stub('channel', :[]= => nil, :active? => false)
|
||||
s.scp.expects(:upload).returns(channel)
|
||||
end
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", sessions, :via => :scp)
|
||||
assert_equal false, transfer.active?
|
||||
end
|
||||
|
||||
[:up, :down].each do |direction|
|
||||
define_method("test_sftp_#{direction}load_from_file_to_file_should_normalize_from_and_to") do
|
||||
sessions = [session('app1', :sftp), session('app2', :sftp)]
|
||||
|
||||
sessions.each do |session|
|
||||
session.xsftp.expects("#{direction}load".to_sym).with("from-#{session.xserver.host}", "to-#{session.xserver.host}",
|
||||
:properties => { :server => session.xserver, :host => session.xserver.host })
|
||||
end
|
||||
|
||||
transfer = Capistrano::Transfer.new(direction, "from-$CAPISTRANO:HOST$", "to-$CAPISTRANO:HOST$", sessions)
|
||||
end
|
||||
|
||||
define_method("test_scp_#{direction}load_from_file_to_file_should_normalize_from_and_to") do
|
||||
sessions = [session('app1', :scp), session('app2', :scp)]
|
||||
|
||||
sessions.each do |session|
|
||||
session.scp.expects("#{direction}load".to_sym).returns({}).with("from-#{session.xserver.host}", "to-#{session.xserver.host}", :via => :scp)
|
||||
end
|
||||
|
||||
transfer = Capistrano::Transfer.new(direction, "from-$CAPISTRANO:HOST$", "to-$CAPISTRANO:HOST$", sessions, :via => :scp)
|
||||
end
|
||||
end
|
||||
|
||||
def test_sftp_upload_from_IO_to_file_should_clone_the_IO_for_each_connection
|
||||
sessions = [session('app1', :sftp), session('app2', :sftp)]
|
||||
io = StringIO.new("from here")
|
||||
|
||||
sessions.each do |session|
|
||||
session.xsftp.expects(:upload).with do |from, to, opts|
|
||||
from != io && from.is_a?(StringIO) && from.string == io.string &&
|
||||
to == "/to/here-#{session.xserver.host}" &&
|
||||
opts[:properties][:server] == session.xserver &&
|
||||
opts[:properties][:host] == session.xserver.host
|
||||
end
|
||||
end
|
||||
|
||||
transfer = Capistrano::Transfer.new(:up, StringIO.new("from here"), "/to/here-$CAPISTRANO:HOST$", sessions)
|
||||
end
|
||||
|
||||
def test_scp_upload_from_IO_to_file_should_clone_the_IO_for_each_connection
|
||||
sessions = [session('app1', :scp), session('app2', :scp)]
|
||||
io = StringIO.new("from here")
|
||||
|
||||
sessions.each do |session|
|
||||
channel = mock('channel')
|
||||
channel.expects(:[]=).with(:server, session.xserver)
|
||||
channel.expects(:[]=).with(:host, session.xserver.host)
|
||||
session.scp.expects(:upload).returns(channel).with do |from, to, opts|
|
||||
from != io && from.is_a?(StringIO) && from.string == io.string &&
|
||||
to == "/to/here-#{session.xserver.host}"
|
||||
end
|
||||
end
|
||||
|
||||
transfer = Capistrano::Transfer.new(:up, StringIO.new("from here"), "/to/here-$CAPISTRANO:HOST$", sessions, :via => :scp)
|
||||
end
|
||||
|
||||
def test_process_should_block_until_transfer_is_no_longer_active
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
||||
transfer.expects(:process_iteration).times(4).yields.returns(true,true,true,false)
|
||||
transfer.expects(:active?).times(4)
|
||||
transfer.process!
|
||||
end
|
||||
|
||||
def test_errors_raised_for_a_sftp_session_should_abort_session_and_continue_with_remaining_sessions
|
||||
s = session('app1')
|
||||
error = ExceptionWithSession.new(s)
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", [])
|
||||
transfer.expects(:process_iteration).raises(error).times(3).returns(true, false)
|
||||
txfr = mock('transfer', :abort! => true)
|
||||
txfr.expects(:[]=).with(:failed, true)
|
||||
txfr.expects(:[]=).with(:error, error)
|
||||
transfer.expects(:session_map).returns(s => txfr)
|
||||
transfer.process!
|
||||
end
|
||||
|
||||
def test_errors_raised_for_a_scp_session_should_abort_session_and_continue_with_remaining_sessions
|
||||
s = session('app1')
|
||||
error = ExceptionWithSession.new(s)
|
||||
transfer = Capistrano::Transfer.new(:up, "from", "to", [], :via => :scp)
|
||||
transfer.expects(:process_iteration).raises(error).times(3).returns(true, false)
|
||||
txfr = mock('channel', :close => true)
|
||||
txfr.expects(:[]=).with(:failed, true)
|
||||
txfr.expects(:[]=).with(:error, error)
|
||||
transfer.expects(:session_map).returns(s => txfr)
|
||||
transfer.process!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
class ExceptionWithSession < ::Exception
|
||||
attr_reader :session
|
||||
|
||||
def initialize(session)
|
||||
@session = session
|
||||
super()
|
||||
end
|
||||
end
|
||||
|
||||
def session(host, mode=nil)
|
||||
session = stub('session', :xserver => stub('server', :host => host))
|
||||
case mode
|
||||
when :sftp
|
||||
sftp = stub('sftp')
|
||||
session.expects(:sftp).with(false).returns(sftp)
|
||||
sftp.expects(:connect).yields(sftp).returns(sftp)
|
||||
session.stubs(:xsftp).returns(sftp)
|
||||
when :scp
|
||||
session.stubs(:scp).returns(stub('scp'))
|
||||
end
|
||||
session
|
||||
end
|
||||
end
|
|
@ -1,131 +0,0 @@
|
|||
require "utils"
|
||||
require 'capistrano/upload'
|
||||
|
||||
class UploadTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@mode = IO::WRONLY | IO::CREAT | IO::TRUNC
|
||||
end
|
||||
|
||||
def test_initialize_should_raise_error_if_data_is_missing
|
||||
assert_raises(ArgumentError) do
|
||||
Capistrano::Upload.new([], "test.txt", :foo => "bar")
|
||||
end
|
||||
end
|
||||
|
||||
def test_initialize_should_get_sftp_for_each_session
|
||||
new_sftp = Proc.new do |state|
|
||||
sftp = mock("sftp", :state => state, :open => nil)
|
||||
sftp.expects(:connect) unless state == :open
|
||||
sftp.stubs(:channel).returns({})
|
||||
sftp
|
||||
end
|
||||
|
||||
sessions = [mock("session", :xserver => server("a"), :sftp => new_sftp[:closed]),
|
||||
mock("session", :xserver => server("b"), :sftp => new_sftp[:closed]),
|
||||
mock("session", :xserver => server("c"), :sftp => new_sftp[:open])]
|
||||
Capistrano::Upload.new(sessions, "test.txt", :data => "data")
|
||||
end
|
||||
|
||||
def test_self_process_should_instantiate_uploader_and_start_process
|
||||
Capistrano::Upload.expects(:new).with([:s1, :s2], "test.txt", :data => "data").returns(mock(:process! => nil))
|
||||
Capistrano::Upload.process([:s1, :s2], "test.txt", :data => "data")
|
||||
end
|
||||
|
||||
def test_process_when_sftp_open_fails_should_raise_error
|
||||
sftp = mock_sftp
|
||||
sftp.expects(:open).with("test.txt", @mode, 0664).yields(mock("status", :code => "bad status", :message => "bad status"), :file_handle)
|
||||
session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
|
||||
upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
|
||||
assert_raises(Capistrano::UploadError) { upload.process! }
|
||||
assert_equal 1, upload.failed
|
||||
assert_equal 1, upload.completed
|
||||
end
|
||||
|
||||
def test_process_when_sftp_write_fails_should_raise_error
|
||||
sftp = mock_sftp
|
||||
sftp.expects(:open).with("test.txt", @mode, 0664).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
|
||||
sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => "bad status", :message => "bad status"))
|
||||
session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
|
||||
upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
|
||||
assert_raises(Capistrano::UploadError) { upload.process! }
|
||||
assert_equal 1, upload.failed
|
||||
assert_equal 1, upload.completed
|
||||
end
|
||||
|
||||
def test_upload_error_should_include_accessor_with_host_array
|
||||
sftp = mock_sftp
|
||||
sftp.expects(:open).with("test.txt", @mode, 0664).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
|
||||
sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => "bad status", :message => "bad status"))
|
||||
session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
|
||||
upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
|
||||
|
||||
begin
|
||||
upload.process!
|
||||
flunk "expected an exception to be raised"
|
||||
rescue Capistrano::UploadError => e
|
||||
assert e.respond_to?(:hosts)
|
||||
assert_equal %w(capistrano), e.hosts.map { |h| h.to_s }
|
||||
end
|
||||
end
|
||||
|
||||
def test_process_when_sftp_succeeds_should_raise_nothing
|
||||
sftp = mock_sftp
|
||||
sftp.expects(:open).with("test.txt", @mode, 0664).yields(mock("status1", :code => Net::SFTP::Session::FX_OK), :file_handle)
|
||||
sftp.expects(:write).with(:file_handle, "data").yields(mock("status2", :code => Net::SFTP::Session::FX_OK))
|
||||
sftp.expects(:close_handle).with(:file_handle).yields
|
||||
session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
|
||||
upload = Capistrano::Upload.new([session], "test.txt", :data => "data", :logger => stub_everything)
|
||||
assert_nothing_raised { upload.process! }
|
||||
assert_equal 0, upload.failed
|
||||
assert_equal 1, upload.completed
|
||||
end
|
||||
|
||||
def test_process_should_loop_while_running
|
||||
con = mock("connection")
|
||||
con.expects(:process).with(true).times(10)
|
||||
channel = {}
|
||||
channel.expects(:connection).returns(con).times(10)
|
||||
sftp = mock("sftp", :state => :open, :open => nil)
|
||||
sftp.stubs(:channel).returns(channel)
|
||||
session = mock("session", :sftp => sftp, :xserver => server("capistrano"))
|
||||
upload = Capistrano::Upload.new([session], "test.txt", :data => "data")
|
||||
upload.expects(:running?).times(11).returns(*([true]*10 + [false]))
|
||||
upload.process!
|
||||
end
|
||||
|
||||
def test_process_should_loop_but_not_process_done_channels
|
||||
new_sftp = Proc.new do |done|
|
||||
channel = {}
|
||||
channel[:needs_done] = done
|
||||
|
||||
if !done
|
||||
con = mock("connection")
|
||||
con.expects(:process).with(true).times(10)
|
||||
channel.expects(:connection).returns(con).times(10)
|
||||
end
|
||||
|
||||
sftp = mock("sftp", :state => :open, :open => nil)
|
||||
sftp.stubs(:channel).returns(channel)
|
||||
sftp
|
||||
end
|
||||
|
||||
sessions = [stub("session", :sftp => new_sftp[true], :xserver => server("capistrano")),
|
||||
stub("session", :sftp => new_sftp[false], :xserver => server("cap2"))]
|
||||
upload = Capistrano::Upload.new(sessions, "test.txt", :data => "data")
|
||||
|
||||
# make sure the sftp channels we wanted to be done, start as done
|
||||
# (Upload.new marks each channel as not-done, so we have to do it here)
|
||||
sessions.each { |s| s.sftp.channel[:done] = true if s.sftp.channel[:needs_done] }
|
||||
upload.expects(:running?).times(11).returns(*([true]*10 + [false]))
|
||||
upload.process!
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mock_sftp
|
||||
sftp = mock("sftp", :state => :open)
|
||||
sftp.stubs(:channel).returns(Hash.new)
|
||||
yield sftp if block_given?
|
||||
sftp
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue