require "common"
class DownloadTest < Net::SFTP::TestCase
def setup
prepare_progress!
end
def test_download_file_should_transfer_remote_to_local
local = "/path/to/local"
remote = "/path/to/remote"
text = "this is some text\n"
expect_file_transfer(remote, text)
file = StringIO.new
File.stubs(:open).with(local, "wb").returns(file)
assert_scripted_command { sftp.download(remote, local) }
assert_equal text, file.string
end
def test_download_large_file_should_transfer_remote_to_local
local = "/path/to/local"
remote = "/path/to/remote"
text = "0123456789" * 1024
file = prepare_large_file_download(local, remote, text)
assert_scripted_command { sftp.download(remote, local, :read_size => 1024) }
assert_equal text, file.string
end
def test_download_large_file_with_progress_should_report_progress
local = "/path/to/local"
remote = "/path/to/remote"
text = "0123456789" * 1024
file = prepare_large_file_download(local, remote, text)
assert_scripted_command do
sftp.download(remote, local, :read_size => 1024) do |*args|
record_progress(args)
end
end
assert_equal text, file.string
assert_progress_reported_open :remote => "/path/to/remote"
assert_progress_reported_get 0, 1024
assert_progress_reported_get 1024, 1024
assert_progress_reported_get 2048, 1024
assert_progress_reported_get 3072, 1024
assert_progress_reported_get 4096, 1024
assert_progress_reported_get 5120, 1024
assert_progress_reported_get 6144, 1024
assert_progress_reported_get 7168, 1024
assert_progress_reported_get 8192, 1024
assert_progress_reported_get 9216, 1024
assert_progress_reported_close
assert_progress_reported_finish
assert_no_more_reported_events
end
def test_download_directory_should_mirror_directory_locally
file1, file2 = prepare_directory_tree_download("/path/to/local", "/path/to/remote")
assert_scripted_command do
sftp.download("/path/to/remote", "/path/to/local", :recursive => true)
end
assert_equal "contents of file1", file1.string
assert_equal "contents of file2", file2.string
end
def test_download_directory_with_progress_should_report_progress
file1, file2 = prepare_directory_tree_download("/path/to/local", "/path/to/remote")
assert_scripted_command do
sftp.download("/path/to/remote", "/path/to/local", :recursive => true) do |*args|
record_progress(args)
end
end
assert_equal "contents of file1", file1.string
assert_equal "contents of file2", file2.string
assert_progress_reported_mkdir "/path/to/local"
assert_progress_reported_mkdir "/path/to/local/subdir1"
assert_progress_reported_open :remote => "/path/to/remote/file1"
assert_progress_reported_open :remote => "/path/to/remote/subdir1/file2"
assert_progress_reported_get 0, "contents of file1"
assert_progress_reported_close :remote => "/path/to/remote/file1"
assert_progress_reported_get 0, "contents of file2"
assert_progress_reported_close :remote => "/path/to/remote/subdir1/file2"
assert_progress_reported_finish
assert_no_more_reported_events
end
def test_download_file_should_transfer_remote_to_local_buffer
remote = "/path/to/remote"
text = "this is some text\n"
expect_file_transfer(remote, text)
local = StringIO.new
assert_scripted_command { sftp.download(remote, local) }
assert_equal text, local.string
end
def test_download_directory_to_buffer_should_fail
expect_sftp_session :server_version => 3
assert_raises(ArgumentError) { sftp.download("/path/to/remote", StringIO.new, :recursive => true) }
end
private
def expect_file_transfer(remote, text)
expect_sftp_session :server_version => 3 do |channel|
channel.sends_packet(FXP_OPEN, :long, 0, :string, remote, :long, 0x01, :long, 0)
channel.gets_packet(FXP_HANDLE, :long, 0, :string, "handle")
channel.sends_packet(FXP_READ, :long, 1, :string, "handle", :int64, 0, :long, 32_000)
channel.gets_packet(FXP_DATA, :long, 1, :string, text)
channel.sends_packet(FXP_READ, :long, 2, :string, "handle", :int64, 32_000, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 2, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 3, :string, "handle")
channel.gets_packet(FXP_STATUS, :long, 3, :long, 0)
end
end
def prepare_large_file_download(local, remote, text)
expect_sftp_session :server_version => 3 do |channel|
channel.sends_packet(FXP_OPEN, :long, 0, :string, remote, :long, 0x01, :long, 0)
channel.gets_packet(FXP_HANDLE, :long, 0, :string, "handle")
10.times do |n|
channel.sends_packet(FXP_READ, :long, n+1, :string, "handle", :int64, n*1024, :long, 1024)
channel.gets_packet(FXP_DATA, :long, n+1, :string, text[n*1024,1024])
end
channel.sends_packet(FXP_READ, :long, 11, :string, "handle", :int64, 10240, :long, 1024)
channel.gets_packet(FXP_STATUS, :long, 11, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 12, :string, "handle")
channel.gets_packet(FXP_STATUS, :long, 12, :long, 0)
end
file = StringIO.new
File.stubs(:open).with(local, "wb").returns(file)
return file
end
# 0:OPENDIR(remote) ->
# <- 0:HANDLE("dir1")
# 1:READDIR("dir1") ->
# <- 1:NAME("..", ".", "subdir1", "file1")
# 2:OPENDIR(remote/subdir1) ->
# 3:OPEN(remote/file1) ->
# 4:READDIR("dir1") ->
# <- 2:HANDLE("dir2")
# 5:READDIR("dir2") ->
# <- 3:HANDLE("file1")
# 6:READ("file1", 0, 32k) ->
# <- 4:STATUS(1)
# 7:CLOSE("dir1") ->
# <- 5:NAME("..", ".", "file2")
# 8:OPEN(remote/subdir1/file2) ->
# 9:READDIR("dir2") ->
# <- 6:DATA("blah blah blah")
# 10:READ("file1", n, 32k)
# <- 7:STATUS(0)
# <- 8:HANDLE("file2")
# 11:READ("file2", 0, 32k) ->
# <- 9:STATUS(1)
# 12:CLOSE("dir2") ->
# <- 10:STATUS(1)
# 13:CLOSE("file1") ->
# <- 11:DATA("blah blah blah")
# 14:READ("file2", n, 32k) ->
# <- 12:STATUS(0)
# <- 13:STATUS(0)
# <- 14:STATUS(1)
# 15:CLOSE("file2") ->
# <- 15:STATUS(0)
def prepare_directory_tree_download(local, remote)
expect_sftp_session :server_version => 3 do |channel|
channel.sends_packet(FXP_OPENDIR, :long, 0, :string, remote)
channel.gets_packet(FXP_HANDLE, :long, 0, :string, "dir1")
channel.sends_packet(FXP_READDIR, :long, 1, :string, "dir1")
channel.gets_packet(FXP_NAME, :long, 1, :long, 4,
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x04, :long, 040755,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x04, :long, 040755,
:string, "subdir1", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 subdir1", :long, 0x04, :long, 040755,
:string, "file1", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file1", :long, 0x04, :long, 0100644)
channel.sends_packet(FXP_OPENDIR, :long, 2, :string, File.join(remote, "subdir1"))
channel.sends_packet(FXP_OPEN, :long, 3, :string, File.join(remote, "file1"), :long, 0x01, :long, 0)
channel.sends_packet(FXP_READDIR, :long, 4, :string, "dir1")
channel.gets_packet(FXP_HANDLE, :long, 2, :string, "dir2")
channel.sends_packet(FXP_READDIR, :long, 5, :string, "dir2")
channel.gets_packet(FXP_HANDLE, :long, 3, :string, "file1")
channel.sends_packet(FXP_READ, :long, 6, :string, "file1", :int64, 0, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 4, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 7, :string, "dir1")
channel.gets_packet(FXP_NAME, :long, 5, :long, 3,
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x04, :long, 040755,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x04, :long, 040755,
:string, "file2", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file2", :long, 0x04, :long, 0100644)
channel.sends_packet(FXP_OPEN, :long, 8, :string, File.join(remote, "subdir1", "file2"), :long, 0x01, :long, 0)
channel.sends_packet(FXP_READDIR, :long, 9, :string, "dir2")
channel.gets_packet(FXP_DATA, :long, 6, :string, "contents of file1")
channel.sends_packet(FXP_READ, :long, 10, :string, "file1", :int64, 32_000, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 7, :long, 0)
channel.gets_packet(FXP_HANDLE, :long, 8, :string, "file2")
channel.sends_packet(FXP_READ, :long, 11, :string, "file2", :int64, 0, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 9, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 12, :string, "dir2")
channel.gets_packet(FXP_STATUS, :long, 10, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 13, :string, "file1")
channel.gets_packet(FXP_DATA, :long, 11, :string, "contents of file2")
channel.sends_packet(FXP_READ, :long, 14, :string, "file2", :int64, 32_000, :long, 32_000)
channel.gets_packet(FXP_STATUS, :long, 12, :long, 0)
channel.gets_packet(FXP_STATUS, :long, 13, :long, 0)
channel.gets_packet(FXP_STATUS, :long, 14, :long, 1)
channel.sends_packet(FXP_CLOSE, :long, 15, :string, "file2")
channel.gets_packet(FXP_STATUS, :long, 15, :long, 0)
end
File.expects(:directory?).with(local).returns(false)
File.expects(:directory?).with(File.join(local, "subdir1")).returns(false)
Dir.expects(:mkdir).with(local)
Dir.expects(:mkdir).with(File.join(local, "subdir1"))
file1 = StringIO.new
file2 = StringIO.new
File.expects(:open).with(File.join(local, "file1"), "wb").returns(file1)
File.expects(:open).with(File.join(local, "subdir1", "file2"), "wb").returns(file2)
[file1, file2]
end
end