spec/storage/scp_spec.rb in backup-3.0.20 vs spec/storage/scp_spec.rb in backup-3.0.21

- old
+ new

@@ -1,203 +1,209 @@ # encoding: utf-8 require File.expand_path('../../spec_helper.rb', __FILE__) describe Backup::Storage::SCP do - - let(:scp) do - Backup::Storage::SCP.new do |scp| - scp.username = 'my_username' - scp.password = 'my_password' - scp.ip = '123.45.678.90' - scp.port = 22 - scp.path = '~/backups/' - scp.keep = 20 + let(:model) { Backup::Model.new(:test_trigger, 'test label') } + let(:storage) do + Backup::Storage::SCP.new(model) do |scp| + scp.username = 'my_username' + scp.password = 'my_password' + scp.ip = '123.45.678.90' + scp.keep = 5 end end - before do - Backup::Configuration::Storage::SCP.clear_defaults! - end + describe '#initialize' do + it 'should set the correct values' do + storage.username.should == 'my_username' + storage.password.should == 'my_password' + storage.ip.should == '123.45.678.90' + storage.port.should == 22 + storage.path.should == 'backups' - it 'should have defined the configuration properly' do - scp.username.should == 'my_username' - scp.password.should == 'my_password' - scp.ip.should == '123.45.678.90' - scp.port.should == 22 - scp.path.should == 'backups/' - scp.keep.should == 20 - end + storage.storage_id.should be_nil + storage.keep.should == 5 + end - it 'should use the defaults if a particular attribute has not been defined' do - Backup::Configuration::Storage::SCP.defaults do |scp| - scp.username = 'my_default_username' - scp.password = 'my_default_password' - scp.path = '~/backups' + it 'should set a storage_id if given' do + scp = Backup::Storage::SCP.new(model, 'my storage_id') + scp.storage_id.should == 'my storage_id' end - scp = Backup::Storage::SCP.new do |scp| - scp.password = 'my_password' - scp.ip = '123.45.678.90' + it 'should remove any preceeding tilde and slash from the path' do + storage = Backup::Storage::SCP.new(model) do |scp| + scp.path = '~/my_backups/path' + end + storage.path.should == 'my_backups/path' end - scp.username.should == 'my_default_username' - scp.password.should == 'my_password' - scp.ip.should == '123.45.678.90' - scp.port.should == 22 - end + context 'when setting configuration defaults' do + after { Backup::Configuration::Storage::SCP.clear_defaults! } - it 'should have its own defaults' do - scp = Backup::Storage::SCP.new - scp.port.should == 22 - scp.path.should == 'backups' - end + it 'should use the configured defaults' do + Backup::Configuration::Storage::SCP.defaults do |scp| + scp.username = 'some_username' + scp.password = 'some_password' + scp.ip = 'some_ip' + scp.port = 'some_port' + scp.path = 'some_path' + scp.keep = 'some_keep' + end + storage = Backup::Storage::SCP.new(model) + storage.username.should == 'some_username' + storage.password.should == 'some_password' + storage.ip.should == 'some_ip' + storage.port.should == 'some_port' + storage.path.should == 'some_path' - describe '#perform' do - it 'should invoke transfer! and cycle!' do - scp.expects(:transfer!) - scp.expects(:cycle!) - scp.perform! - end - end + storage.storage_id.should be_nil + storage.keep.should == 'some_keep' + end + it 'should override the configured defaults' do + Backup::Configuration::Storage::SCP.defaults do |scp| + scp.username = 'old_username' + scp.password = 'old_password' + scp.ip = 'old_ip' + scp.port = 'old_port' + scp.path = 'old_path' + scp.keep = 'old_keep' + end + storage = Backup::Storage::SCP.new(model) do |scp| + scp.username = 'new_username' + scp.password = 'new_password' + scp.ip = 'new_ip' + scp.port = 'new_port' + scp.path = 'new_path' + scp.keep = 'new_keep' + end + + storage.username.should == 'new_username' + storage.password.should == 'new_password' + storage.ip.should == 'new_ip' + storage.port.should == 'new_port' + storage.path.should == 'new_path' + + storage.storage_id.should be_nil + storage.keep.should == 'new_keep' + end + end # context 'when setting configuration defaults' + + end # describe '#initialize' + describe '#connection' do - it 'should establish a connection to the remote server' do - connection = mock + let(:connection) { mock } + it 'should yield a Net::SSH connection' do Net::SSH.expects(:start).with( - '123.45.678.90', - 'my_username', - :password => 'my_password', - :port => 22 + '123.45.678.90', 'my_username', :password => 'my_password', :port => 22 ).yields(connection) - scp.send(:connection) do |ssh| - ssh.should be connection + storage.send(:connection) do |ssh| + ssh.should be(connection) end end end describe '#transfer!' do + let(:connection) { mock } + let(:package) { mock } + let(:ssh_scp) { mock } + let(:s) { sequence '' } before do - scp.stubs(:storage_name).returns('Storage::SCP') + storage.instance_variable_set(:@package, package) + storage.stubs(:storage_name).returns('Storage::SCP') + storage.stubs(:local_path).returns('/local/path') + storage.stubs(:connection).yields(connection) + connection.stubs(:scp).returns(ssh_scp) end - context 'when file chunking is not used' do - it 'should create remote paths and transfer using a single connection' do - ssh, ssh_scp = mock, mock - local_file = "#{ Backup::TIME }.#{ Backup::TRIGGER }.tar" - remote_file = "#{ Backup::TRIGGER }.tar" + it 'should transfer the package files' do + storage.expects(:remote_path_for).in_sequence(s).with(package). + returns('remote/path') + connection.expects(:exec!).in_sequence(s).with("mkdir -p 'remote/path'") - scp.expects(:connection).yields(ssh) - scp.expects(:create_remote_directories).with(ssh) + storage.expects(:files_to_transfer_for).in_sequence(s).with(package). + multiple_yields( + ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'], + ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab'] + ) + # first yield + Backup::Logger.expects(:message).in_sequence(s).with( + "Storage::SCP started transferring " + + "'2011.12.31.11.00.02.backup.tar.enc-aa' to '123.45.678.90'." + ) + ssh_scp.expects(:upload!).in_sequence(s).with( + File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-aa'), + File.join('remote/path', 'backup.tar.enc-aa') + ) + # second yield + Backup::Logger.expects(:message).in_sequence(s).with( + "Storage::SCP started transferring " + + "'2011.12.31.11.00.02.backup.tar.enc-ab' to '123.45.678.90'." + ) + ssh_scp.expects(:upload!).in_sequence(s).with( + File.join('/local/path', '2011.12.31.11.00.02.backup.tar.enc-ab'), + File.join('remote/path', 'backup.tar.enc-ab') + ) - Backup::Logger.expects(:message).with( - "Storage::SCP started transferring '#{local_file}' to '#{scp.ip}'." - ) - - ssh.expects(:scp).returns(ssh_scp) - ssh_scp.expects(:upload!).with( - File.join(Backup::TMP_PATH, local_file), - File.join('backups/myapp', Backup::TIME, remote_file) - ) - - scp.send(:transfer!) - end + storage.send(:transfer!) end - - context 'when file chunking is used' do - it 'should transfer all the provided files using a single connection' do - s = sequence '' - ssh, ssh_scp = mock, mock - - scp.expects(:connection).in_sequence(s).yields(ssh) - scp.expects(:create_remote_directories).in_sequence(s).with(ssh) - - scp.expects(:files_to_transfer).in_sequence(s).multiple_yields( - ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2'] - ) - - Backup::Logger.expects(:message).in_sequence(s).with( - "Storage::SCP started transferring 'local_file1' to '#{scp.ip}'." - ) - ssh.expects(:scp).in_sequence(s).returns(ssh_scp) - ssh_scp.expects(:upload!).in_sequence(s).with( - File.join(Backup::TMP_PATH, 'local_file1'), - File.join('backups/myapp', Backup::TIME, 'remote_file1') - ) - - Backup::Logger.expects(:message).in_sequence(s).with( - "Storage::SCP started transferring 'local_file2' to '#{scp.ip}'." - ) - ssh.expects(:scp).in_sequence(s).returns(ssh_scp) - ssh_scp.expects(:upload!).in_sequence(s).with( - File.join(Backup::TMP_PATH, 'local_file2'), - File.join('backups/myapp', Backup::TIME, 'remote_file2') - ) - - scp.send(:transfer!) - end - end - end # describe '#transfer!' describe '#remove!' do + let(:package) { mock } + let(:connection) { mock } + let(:s) { sequence '' } before do - scp.stubs(:storage_name).returns('Storage::SCP') + storage.stubs(:storage_name).returns('Storage::SCP') + storage.stubs(:connection).yields(connection) end - it 'should remove all remote files with a single logger call' do - ssh = mock + it 'should remove the package files' do + storage.expects(:remote_path_for).in_sequence(s).with(package). + returns('remote/path') - scp.expects(:transferred_files).multiple_yields( - ['local_file1', 'remote_file1'], ['local_file2', 'remote_file2'] + storage.expects(:transferred_files_for).in_sequence(s).with(package). + multiple_yields( + ['2011.12.31.11.00.02.backup.tar.enc-aa', 'backup.tar.enc-aa'], + ['2011.12.31.11.00.02.backup.tar.enc-ab', 'backup.tar.enc-ab'] ) - - Backup::Logger.expects(:message).with( - "Storage::SCP started removing 'local_file1' from '#{scp.ip}'.\n" + - "Storage::SCP started removing 'local_file2' from '#{scp.ip}'." + # after both yields + Backup::Logger.expects(:message).in_sequence(s).with( + "Storage::SCP started removing " + + "'2011.12.31.11.00.02.backup.tar.enc-aa' from '123.45.678.90'.\n" + + "Storage::SCP started removing " + + "'2011.12.31.11.00.02.backup.tar.enc-ab' from '123.45.678.90'." ) + connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s) - scp.expects(:connection).yields(ssh) - ssh.expects(:exec!).with("rm -r 'backups/myapp/#{ Backup::TIME }'") - - scp.send(:remove!) + storage.send(:remove!, package) end - it 'should raise an error if Net::SSH reports errors' do - ssh = mock + context 'when the ssh connection reports errors' do + it 'should raise an error reporting the errors' do + storage.expects(:remote_path_for).in_sequence(s).with(package). + returns('remote/path') - scp.expects(:transferred_files) - Backup::Logger.expects(:message) + storage.expects(:transferred_files_for).in_sequence(s).with(package) - scp.expects(:connection).yields(ssh) - ssh.expects(:exec!).yields('', :stderr, 'error message') + Backup::Logger.expects(:message).in_sequence(s) - expect do - scp.send(:remove!) - end.to raise_error( - Backup::Errors::Storage::SCP::SSHError, - "Storage::SCP::SSHError: Net::SSH reported the following errors:\n" + - " error message" - ) - end + connection.expects(:exec!).with("rm -r 'remote/path'").in_sequence(s). + yields(:ch, :stderr, 'path not found') - end # describe '#remove!' - - describe '#create_remote_directories' do - it 'should properly create remote directories one by one' do - ssh = mock - scp.path = 'backups/some_other_folder/another_folder' - - ssh.expects(:exec!).with("mkdir 'backups'") - ssh.expects(:exec!).with("mkdir 'backups/some_other_folder'") - ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder'") - ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder/myapp'") - ssh.expects(:exec!).with("mkdir 'backups/some_other_folder/another_folder/myapp/#{ Backup::TIME }'") - - scp.send(:create_remote_directories, ssh) + expect do + storage.send(:remove!, package) + end.to raise_error {|err| + err.should be_an_instance_of Backup::Errors::Storage::SCP::SSHError + err.message.should == "Storage::SCP::SSHError: " + + "Net::SSH reported the following errors:\n" + + " path not found" + } + end end - end + end # describe '#remove!' end