Skip to content
Browse files

tests all pass

  • Loading branch information...
1 parent b4bd528 commit 8f0f99565e4ff8a9c3acf9544283be343787be91 @jamis jamis committed Apr 27, 2008
View
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
View
4 lib/capistrano/configuration/actions/file_transfer.rb
@@ -9,7 +9,9 @@ module FileTransfer
# 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
View
8 lib/capistrano/configuration/connections.rb
@@ -1,6 +1,7 @@
require 'enumerator'
require 'net/ssh/gateway'
require 'capistrano/ssh'
+require 'capistrano/errors'
module Capistrano
class Configuration
@@ -24,8 +25,11 @@ class GatewayConnectionFactory #:nodoc:
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 @@ def establish_connection_to(server, failures=nil)
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
View
23 lib/capistrano/ssh.rb
@@ -39,23 +39,38 @@ def self.apply_to(connection, server)
# 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
ssh_options = (server.options[:ssh_options] || {}).merge(options[:ssh_options] || {})
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]
View
40 lib/capistrano/transfer.rb
@@ -31,9 +31,11 @@ def initialize(direction, from, to, sessions, options={}, &block)
@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 @@ def sanitized_to
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 @@ def prepare_transfers
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 @@ class SFTPTransferWrapper
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 @@ def prepare_sftp_transfer(from, to, session)
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 @@ def normalize(argument, session)
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
View
80 test/command_test.rb
@@ -20,8 +20,7 @@ def test_command_with_windows_newlines_should_be_properly_escaped
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 @@ def test_successful_channel_should_send_data_if_data_key_is_present
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 @@ def test_on_extended_data_should_invoke_callback_as_stderr
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 @@ def test_on_close_should_set_channel_closed
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 @@ def test_process_should_loop_until_all_channels_are_closed
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 @@ def test_process_with_unknown_placeholder_should_not_replace_placeholder
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 @@ def setup_for_extracting_channel_action(action=nil, *args)
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?
View
38 test/configuration/actions/file_transfer_test.rb
@@ -4,37 +4,39 @@
class ConfigurationActionsFileTransferTest < Test::Unit::TestCase
class MockConfig
include Capistrano::Configuration::Actions::FileTransfer
+ attr_accessor :sessions
end
def setup
@config = MockConfig.new
@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")
+ 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_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)
- @config.put("some data", "test.txt", :mode => 0777)
+ 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_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_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
- 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_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
- 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_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
View
21 test/configuration/connections_test.rb
@@ -31,7 +31,7 @@ def setup
@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 @@ def test_default_connection_factory_honors_config_options
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 @@ def test_execute_servers_should_raise_connection_error_on_failure_by_default
@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 @@ def test_execute_on_servers_should_not_try_to_connect_to_hosts_with_command_erro
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
View
42 test/ssh_test.rb
@@ -3,101 +3,101 @@
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)
assert_equal success.xserver, @server
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
View
160 test/transfer_test.rb
@@ -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
View
131 test/upload_test.rb
@@ -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

0 comments on commit 8f0f995

Please sign in to comment.
Something went wrong with that request. Please try again.