def test_recover_xlog(self, rsync_pg_mock, cm_mock, tmpdir): """ Test the recovery of the xlogs of a backup :param rsync_pg_mock: Mock rsync object for the purpose if this test """ # Build basic folders/files structure dest = tmpdir.mkdir("destination") wals = tmpdir.mkdir("wals") # Create 3 WAL files with different compressions xlog_dir = wals.mkdir(xlog.hash_dir("000000000000000000000002")) xlog_plain = xlog_dir.join("000000000000000000000001") xlog_gz = xlog_dir.join("000000000000000000000002") xlog_bz2 = xlog_dir.join("000000000000000000000003") xlog_plain.write("dummy content") xlog_gz.write("dummy content gz") xlog_bz2.write("dummy content bz2") server = testing_helpers.build_real_server(main_conf={"wals_directory": wals.strpath}) # Prepare compressors mock c = {"gzip": mock.Mock(name="gzip"), "bzip2": mock.Mock(name="bzip2")} cm_mock.return_value.get_compressor = lambda compression=None, path=None: c[compression] # touch destination files to avoid errors on cleanup c["gzip"].decompress.side_effect = lambda src, dst: open(dst, "w") c["bzip2"].decompress.side_effect = lambda src, dst: open(dst, "w") # Build executor executor = RecoveryExecutor(server.backup_manager) # Test: local copy required_wals = ( WalFileInfo.from_xlogdb_line("000000000000000000000001\t42\t43\tNone\n"), WalFileInfo.from_xlogdb_line("000000000000000000000002\t42\t43\tgzip\n"), WalFileInfo.from_xlogdb_line("000000000000000000000003\t42\t43\tbzip2\n"), ) executor._xlog_copy(required_wals, dest.strpath, None) # Check for a correct invocation of rsync using local paths rsync_pg_mock.assert_called_once_with(network_compression=False, bwlimit=None, path=None, ssh=None) assert not rsync_pg_mock.return_value.from_file_list.called c["gzip"].decompress.assert_called_once_with(xlog_gz.strpath, mock.ANY) c["bzip2"].decompress.assert_called_once_with(xlog_bz2.strpath, mock.ANY) # Reset mock calls rsync_pg_mock.reset_mock() c["gzip"].reset_mock() c["bzip2"].reset_mock() # Test: remote copy executor._xlog_copy(required_wals, dest.strpath, "remote_command") # Check for the invocation of rsync on a remote call rsync_pg_mock.assert_called_once_with( network_compression=False, bwlimit=None, path=mock.ANY, ssh="remote_command" ) rsync_pg_mock.return_value.from_file_list.assert_called_once_with( ["000000000000000000000001", "000000000000000000000002", "000000000000000000000003"], mock.ANY, mock.ANY ) c["gzip"].decompress.assert_called_once_with(xlog_gz.strpath, mock.ANY) c["bzip2"].decompress.assert_called_once_with(xlog_bz2.strpath, mock.ANY)
def test_recover_standby_mode(self, tmpdir): backup_info = testing_helpers.build_test_backup_info() backup_manager = testing_helpers.build_backup_manager() executor = RecoveryExecutor(backup_manager) backup_info.version = 90300 destination = tmpdir.mkdir('destination').strpath # If standby mode is not enabled, recovery.conf is not generated executor._prepare_tablespaces = MagicMock() executor._backup_copy = MagicMock() executor._xlog_copy = MagicMock() executor._generate_recovery_conf = MagicMock() with closing(executor): executor.recover(backup_info, destination, standby_mode=None) executor._generate_recovery_conf.assert_not_called() # If standby mode is enabled, recovery.conf is generated executor._prepare_tablespaces.reset_mock() executor._backup_copy.reset_mock() executor._xlog_copy.reset_mock() executor._generate_recovery_conf.reset_mock() with closing(executor): executor.recover(backup_info, destination, standby_mode=True) executor._generate_recovery_conf.assert_called() # If standby mode is passed but PostgreSQL is older than 9.0, # we must raise an exception backup_info.version = 80000 with pytest.raises(RecoveryStandbyModeException): with closing(executor): executor.recover(backup_info, destination, standby_mode=True)
def test_recover_xlog(self, rsync_pg_mock, cm_mock, tmpdir): """ Test the recovery of the xlogs of a backup :param rsync_pg_mock: Mock rsync object for the purpose if this test """ # Build basic folders/files structure dest = tmpdir.mkdir('destination') wals = tmpdir.mkdir('wals') # Create 3 WAL files with different compressions xlog_dir = wals.mkdir(xlog.hash_dir('000000000000000000000002')) xlog_plain = xlog_dir.join('000000000000000000000001') xlog_gz = xlog_dir.join('000000000000000000000002') xlog_bz2 = xlog_dir.join('000000000000000000000003') xlog_plain.write('dummy content') xlog_gz.write('dummy content gz') xlog_bz2.write('dummy content bz2') server = testing_helpers.build_real_server( main_conf={'wals_directory': wals.strpath}) # Prepare compressors mock c = { 'gzip': mock.Mock(name='gzip'), 'bzip2': mock.Mock(name='bzip2'), } cm_mock.return_value.get_compressor = \ lambda compression=None, path=None: c[compression] # touch destination files to avoid errors on cleanup c['gzip'].decompress.side_effect = lambda src, dst: open(dst, 'w') c['bzip2'].decompress.side_effect = lambda src, dst: open(dst, 'w') # Build executor executor = RecoveryExecutor(server.backup_manager) # Test: local copy required_wals = ( WalFileInfo.from_xlogdb_line( '000000000000000000000001\t42\t43\tNone\n'), WalFileInfo.from_xlogdb_line( '000000000000000000000002\t42\t43\tgzip\n'), WalFileInfo.from_xlogdb_line( '000000000000000000000003\t42\t43\tbzip2\n'), ) executor._xlog_copy(required_wals, dest.strpath, None) # Check for a correct invocation of rsync using local paths rsync_pg_mock.assert_called_once_with(network_compression=False, bwlimit=None, path=None, ssh=None) assert not rsync_pg_mock.return_value.from_file_list.called c['gzip'].decompress.assert_called_once_with(xlog_gz.strpath, mock.ANY) c['bzip2'].decompress.assert_called_once_with(xlog_bz2.strpath, mock.ANY) # Reset mock calls rsync_pg_mock.reset_mock() c['gzip'].reset_mock() c['bzip2'].reset_mock() # Test: remote copy executor._xlog_copy(required_wals, dest.strpath, 'remote_command') # Check for the invocation of rsync on a remote call rsync_pg_mock.assert_called_once_with(network_compression=False, bwlimit=None, path=mock.ANY, ssh='remote_command') rsync_pg_mock.return_value.from_file_list.assert_called_once_with([ '000000000000000000000001', '000000000000000000000002', '000000000000000000000003' ], mock.ANY, mock.ANY) c['gzip'].decompress.assert_called_once_with(xlog_gz.strpath, mock.ANY) c['bzip2'].decompress.assert_called_once_with(xlog_bz2.strpath, mock.ANY)