def test_sync_backup(self, logger_mock, rsync_mock, tmpdir, capsys): """ Test the synchronisation method, testing all the possible error conditions. :param MagicMock logger_mock: MagicMock obj mimicking the logger :param MagicMock rsync_mock: MagicMock replacing Rsync class :param py.local.path tmpdir: py.test temporary directory :param capsys: fixture that allow to access stdout/stderr output """ backup_name = '1234567890' server_name = 'main' # Prepare paths backup_dir = tmpdir.mkdir(server_name) basebackup_dir = backup_dir.mkdir("base") full_backup_path = basebackup_dir.mkdir(backup_name) primary_info_file = backup_dir.join(barman.server.PRIMARY_INFO_FILE) # prepare the primary_info file remote_basebackup_dir = tmpdir.mkdir("primary") primary_info_content = dict(EXPECTED_MINIMAL) primary_info_content['config'].update( basebackups_directory=str(remote_basebackup_dir)) primary_info_file.write(json.dumps(primary_info_content)) # Test 1: Not a passive node. # Expect SyncError server = build_real_server( global_conf={'barman_lock_directory': tmpdir.strpath}, main_conf={'backup_directory': backup_dir.strpath}) with pytest.raises(SyncError): server.sync_backup(backup_name) # Test 2: normal sync execution, no error expected. # test for all the step on the logger logger_mock.reset_mock() server = build_real_server( global_conf={'barman_lock_directory': tmpdir.strpath}, main_conf={ 'backup_directory': backup_dir.strpath, 'primary_ssh_command': 'ssh fakeuser@fakehost' }) server.sync_backup(backup_name) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 1/3: " "parse server information", server_name, backup_name) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 2/3: " "file copy", server_name, backup_name) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 3/3: " "finalise sync", server_name, backup_name) # Test 3: test Rsync Failure # Expect a BackupInfo object with status "FAILED" # and a error message on the "error" field of the obj rsync_mock.reset_mock() server.backup_manager._backup_cache = {} rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.FAILED assert backup_info.error == 'failure syncing server main ' \ 'backup 1234567890: TestFailure' # Test 4: test KeyboardInterrupt management # Check the error message for the KeyboardInterrupt event rsync_mock.reset_mock() rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) rsync_mock.side_effect = KeyboardInterrupt() server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.FAILED assert backup_info.error == 'failure syncing server main ' \ 'backup 1234567890: KeyboardInterrupt' # Test 5: test backup name not present on Master server # Expect a error message on stderr rsync_mock.reset_mock() rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) server.sync_backup('wrong_backup_name') (out, err) = capsys.readouterr() # Check the stderr using capsys. we need only the first line # from stderr e = err.split('\n') assert 'ERROR: failure syncing server main ' \ 'backup 1234567890: TestFailure' in e # Test 5: Backup already synced # Check for the warning message on the stout using capsys rsync_mock.reset_mock() rsync_mock.side_effect = None # do it the first time and check it succeeded server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.DONE # do it again ant test it does not call rsync rsync_mock.reset_mock() server.sync_backup(backup_name) assert not rsync_mock.called (out, err) = capsys.readouterr() assert out.strip() == 'Backup 1234567890 is already' \ ' synced with main server'
def test_sync_backup(self, logger_mock, rsync_mock, tmpdir, capsys): """ Test the synchronisation method, testing all the possible error conditions. :param MagicMock logger_mock: MagicMock obj mimicking the logger :param MagicMock rsync_mock: MagicMock replacing Rsync class :param py.local.path tmpdir: py.test temporary directory :param capsys: fixture that allow to access stdout/stderr output """ backup_name = "1234567890" server_name = "main" # Prepare paths backup_dir = tmpdir.mkdir(server_name) basebackup_dir = backup_dir.mkdir("base") full_backup_path = basebackup_dir.mkdir(backup_name) self._create_primary_info_file(tmpdir, backup_dir) # Test 1: Not a passive node. # Expect SyncError server = build_real_server( global_conf={"barman_lock_directory": tmpdir.strpath}, main_conf={"backup_directory": backup_dir.strpath}, ) with pytest.raises(SyncError): server.sync_backup(backup_name) # Test 2: normal sync execution, no error expected. # test for all the step on the logger logger_mock.reset_mock() server = build_real_server( global_conf={"barman_lock_directory": tmpdir.strpath}, main_conf={ "backup_directory": backup_dir.strpath, "primary_ssh_command": "ssh fakeuser@fakehost", }, ) server.sync_backup(backup_name) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 1/3: " "parse server information", server_name, backup_name, ) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 2/3: file copy", server_name, backup_name, ) logger_mock.info.assert_any_call( "Synchronising with server %s backup %s: step 3/3: finalise sync", server_name, backup_name, ) # Test 3: test Rsync Failure # Expect a BackupInfo object with status "FAILED" # and a error message on the "error" field of the obj rsync_mock.reset_mock() server.backup_manager._backup_cache = {} rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.FAILED assert ( backup_info.error == "failure syncing server main " "backup 1234567890: TestFailure" ) # Test 4: test KeyboardInterrupt management # Check the error message for the KeyboardInterrupt event rsync_mock.reset_mock() rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) rsync_mock.side_effect = KeyboardInterrupt() server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.FAILED assert ( backup_info.error == "failure syncing server main " "backup 1234567890: KeyboardInterrupt" ) # Test 5: test backup name not present on Master server # Expect a error message on stderr rsync_mock.reset_mock() rsync_mock.side_effect = CommandFailedException("TestFailure") full_backup_path.remove(rec=1) server.sync_backup("wrong_backup_name") (out, err) = capsys.readouterr() # Check the stderr using capsys. we need only the first line # from stderr e = err.split("\n") assert "ERROR: failure syncing server main backup 1234567890: TestFailure" in e # Test 5: Backup already synced # Check for the warning message on the stout using capsys rsync_mock.reset_mock() rsync_mock.side_effect = None # do it the first time and check it succeeded server.sync_backup(backup_name) backup_info = server.get_backup(backup_name) assert backup_info.status == BackupInfo.DONE # do it again ant test it does not call rsync rsync_mock.reset_mock() server.sync_backup(backup_name) assert not rsync_mock.called (out, err) = capsys.readouterr() assert out.strip() == "Backup 1234567890 is already synced with main server"