Fix for database "restore" action not actually restore anything (#738).

This commit is contained in:
Dan Helfman 2023-08-14 12:43:21 -07:00
parent 6dca7c1c15
commit cd51e9c1ea
17 changed files with 421 additions and 380 deletions

View file

@ -13,7 +13,6 @@ services:
environment: environment:
POSTGRES_PASSWORD: test2 POSTGRES_PASSWORD: test2
POSTGRES_DB: test POSTGRES_DB: test
POSTGRES_USER: postgres2
commands: commands:
- docker-entrypoint.sh -p 5433 - docker-entrypoint.sh -p 5433
- name: mariadb - name: mariadb
@ -28,6 +27,18 @@ services:
MARIADB_DATABASE: test MARIADB_DATABASE: test
commands: commands:
- docker-entrypoint.sh --port=3307 - docker-entrypoint.sh --port=3307
- name: not-actually-mysql
image: docker.io/mariadb:10.11.4
environment:
MARIADB_ROOT_PASSWORD: test
MARIADB_DATABASE: test
- name: not-actually-mysql2
image: docker.io/mariadb:10.11.4
environment:
MARIADB_ROOT_PASSWORD: test2
MARIADB_DATABASE: test
commands:
- docker-entrypoint.sh --port=3307
- name: mongodb - name: mongodb
image: docker.io/mongo:5.0.5 image: docker.io/mongo:5.0.5
environment: environment:

3
NEWS
View file

@ -4,6 +4,9 @@
* #727: Add a MariaDB database hook that uses native MariaDB commands instead of the deprecated * #727: Add a MariaDB database hook that uses native MariaDB commands instead of the deprecated
MySQL ones. Be aware though that any existing backups made with the "mysql_databases:" hook are MySQL ones. Be aware though that any existing backups made with the "mysql_databases:" hook are
only restorable with a "mysql_databases:" configuration. only restorable with a "mysql_databases:" configuration.
* #738: Fix for potential data loss (data not getting restored) in which the database "restore"
action didn't actually restore anything and indicated success anyway.
* Remove the deprecated use of the MongoDB hook's "--db" flag for database restoration.
* Add source code reference documentation for getting oriented with the borgmatic code as a * Add source code reference documentation for getting oriented with the borgmatic code as a
developer: https://torsion.org/borgmatic/docs/reference/source-code/ developer: https://torsion.org/borgmatic/docs/reference/source-code/

View file

@ -27,7 +27,8 @@ def get_configured_database(
hooks for the named database. If a configuration database name is given, use that instead of the hooks for the named database. If a configuration database name is given, use that instead of the
database name to lookup the database in the given hooks configuration. database name to lookup the database in the given hooks configuration.
Return the found database as a tuple of (found hook name, database configuration dict). Return the found database as a tuple of (found hook name, database configuration dict) or (None,
None) if not found.
''' '''
if not configuration_database_name: if not configuration_database_name:
configuration_database_name = database_name configuration_database_name = database_name
@ -39,7 +40,10 @@ def get_configured_database(
if hook_name in borgmatic.hooks.dump.DATABASE_HOOK_NAMES if hook_name in borgmatic.hooks.dump.DATABASE_HOOK_NAMES
} }
else: else:
try:
hooks_to_search = {hook_name: config[hook_name]} hooks_to_search = {hook_name: config[hook_name]}
except KeyError:
return (None, None)
return next( return next(
( (
@ -73,9 +77,9 @@ def restore_single_database(
connection_params, connection_params,
): # pragma: no cover ): # pragma: no cover
''' '''
Given (among other things) an archive name, a database hook name, the hostname, Given (among other things) an archive name, a database hook name, the hostname, port,
port, username and password as connection params, and a configured database username/password as connection params, and a configured database configuration dict, restore
configuration dict, restore that database from the archive. that database from the archive.
''' '''
logger.info( logger.info(
f'{repository.get("label", repository["path"])}: Restoring database {database["name"]}' f'{repository.get("label", repository["path"])}: Restoring database {database["name"]}'
@ -108,14 +112,14 @@ def restore_single_database(
# Run a single database restore, consuming the extract stdout (if any). # Run a single database restore, consuming the extract stdout (if any).
borgmatic.hooks.dispatch.call_hooks( borgmatic.hooks.dispatch.call_hooks(
'restore_database_dump', function_name='restore_database_dump',
config, config=config,
repository['path'], log_prefix=repository['path'],
database['name'], hook_names=[hook_name],
borgmatic.hooks.dump.DATABASE_HOOK_NAMES, database=database,
global_arguments.dry_run, dry_run=global_arguments.dry_run,
extract_process, extract_process=extract_process,
connection_params, connection_params=connection_params,
) )
@ -333,7 +337,7 @@ def run_restore(
connection_params, connection_params,
) )
# For any database that weren't found via exact matches in the configuration, try to fallback # For any databases that weren't found via exact matches in the configuration, try to fallback
# to "all" entries. # to "all" entries.
for hook_name, database_names in remaining_restore_names.items(): for hook_name, database_names in remaining_restore_names.items():
for database_name in database_names: for database_name in database_names:

View file

@ -184,28 +184,16 @@ def make_database_dump_pattern(databases, config, log_prefix, name=None): # pra
def restore_database_dump( def restore_database_dump(
databases_config, config, log_prefix, database_name, dry_run, extract_process, connection_params hook_config, config, log_prefix, database, dry_run, extract_process, connection_params
): ):
''' '''
Restore the given MariaDB database from an extract stream. The databases are supplied as a Restore a database from the given extract stream. The database is supplied as a configuration
sequence containing one dict describing each database (as per the configuration schema), but dict, but the given hook configuration is ignored. The given configuration dict is used to
only the database corresponding to the given database name is restored. Use the given log prefix construct the destination path, and the given log prefix is used for any log entries. If this is
in any log entries. If this is a dry run, then don't actually restore anything. Trigger the a dry run, then don't actually restore anything. Trigger the given active extract process (an
given active extract process (an instance of subprocess.Popen) to produce output to consume. instance of subprocess.Popen) to produce output to consume.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
try:
database = next(
database_config
for database_config in databases_config
if database_config.get('name') == database_name
)
except StopIteration:
raise ValueError(
f'A database named "{database_name}" could not be found in the configuration'
)
hostname = connection_params['hostname'] or database.get( hostname = connection_params['hostname'] or database.get(
'restore_hostname', database.get('hostname') 'restore_hostname', database.get('hostname')
) )

View file

@ -97,32 +97,19 @@ def make_database_dump_pattern(databases, config, log_prefix, name=None): # pra
def restore_database_dump( def restore_database_dump(
databases_config, config, log_prefix, database_name, dry_run, extract_process, connection_params hook_config, config, log_prefix, database, dry_run, extract_process, connection_params
): ):
''' '''
Restore the given MongoDB database from an extract stream. The databases are supplied as a Restore a database from the given extract stream. The database is supplied as a configuration
sequence containing one dict describing each database (as per the configuration schema), but dict, but the given hook configuration is ignored. The given configuration dict is used to
only the database corresponding to the given database name is restored. Use the configuration construct the destination path, and the given log prefix is used for any log entries. If this is
dict to construct the destination path and the given log prefix in any log entries. If this is a a dry run, then don't actually restore anything. Trigger the given active extract process (an
dry run, then don't actually restore anything. Trigger the given active extract process (an
instance of subprocess.Popen) to produce output to consume. instance of subprocess.Popen) to produce output to consume.
If the extract process is None, then restore the dump from the filesystem rather than from an If the extract process is None, then restore the dump from the filesystem rather than from an
extract stream. extract stream.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
try:
database = next(
database_config
for database_config in databases_config
if database_config.get('name') == database_name
)
except StopIteration:
raise ValueError(
f'A database named "{database_name}" could not be found in the configuration'
)
dump_filename = dump.make_database_dump_filename( dump_filename = dump.make_database_dump_filename(
make_dump_path(config), database['name'], database.get('hostname') make_dump_path(config), database['name'], database.get('hostname')
) )
@ -165,7 +152,7 @@ def build_restore_command(extract_process, database, dump_filename, connection_p
else: else:
command.extend(('--dir', dump_filename)) command.extend(('--dir', dump_filename))
if database['name'] != 'all': if database['name'] != 'all':
command.extend(('--drop', '--db', database['name'])) command.extend(('--drop',))
if hostname: if hostname:
command.extend(('--host', hostname)) command.extend(('--host', hostname))
if port: if port:
@ -178,7 +165,8 @@ def build_restore_command(extract_process, database, dump_filename, connection_p
command.extend(('--authenticationDatabase', database['authentication_database'])) command.extend(('--authenticationDatabase', database['authentication_database']))
if 'restore_options' in database: if 'restore_options' in database:
command.extend(database['restore_options'].split(' ')) command.extend(database['restore_options'].split(' '))
if database['schemas']: if database.get('schemas'):
for schema in database['schemas']: for schema in database['schemas']:
command.extend(('--nsInclude', schema)) command.extend(('--nsInclude', schema))
return command return command

View file

@ -181,28 +181,16 @@ def make_database_dump_pattern(databases, config, log_prefix, name=None): # pra
def restore_database_dump( def restore_database_dump(
databases_config, config, log_prefix, database_name, dry_run, extract_process, connection_params hook_config, config, log_prefix, database, dry_run, extract_process, connection_params
): ):
''' '''
Restore the given MySQL/MariaDB database from an extract stream. The databases are supplied as a Restore a database from the given extract stream. The database is supplied as a configuration
sequence containing one dict describing each database (as per the configuration schema), but dict, but the given hook configuration is ignored. The given configuration dict is used to
only the database corresponding to the given database name is restored. Use the given log construct the destination path, and the given log prefix is used for any log entries. If this is
prefix in any log entries. If this is a dry run, then don't actually restore anything. Trigger a dry run, then don't actually restore anything. Trigger the given active extract process (an
the given active extract process (an instance of subprocess.Popen) to produce output to consume. instance of subprocess.Popen) to produce output to consume.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
try:
database = next(
database_config
for database_config in databases_config
if database_config.get('name') == database_name
)
except StopIteration:
raise ValueError(
f'A database named "{database_name}" could not be found in the configuration'
)
hostname = connection_params['hostname'] or database.get( hostname = connection_params['hostname'] or database.get(
'restore_hostname', database.get('hostname') 'restore_hostname', database.get('hostname')
) )

View file

@ -202,15 +202,14 @@ def make_database_dump_pattern(databases, config, log_prefix, name=None): # pra
def restore_database_dump( def restore_database_dump(
databases_config, config, log_prefix, database_name, dry_run, extract_process, connection_params hook_config, config, log_prefix, database, dry_run, extract_process, connection_params
): ):
''' '''
Restore the given PostgreSQL database from an extract stream. The databases are supplied as a Restore a database from the given extract stream. The database is supplied as a configuration
sequence containing one dict describing each database (as per the configuration schema), but dict, but the given hook configuration is ignored. The given configuration dict is used to
only the database corresponding to the given database name is restored. Use the given construct the destination path, and the given log prefix is used for any log entries. If this is
configuration dict to construct the destination path and the given log prefix in any log a dry run, then don't actually restore anything. Trigger the given active extract process (an
entries. If this is a dry run, then don't actually restore anything. Trigger the given active instance of subprocess.Popen) to produce output to consume.
extract process (an instance of subprocess.Popen) to produce output to consume.
If the extract process is None, then restore the dump from the filesystem rather than from an If the extract process is None, then restore the dump from the filesystem rather than from an
extract stream. extract stream.
@ -219,18 +218,6 @@ def restore_database_dump(
hostname, port, username, and password. hostname, port, username, and password.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
try:
database = next(
database_config
for database_config in databases_config
if database_config.get('name') == database_name
)
except StopIteration:
raise ValueError(
f'A database named "{database_name}" could not be found in the configuration'
)
hostname = connection_params['hostname'] or database.get( hostname = connection_params['hostname'] or database.get(
'restore_hostname', database.get('hostname') 'restore_hostname', database.get('hostname')
) )

View file

@ -32,10 +32,10 @@ def dump_databases(databases, config, log_prefix, dry_run):
database_path = database['path'] database_path = database['path']
if database['name'] == 'all': if database['name'] == 'all':
logger.warning('The "all" database name has no meaning for SQLite3 databases') logger.warning('The "all" database name has no meaning for SQLite databases')
if not os.path.exists(database_path): if not os.path.exists(database_path):
logger.warning( logger.warning(
f'{log_prefix}: No SQLite database at {database_path}; An empty database will be created and dumped' f'{log_prefix}: No SQLite database at {database_path}; an empty database will be created and dumped'
) )
dump_path = make_dump_path(config) dump_path = make_dump_path(config)
@ -84,28 +84,16 @@ def make_database_dump_pattern(databases, config, log_prefix, name=None): # pra
def restore_database_dump( def restore_database_dump(
databases_config, config, log_prefix, database_name, dry_run, extract_process, connection_params hook_config, config, log_prefix, database, dry_run, extract_process, connection_params
): ):
''' '''
Restore the given SQLite3 database from an extract stream. The databases are supplied as a Restore a database from the given extract stream. The database is supplied as a configuration
sequence containing one dict describing each database (as per the configuration schema), but dict, but the given hook configuration is ignored. The given configuration dict is used to
only the database corresponding to the given database name is restored. Use the given log prefix construct the destination path, and the given log prefix is used for any log entries. If this is
in any log entries. If this is a dry run, then don't actually restore anything. Trigger the a dry run, then don't actually restore anything. Trigger the given active extract process (an
given active extract process (an instance of subprocess.Popen) to produce output to consume. instance of subprocess.Popen) to produce output to consume.
''' '''
dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else '' dry_run_label = ' (dry run; not actually restoring anything)' if dry_run else ''
try:
database = next(
database_config
for database_config in databases_config
if database_config.get('name') == database_name
)
except StopIteration:
raise ValueError(
f'A database named "{database_name}" could not be found in the configuration'
)
database_path = connection_params['restore_path'] or database.get( database_path = connection_params['restore_path'] or database.get(
'restore_path', database.get('path') 'restore_path', database.get('path')
) )

View file

@ -21,7 +21,7 @@ apk add --no-cache python3 py3-pip borgbackup postgresql-client mariadb-client m
py3-ruamel.yaml py3-ruamel.yaml.clib bash sqlite fish py3-ruamel.yaml py3-ruamel.yaml.clib bash sqlite fish
# If certain dependencies of black are available in this version of Alpine, install them. # If certain dependencies of black are available in this version of Alpine, install them.
apk add --no-cache py3-typed-ast py3-regex || true apk add --no-cache py3-typed-ast py3-regex || true
python3 -m pip install --no-cache --upgrade pip==22.2.2 setuptools==64.0.1 python3 -m pip install --no-cache --upgrade pip==22.2.2 setuptools==64.0.1 pymongo==4.4.1
pip3 install --ignore-installed tox==3.25.1 pip3 install --ignore-installed tox==3.25.1
export COVERAGE_FILE=/tmp/.coverage export COVERAGE_FILE=/tmp/.coverage

View file

@ -10,7 +10,6 @@ services:
environment: environment:
POSTGRES_PASSWORD: test2 POSTGRES_PASSWORD: test2
POSTGRES_DB: test POSTGRES_DB: test
POSTGRES_USER: postgres2
command: docker-entrypoint.sh -p 5433 command: docker-entrypoint.sh -p 5433
mariadb: mariadb:
image: docker.io/mariadb:10.11.4 image: docker.io/mariadb:10.11.4
@ -23,6 +22,17 @@ services:
MARIADB_ROOT_PASSWORD: test2 MARIADB_ROOT_PASSWORD: test2
MARIADB_DATABASE: test MARIADB_DATABASE: test
command: docker-entrypoint.sh --port=3307 command: docker-entrypoint.sh --port=3307
not-actually-mysql:
image: docker.io/mariadb:10.11.4
environment:
MARIADB_ROOT_PASSWORD: test
MARIADB_DATABASE: test
not-actually-mysql2:
image: docker.io/mariadb:10.11.4
environment:
MARIADB_ROOT_PASSWORD: test2
MARIADB_DATABASE: test
command: docker-entrypoint.sh --port=3307
mongodb: mongodb:
image: docker.io/mongo:5.0.5 image: docker.io/mongo:5.0.5
environment: environment:

View file

@ -5,7 +5,9 @@ import subprocess
import sys import sys
import tempfile import tempfile
import pymongo
import pytest import pytest
import ruamel.yaml
def write_configuration( def write_configuration(
@ -21,7 +23,7 @@ def write_configuration(
for testing. This includes injecting the given repository path, borgmatic source directory for for testing. This includes injecting the given repository path, borgmatic source directory for
storing database dumps, dump format (for PostgreSQL), and encryption passphrase. storing database dumps, dump format (for PostgreSQL), and encryption passphrase.
''' '''
config = f''' config_yaml = f'''
source_directories: source_directories:
- {source_directory} - {source_directory}
repositories: repositories:
@ -61,16 +63,16 @@ mariadb_databases:
password: test password: test
mysql_databases: mysql_databases:
- name: test - name: test
hostname: mariadb hostname: not-actually-mysql
username: root username: root
password: test password: test
- name: all - name: all
hostname: mariadb hostname: not-actually-mysql
username: root username: root
password: test password: test
- name: all - name: all
format: sql format: sql
hostname: mariadb hostname: not-actually-mysql
username: root username: root
password: test password: test
mongodb_databases: mongodb_databases:
@ -90,7 +92,9 @@ sqlite_databases:
''' '''
with open(config_path, 'w') as config_file: with open(config_path, 'w') as config_file:
config_file.write(config) config_file.write(config_yaml)
return ruamel.yaml.YAML(typ='safe').load(config_yaml)
def write_custom_restore_configuration( def write_custom_restore_configuration(
@ -106,7 +110,7 @@ def write_custom_restore_configuration(
for testing with custom restore options. This includes a custom restore_hostname, restore_port, for testing with custom restore options. This includes a custom restore_hostname, restore_port,
restore_username, restore_password and restore_path. restore_username, restore_password and restore_path.
''' '''
config = f''' config_yaml = f'''
source_directories: source_directories:
- {source_directory} - {source_directory}
repositories: repositories:
@ -123,7 +127,6 @@ postgresql_databases:
format: {postgresql_dump_format} format: {postgresql_dump_format}
restore_hostname: postgresql2 restore_hostname: postgresql2
restore_port: 5433 restore_port: 5433
restore_username: postgres2
restore_password: test2 restore_password: test2
mariadb_databases: mariadb_databases:
- name: test - name: test
@ -136,10 +139,10 @@ mariadb_databases:
restore_password: test2 restore_password: test2
mysql_databases: mysql_databases:
- name: test - name: test
hostname: mariadb hostname: not-actually-mysql
username: root username: root
password: test password: test
restore_hostname: mariadb2 restore_hostname: not-actually-mysql2
restore_port: 3307 restore_port: 3307
restore_username: root restore_username: root
restore_password: test2 restore_password: test2
@ -161,7 +164,9 @@ sqlite_databases:
''' '''
with open(config_path, 'w') as config_file: with open(config_path, 'w') as config_file:
config_file.write(config) config_file.write(config_yaml)
return ruamel.yaml.YAML(typ='safe').load(config_yaml)
def write_simple_custom_restore_configuration( def write_simple_custom_restore_configuration(
@ -177,7 +182,7 @@ def write_simple_custom_restore_configuration(
custom restore_hostname, restore_port, restore_username and restore_password as we only test custom restore_hostname, restore_port, restore_username and restore_password as we only test
these options for PostgreSQL. these options for PostgreSQL.
''' '''
config = f''' config_yaml = f'''
source_directories: source_directories:
- {source_directory} - {source_directory}
repositories: repositories:
@ -195,7 +200,147 @@ postgresql_databases:
''' '''
with open(config_path, 'w') as config_file: with open(config_path, 'w') as config_file:
config_file.write(config) config_file.write(config_yaml)
return ruamel.yaml.YAML(typ='safe').load(config_yaml)
def get_connection_params(database, use_restore_options=False):
hostname = (database.get('restore_hostname') if use_restore_options else None) or database.get(
'hostname'
)
port = (database.get('restore_port') if use_restore_options else None) or database.get('port')
username = (database.get('restore_username') if use_restore_options else None) or database.get(
'username'
)
password = (database.get('restore_password') if use_restore_options else None) or database.get(
'password'
)
return (hostname, port, username, password)
def run_postgresql_command(command, config, use_restore_options=False):
(hostname, port, username, password) = get_connection_params(
config['postgresql_databases'][0], use_restore_options
)
subprocess.check_call(
[
'/usr/bin/psql',
f'--host={hostname}',
f'--port={port or 5432}',
f"--username={username or 'root'}",
f'--command={command}',
'test',
],
env={'PGPASSWORD': password},
)
def run_mariadb_command(command, config, use_restore_options=False, binary_name='mariadb'):
(hostname, port, username, password) = get_connection_params(
config[f'{binary_name}_databases'][0], use_restore_options
)
subprocess.check_call(
[
f'/usr/bin/{binary_name}',
f'--host={hostname}',
f'--port={port or 3306}',
f'--user={username}',
f'--execute={command}',
'test',
],
env={'MYSQL_PWD': password},
)
def get_mongodb_database_client(config, use_restore_options=False):
(hostname, port, username, password) = get_connection_params(
config['mongodb_databases'][0], use_restore_options
)
return pymongo.MongoClient(f'mongodb://{username}:{password}@{hostname}:{port or 27017}').test
def run_sqlite_command(command, config, use_restore_options=False):
database = config['sqlite_databases'][0]
path = (database.get('restore_path') if use_restore_options else None) or database.get('path')
subprocess.check_call(
[
'/usr/bin/sqlite3',
path,
command,
'.exit',
],
)
DEFAULT_HOOK_NAMES = {'postgresql', 'mariadb', 'mysql', 'mongodb', 'sqlite'}
def create_test_tables(config, use_restore_options=False):
'''
Create test tables for borgmatic to dump and backup.
'''
command = 'create table test{id} (thing int); insert into test{id} values (1);'
if 'postgresql_databases' in config:
run_postgresql_command(command.format(id=1), config, use_restore_options)
if 'mariadb_databases' in config:
run_mariadb_command(command.format(id=2), config, use_restore_options)
if 'mysql_databases' in config:
run_mariadb_command(command.format(id=3), config, use_restore_options, binary_name='mysql')
if 'mongodb_databases' in config:
get_mongodb_database_client(config, use_restore_options)['test4'].insert_one({'thing': 1})
if 'sqlite_databases' in config:
run_sqlite_command(command.format(id=5), config, use_restore_options)
def drop_test_tables(config, use_restore_options=False):
'''
Drop the test tables in preparation for borgmatic restoring them.
'''
command = 'drop table if exists test{id};'
if 'postgresql_databases' in config:
run_postgresql_command(command.format(id=1), config, use_restore_options)
if 'mariadb_databases' in config:
run_mariadb_command(command.format(id=2), config, use_restore_options)
if 'mysql_databases' in config:
run_mariadb_command(command.format(id=3), config, use_restore_options, binary_name='mysql')
if 'mongodb_databases' in config:
get_mongodb_database_client(config, use_restore_options)['test4'].drop()
if 'sqlite_databases' in config:
run_sqlite_command(command.format(id=5), config, use_restore_options)
def select_test_tables(config, use_restore_options=False):
'''
Select the test tables to make sure they exist.
Raise if the expected tables cannot be selected, for instance if a restore hasn't worked as
expected.
'''
command = 'select count(*) from test{id};'
if 'postgresql_databases' in config:
run_postgresql_command(command.format(id=1), config, use_restore_options)
if 'mariadb_databases' in config:
run_mariadb_command(command.format(id=2), config, use_restore_options)
if 'mysql_databases' in config:
run_mariadb_command(command.format(id=3), config, use_restore_options, binary_name='mysql')
if 'mongodb_databases' in config:
assert (
get_mongodb_database_client(config, use_restore_options)['test4'].count_documents(
filter={}
)
> 0
)
if 'sqlite_databases' in config:
run_sqlite_command(command.format(id=5), config, use_restore_options)
def test_database_dump_and_restore(): def test_database_dump_and_restore():
@ -211,15 +356,17 @@ def test_database_dump_and_restore():
try: try:
config_path = os.path.join(temporary_directory, 'test.yaml') config_path = os.path.join(temporary_directory, 'test.yaml')
write_configuration( config = write_configuration(
temporary_directory, config_path, repository_path, borgmatic_source_directory temporary_directory, config_path, repository_path, borgmatic_source_directory
) )
create_test_tables(config)
select_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey'] ['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey']
) )
# Run borgmatic to generate a backup archive including a database dump. # Run borgmatic to generate a backup archive including database dumps.
subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2']) subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2'])
# Get the created archive name. # Get the created archive name.
@ -232,16 +379,21 @@ def test_database_dump_and_restore():
assert len(parsed_output[0]['archives']) == 1 assert len(parsed_output[0]['archives']) == 1
archive_name = parsed_output[0]['archives'][0]['archive'] archive_name = parsed_output[0]['archives'][0]['archive']
# Restore the database from the archive. # Restore the databases from the archive.
drop_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'restore', '--archive', archive_name] ['borgmatic', '-v', '2', '--config', config_path, 'restore', '--archive', archive_name]
) )
# Ensure the test tables have actually been restored.
select_test_tables(config)
finally: finally:
os.chdir(original_working_directory) os.chdir(original_working_directory)
shutil.rmtree(temporary_directory) shutil.rmtree(temporary_directory)
drop_test_tables(config)
def test_database_dump_and_restore_with_restore_cli_arguments(): def test_database_dump_and_restore_with_restore_cli_flags():
# Create a Borg repository. # Create a Borg repository.
temporary_directory = tempfile.mkdtemp() temporary_directory = tempfile.mkdtemp()
repository_path = os.path.join(temporary_directory, 'test.borg') repository_path = os.path.join(temporary_directory, 'test.borg')
@ -251,9 +403,11 @@ def test_database_dump_and_restore_with_restore_cli_arguments():
try: try:
config_path = os.path.join(temporary_directory, 'test.yaml') config_path = os.path.join(temporary_directory, 'test.yaml')
write_simple_custom_restore_configuration( config = write_simple_custom_restore_configuration(
temporary_directory, config_path, repository_path, borgmatic_source_directory temporary_directory, config_path, repository_path, borgmatic_source_directory
) )
create_test_tables(config)
select_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey'] ['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey']
@ -273,6 +427,7 @@ def test_database_dump_and_restore_with_restore_cli_arguments():
archive_name = parsed_output[0]['archives'][0]['archive'] archive_name = parsed_output[0]['archives'][0]['archive']
# Restore the database from the archive. # Restore the database from the archive.
drop_test_tables(config)
subprocess.check_call( subprocess.check_call(
[ [
'borgmatic', 'borgmatic',
@ -287,15 +442,25 @@ def test_database_dump_and_restore_with_restore_cli_arguments():
'postgresql2', 'postgresql2',
'--port', '--port',
'5433', '5433',
'--username',
'postgres2',
'--password', '--password',
'test2', 'test2',
] ]
) )
# Ensure the test tables have actually been restored. But first modify the config to contain
# the altered restore values from the borgmatic command above. This ensures that the test
# tables are selected from the correct database.
database = config['postgresql_databases'][0]
database['restore_hostname'] = 'postgresql2'
database['restore_port'] = '5433'
database['restore_password'] = 'test2'
select_test_tables(config, use_restore_options=True)
finally: finally:
os.chdir(original_working_directory) os.chdir(original_working_directory)
shutil.rmtree(temporary_directory) shutil.rmtree(temporary_directory)
drop_test_tables(config)
drop_test_tables(config, use_restore_options=True)
def test_database_dump_and_restore_with_restore_configuration_options(): def test_database_dump_and_restore_with_restore_configuration_options():
@ -308,9 +473,11 @@ def test_database_dump_and_restore_with_restore_configuration_options():
try: try:
config_path = os.path.join(temporary_directory, 'test.yaml') config_path = os.path.join(temporary_directory, 'test.yaml')
write_custom_restore_configuration( config = write_custom_restore_configuration(
temporary_directory, config_path, repository_path, borgmatic_source_directory temporary_directory, config_path, repository_path, borgmatic_source_directory
) )
create_test_tables(config)
select_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey'] ['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey']
@ -330,12 +497,18 @@ def test_database_dump_and_restore_with_restore_configuration_options():
archive_name = parsed_output[0]['archives'][0]['archive'] archive_name = parsed_output[0]['archives'][0]['archive']
# Restore the database from the archive. # Restore the database from the archive.
drop_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'restore', '--archive', archive_name] ['borgmatic', '-v', '2', '--config', config_path, 'restore', '--archive', archive_name]
) )
# Ensure the test tables have actually been restored.
select_test_tables(config, use_restore_options=True)
finally: finally:
os.chdir(original_working_directory) os.chdir(original_working_directory)
shutil.rmtree(temporary_directory) shutil.rmtree(temporary_directory)
drop_test_tables(config)
drop_test_tables(config, use_restore_options=True)
def test_database_dump_and_restore_with_directory_format(): def test_database_dump_and_restore_with_directory_format():
@ -348,7 +521,7 @@ def test_database_dump_and_restore_with_directory_format():
try: try:
config_path = os.path.join(temporary_directory, 'test.yaml') config_path = os.path.join(temporary_directory, 'test.yaml')
write_configuration( config = write_configuration(
temporary_directory, temporary_directory,
config_path, config_path,
repository_path, repository_path,
@ -356,6 +529,8 @@ def test_database_dump_and_restore_with_directory_format():
postgresql_dump_format='directory', postgresql_dump_format='directory',
mongodb_dump_format='directory', mongodb_dump_format='directory',
) )
create_test_tables(config)
select_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey'] ['borgmatic', '-v', '2', '--config', config_path, 'rcreate', '--encryption', 'repokey']
@ -365,12 +540,17 @@ def test_database_dump_and_restore_with_directory_format():
subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2']) subprocess.check_call(['borgmatic', 'create', '--config', config_path, '-v', '2'])
# Restore the database from the archive. # Restore the database from the archive.
drop_test_tables(config)
subprocess.check_call( subprocess.check_call(
['borgmatic', '--config', config_path, 'restore', '--archive', 'latest'] ['borgmatic', '--config', config_path, 'restore', '--archive', 'latest']
) )
# Ensure the test tables have actually been restored.
select_test_tables(config)
finally: finally:
os.chdir(original_working_directory) os.chdir(original_working_directory)
shutil.rmtree(temporary_directory) shutil.rmtree(temporary_directory)
drop_test_tables(config)
def test_database_dump_with_error_causes_borgmatic_to_exit(): def test_database_dump_with_error_causes_borgmatic_to_exit():

View file

@ -16,6 +16,15 @@ def test_get_configured_database_matches_database_by_name():
) == ('postgresql_databases', {'name': 'bar'}) ) == ('postgresql_databases', {'name': 'bar'})
def test_get_configured_database_matches_nothing_when_nothing_configured():
assert module.get_configured_database(
config={},
archive_database_names={'postgresql_databases': ['foo']},
hook_name='postgresql_databases',
database_name='quux',
) == (None, None)
def test_get_configured_database_matches_nothing_when_database_name_not_configured(): def test_get_configured_database_matches_nothing_when_database_name_not_configured():
assert module.get_configured_database( assert module.get_configured_database(
config={'postgresql_databases': [{'name': 'foo'}, {'name': 'bar'}]}, config={'postgresql_databases': [{'name': 'foo'}, {'name': 'bar'}]},

View file

@ -380,7 +380,7 @@ def test_dump_databases_does_not_error_for_missing_all_databases_with_dry_run():
def test_restore_database_dump_runs_mariadb_to_restore(): def test_restore_database_dump_runs_mariadb_to_restore():
databases_config = [{'name': 'foo'}, {'name': 'bar'}] hook_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -392,33 +392,10 @@ def test_restore_database_dump_runs_mariadb_to_restore():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False,
extract_process=extract_process,
connection_params={
'hostname': None,
'port': None,
'username': None,
'password': None,
},
)
def test_restore_database_dump_errors_when_database_missing_from_configuration():
databases_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').never()
with pytest.raises(ValueError):
module.restore_database_dump(
databases_config,
{},
'test.yaml',
database_name='other',
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -431,7 +408,7 @@ def test_restore_database_dump_errors_when_database_missing_from_configuration()
def test_restore_database_dump_runs_mariadb_with_options(): def test_restore_database_dump_runs_mariadb_with_options():
databases_config = [{'name': 'foo', 'restore_options': '--harder'}] hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -443,10 +420,10 @@ def test_restore_database_dump_runs_mariadb_with_options():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -459,7 +436,7 @@ def test_restore_database_dump_runs_mariadb_with_options():
def test_restore_database_dump_runs_mariadb_with_hostname_and_port(): def test_restore_database_dump_runs_mariadb_with_hostname_and_port():
databases_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}] hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -480,10 +457,10 @@ def test_restore_database_dump_runs_mariadb_with_hostname_and_port():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -496,7 +473,7 @@ def test_restore_database_dump_runs_mariadb_with_hostname_and_port():
def test_restore_database_dump_runs_mariadb_with_username_and_password(): def test_restore_database_dump_runs_mariadb_with_username_and_password():
databases_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}] hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -508,10 +485,10 @@ def test_restore_database_dump_runs_mariadb_with_username_and_password():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -524,7 +501,7 @@ def test_restore_database_dump_runs_mariadb_with_username_and_password():
def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore(): def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'root', 'username': 'root',
@ -557,10 +534,10 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -573,7 +550,7 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore(): def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'root', 'username': 'root',
@ -608,10 +585,10 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -624,15 +601,15 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
def test_restore_database_dump_with_dry_run_skips_restore(): def test_restore_database_dump_with_dry_run_skips_restore():
databases_config = [{'name': 'foo'}] hook_config = [{'name': 'foo'}]
flexmock(module).should_receive('execute_command_with_processes').never() flexmock(module).should_receive('execute_command_with_processes').never()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=True, dry_run=True,
extract_process=flexmock(), extract_process=flexmock(),
connection_params={ connection_params={

View file

@ -1,6 +1,5 @@
import logging import logging
import pytest
from flexmock import flexmock from flexmock import flexmock
from borgmatic.hooks import mongodb as module from borgmatic.hooks import mongodb as module
@ -131,7 +130,15 @@ def test_dump_databases_runs_mongodump_with_options():
flexmock(module.dump).should_receive('create_named_pipe_for_dump') flexmock(module.dump).should_receive('create_named_pipe_for_dump')
flexmock(module).should_receive('execute_command').with_args( flexmock(module).should_receive('execute_command').with_args(
('mongodump', '--db', 'foo', '--stuff=such', '--archive', '>', 'databases/localhost/foo'), (
'mongodump',
'--db',
'foo',
'--stuff=such',
'--archive',
'>',
'databases/localhost/foo',
),
shell=True, shell=True,
run_to_completion=False, run_to_completion=False,
).and_return(process).once() ).and_return(process).once()
@ -158,23 +165,23 @@ def test_dump_databases_runs_mongodumpall_for_all_databases():
def test_restore_database_dump_runs_mongorestore(): def test_restore_database_dump_runs_mongorestore():
databases_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}] hook_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_database_dump_filename') flexmock(module.dump).should_receive('make_database_dump_filename')
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
['mongorestore', '--archive', '--drop', '--db', 'foo'], ['mongorestore', '--archive', '--drop'],
processes=[extract_process], processes=[extract_process],
output_log_level=logging.DEBUG, output_log_level=logging.DEBUG,
input_file=extract_process.stdout, input_file=extract_process.stdout,
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -186,33 +193,8 @@ def test_restore_database_dump_runs_mongorestore():
) )
def test_restore_database_dump_errors_on_empty_databases_config():
databases_config = []
flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_database_dump_filename')
flexmock(module).should_receive('execute_command_with_processes').never()
flexmock(module).should_receive('execute_command').never()
with pytest.raises(ValueError):
module.restore_database_dump(
databases_config,
{},
'test.yaml',
database_name='foo',
dry_run=False,
extract_process=flexmock(),
connection_params={
'hostname': None,
'port': None,
'username': None,
'password': None,
},
)
def test_restore_database_dump_runs_mongorestore_with_hostname_and_port(): def test_restore_database_dump_runs_mongorestore_with_hostname_and_port():
databases_config = [ hook_config = [
{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433, 'schemas': None} {'name': 'foo', 'hostname': 'database.example.org', 'port': 5433, 'schemas': None}
] ]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
@ -224,8 +206,6 @@ def test_restore_database_dump_runs_mongorestore_with_hostname_and_port():
'mongorestore', 'mongorestore',
'--archive', '--archive',
'--drop', '--drop',
'--db',
'foo',
'--host', '--host',
'database.example.org', 'database.example.org',
'--port', '--port',
@ -237,10 +217,10 @@ def test_restore_database_dump_runs_mongorestore_with_hostname_and_port():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -253,7 +233,7 @@ def test_restore_database_dump_runs_mongorestore_with_hostname_and_port():
def test_restore_database_dump_runs_mongorestore_with_username_and_password(): def test_restore_database_dump_runs_mongorestore_with_username_and_password():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'mongo', 'username': 'mongo',
@ -271,8 +251,6 @@ def test_restore_database_dump_runs_mongorestore_with_username_and_password():
'mongorestore', 'mongorestore',
'--archive', '--archive',
'--drop', '--drop',
'--db',
'foo',
'--username', '--username',
'mongo', 'mongo',
'--password', '--password',
@ -286,10 +264,10 @@ def test_restore_database_dump_runs_mongorestore_with_username_and_password():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -302,7 +280,7 @@ def test_restore_database_dump_runs_mongorestore_with_username_and_password():
def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore(): def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'mongo', 'username': 'mongo',
@ -324,8 +302,6 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
'mongorestore', 'mongorestore',
'--archive', '--archive',
'--drop', '--drop',
'--db',
'foo',
'--host', '--host',
'clihost', 'clihost',
'--port', '--port',
@ -343,10 +319,10 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -359,7 +335,7 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore(): def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'mongo', 'username': 'mongo',
@ -381,8 +357,6 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
'mongorestore', 'mongorestore',
'--archive', '--archive',
'--drop', '--drop',
'--db',
'foo',
'--host', '--host',
'restorehost', 'restorehost',
'--port', '--port',
@ -400,10 +374,10 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -416,23 +390,23 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
def test_restore_database_dump_runs_mongorestore_with_options(): def test_restore_database_dump_runs_mongorestore_with_options():
databases_config = [{'name': 'foo', 'restore_options': '--harder', 'schemas': None}] hook_config = [{'name': 'foo', 'restore_options': '--harder', 'schemas': None}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_database_dump_filename') flexmock(module.dump).should_receive('make_database_dump_filename')
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
['mongorestore', '--archive', '--drop', '--db', 'foo', '--harder'], ['mongorestore', '--archive', '--drop', '--harder'],
processes=[extract_process], processes=[extract_process],
output_log_level=logging.DEBUG, output_log_level=logging.DEBUG,
input_file=extract_process.stdout, input_file=extract_process.stdout,
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -445,7 +419,7 @@ def test_restore_database_dump_runs_mongorestore_with_options():
def test_restore_databases_dump_runs_mongorestore_with_schemas(): def test_restore_databases_dump_runs_mongorestore_with_schemas():
databases_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}] hook_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
@ -455,8 +429,6 @@ def test_restore_databases_dump_runs_mongorestore_with_schemas():
'mongorestore', 'mongorestore',
'--archive', '--archive',
'--drop', '--drop',
'--db',
'foo',
'--nsInclude', '--nsInclude',
'bar', 'bar',
'--nsInclude', '--nsInclude',
@ -468,10 +440,10 @@ def test_restore_databases_dump_runs_mongorestore_with_schemas():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -484,7 +456,7 @@ def test_restore_databases_dump_runs_mongorestore_with_schemas():
def test_restore_database_dump_runs_psql_for_all_database_dump(): def test_restore_database_dump_runs_psql_for_all_database_dump():
databases_config = [{'name': 'all', 'schemas': None}] hook_config = [{'name': 'all', 'schemas': None}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
@ -497,10 +469,10 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='all', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -513,17 +485,17 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
def test_restore_database_dump_with_dry_run_skips_restore(): def test_restore_database_dump_with_dry_run_skips_restore():
databases_config = [{'name': 'foo', 'schemas': None}] hook_config = [{'name': 'foo', 'schemas': None}]
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_database_dump_filename') flexmock(module.dump).should_receive('make_database_dump_filename')
flexmock(module).should_receive('execute_command_with_processes').never() flexmock(module).should_receive('execute_command_with_processes').never()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=True, dry_run=True,
extract_process=flexmock(), extract_process=flexmock(),
connection_params={ connection_params={
@ -536,22 +508,22 @@ def test_restore_database_dump_with_dry_run_skips_restore():
def test_restore_database_dump_without_extract_process_restores_from_disk(): def test_restore_database_dump_without_extract_process_restores_from_disk():
databases_config = [{'name': 'foo', 'format': 'directory', 'schemas': None}] hook_config = [{'name': 'foo', 'format': 'directory', 'schemas': None}]
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
flexmock(module.dump).should_receive('make_database_dump_filename').and_return('/dump/path') flexmock(module.dump).should_receive('make_database_dump_filename').and_return('/dump/path')
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
['mongorestore', '--dir', '/dump/path', '--drop', '--db', 'foo'], ['mongorestore', '--dir', '/dump/path', '--drop'],
processes=[], processes=[],
output_log_level=logging.DEBUG, output_log_level=logging.DEBUG,
input_file=None, input_file=None,
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False, dry_run=False,
extract_process=None, extract_process=None,
connection_params={ connection_params={

View file

@ -380,7 +380,7 @@ def test_dump_databases_does_not_error_for_missing_all_databases_with_dry_run():
def test_restore_database_dump_runs_mysql_to_restore(): def test_restore_database_dump_runs_mysql_to_restore():
databases_config = [{'name': 'foo'}, {'name': 'bar'}] hook_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -392,33 +392,10 @@ def test_restore_database_dump_runs_mysql_to_restore():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False,
extract_process=extract_process,
connection_params={
'hostname': None,
'port': None,
'username': None,
'password': None,
},
)
def test_restore_database_dump_errors_when_database_missing_from_configuration():
databases_config = [{'name': 'foo'}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').never()
with pytest.raises(ValueError):
module.restore_database_dump(
databases_config,
{},
'test.yaml',
database_name='other',
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -431,7 +408,7 @@ def test_restore_database_dump_errors_when_database_missing_from_configuration()
def test_restore_database_dump_runs_mysql_with_options(): def test_restore_database_dump_runs_mysql_with_options():
databases_config = [{'name': 'foo', 'restore_options': '--harder'}] hook_config = [{'name': 'foo', 'restore_options': '--harder'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -443,10 +420,10 @@ def test_restore_database_dump_runs_mysql_with_options():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -459,7 +436,7 @@ def test_restore_database_dump_runs_mysql_with_options():
def test_restore_database_dump_runs_mysql_with_hostname_and_port(): def test_restore_database_dump_runs_mysql_with_hostname_and_port():
databases_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}] hook_config = [{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -480,10 +457,10 @@ def test_restore_database_dump_runs_mysql_with_hostname_and_port():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -496,7 +473,7 @@ def test_restore_database_dump_runs_mysql_with_hostname_and_port():
def test_restore_database_dump_runs_mysql_with_username_and_password(): def test_restore_database_dump_runs_mysql_with_username_and_password():
databases_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}] hook_config = [{'name': 'foo', 'username': 'root', 'password': 'trustsome1'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -508,10 +485,10 @@ def test_restore_database_dump_runs_mysql_with_username_and_password():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -524,7 +501,7 @@ def test_restore_database_dump_runs_mysql_with_username_and_password():
def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore(): def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'root', 'username': 'root',
@ -557,10 +534,10 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -573,7 +550,7 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore(): def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'username': 'root', 'username': 'root',
@ -608,10 +585,10 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -624,15 +601,15 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
def test_restore_database_dump_with_dry_run_skips_restore(): def test_restore_database_dump_with_dry_run_skips_restore():
databases_config = [{'name': 'foo'}] hook_config = [{'name': 'foo'}]
flexmock(module).should_receive('execute_command_with_processes').never() flexmock(module).should_receive('execute_command_with_processes').never()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=True, dry_run=True,
extract_process=flexmock(), extract_process=flexmock(),
connection_params={ connection_params={

View file

@ -464,7 +464,7 @@ def test_dump_databases_runs_non_default_pg_dump():
def test_restore_database_dump_runs_pg_restore(): def test_restore_database_dump_runs_pg_restore():
databases_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}] hook_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -500,34 +500,10 @@ def test_restore_database_dump_runs_pg_restore():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False,
extract_process=extract_process,
connection_params={
'hostname': None,
'port': None,
'username': None,
'password': None,
},
)
def test_restore_database_dump_errors_when_database_missing_from_configuration():
databases_config = [{'name': 'foo', 'schemas': None}, {'name': 'bar'}]
extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').never()
flexmock(module).should_receive('execute_command').never()
with pytest.raises(ValueError):
module.restore_database_dump(
databases_config,
{},
'test.yaml',
database_name='other',
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -540,7 +516,7 @@ def test_restore_database_dump_errors_when_database_missing_from_configuration()
def test_restore_database_dump_runs_pg_restore_with_hostname_and_port(): def test_restore_database_dump_runs_pg_restore_with_hostname_and_port():
databases_config = [ hook_config = [
{'name': 'foo', 'hostname': 'database.example.org', 'port': 5433, 'schemas': None} {'name': 'foo', 'hostname': 'database.example.org', 'port': 5433, 'schemas': None}
] ]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
@ -586,10 +562,10 @@ def test_restore_database_dump_runs_pg_restore_with_hostname_and_port():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -602,7 +578,7 @@ def test_restore_database_dump_runs_pg_restore_with_hostname_and_port():
def test_restore_database_dump_runs_pg_restore_with_username_and_password(): def test_restore_database_dump_runs_pg_restore_with_username_and_password():
databases_config = [ hook_config = [
{'name': 'foo', 'username': 'postgres', 'password': 'trustsome1', 'schemas': None} {'name': 'foo', 'username': 'postgres', 'password': 'trustsome1', 'schemas': None}
] ]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
@ -646,10 +622,10 @@ def test_restore_database_dump_runs_pg_restore_with_username_and_password():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -662,7 +638,7 @@ def test_restore_database_dump_runs_pg_restore_with_username_and_password():
def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore(): def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'hostname': 'database.example.org', 'hostname': 'database.example.org',
@ -725,10 +701,10 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -741,7 +717,7 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore(): def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'hostname': 'database.example.org', 'hostname': 'database.example.org',
@ -804,10 +780,10 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -820,7 +796,7 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
def test_restore_database_dump_runs_pg_restore_with_options(): def test_restore_database_dump_runs_pg_restore_with_options():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'restore_options': '--harder', 'restore_options': '--harder',
@ -865,10 +841,10 @@ def test_restore_database_dump_runs_pg_restore_with_options():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -881,7 +857,7 @@ def test_restore_database_dump_runs_pg_restore_with_options():
def test_restore_database_dump_runs_psql_for_all_database_dump(): def test_restore_database_dump_runs_psql_for_all_database_dump():
databases_config = [{'name': 'all', 'schemas': None}] hook_config = [{'name': 'all', 'schemas': None}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -904,10 +880,10 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='all', database={'name': 'all'},
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -920,7 +896,7 @@ def test_restore_database_dump_runs_psql_for_all_database_dump():
def test_restore_database_dump_runs_psql_for_plain_database_dump(): def test_restore_database_dump_runs_psql_for_plain_database_dump():
databases_config = [{'name': 'foo', 'format': 'plain', 'schemas': None}] hook_config = [{'name': 'foo', 'format': 'plain', 'schemas': None}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
@ -948,10 +924,10 @@ def test_restore_database_dump_runs_psql_for_plain_database_dump():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -964,7 +940,7 @@ def test_restore_database_dump_runs_psql_for_plain_database_dump():
def test_restore_database_dump_runs_non_default_pg_restore_and_psql(): def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
databases_config = [ hook_config = [
{ {
'name': 'foo', 'name': 'foo',
'pg_restore_command': 'docker exec mycontainer pg_restore', 'pg_restore_command': 'docker exec mycontainer pg_restore',
@ -1013,10 +989,10 @@ def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={ connection_params={
@ -1029,7 +1005,7 @@ def test_restore_database_dump_runs_non_default_pg_restore_and_psql():
def test_restore_database_dump_with_dry_run_skips_restore(): def test_restore_database_dump_with_dry_run_skips_restore():
databases_config = [{'name': 'foo', 'schemas': None}] hook_config = [{'name': 'foo', 'schemas': None}]
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
@ -1037,10 +1013,10 @@ def test_restore_database_dump_with_dry_run_skips_restore():
flexmock(module).should_receive('execute_command_with_processes').never() flexmock(module).should_receive('execute_command_with_processes').never()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=True, dry_run=True,
extract_process=flexmock(), extract_process=flexmock(),
connection_params={ connection_params={
@ -1053,7 +1029,7 @@ def test_restore_database_dump_with_dry_run_skips_restore():
def test_restore_database_dump_without_extract_process_restores_from_disk(): def test_restore_database_dump_without_extract_process_restores_from_disk():
databases_config = [{'name': 'foo', 'schemas': None}] hook_config = [{'name': 'foo', 'schemas': None}]
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
@ -1089,10 +1065,10 @@ def test_restore_database_dump_without_extract_process_restores_from_disk():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database={'name': 'foo'},
dry_run=False, dry_run=False,
extract_process=None, extract_process=None,
connection_params={ connection_params={
@ -1105,7 +1081,7 @@ def test_restore_database_dump_without_extract_process_restores_from_disk():
def test_restore_database_dump_with_schemas_restores_schemas(): def test_restore_database_dump_with_schemas_restores_schemas():
databases_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}] hook_config = [{'name': 'foo', 'schemas': ['bar', 'baz']}]
flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'}) flexmock(module).should_receive('make_extra_environment').and_return({'PGSSLMODE': 'disable'})
flexmock(module).should_receive('make_dump_path') flexmock(module).should_receive('make_dump_path')
@ -1145,10 +1121,10 @@ def test_restore_database_dump_with_schemas_restores_schemas():
).once() ).once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='foo', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=None, extract_process=None,
connection_params={ connection_params={

View file

@ -1,6 +1,5 @@
import logging import logging
import pytest
from flexmock import flexmock from flexmock import flexmock
from borgmatic.hooks import sqlite as module from borgmatic.hooks import sqlite as module
@ -93,7 +92,7 @@ def test_dump_databases_does_not_dump_if_dry_run():
def test_restore_database_dump_restores_database(): def test_restore_database_dump_restores_database():
databases_config = [{'path': '/path/to/database', 'name': 'database'}, {'name': 'other'}] hook_config = [{'path': '/path/to/database', 'name': 'database'}, {'name': 'other'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').with_args( flexmock(module).should_receive('execute_command_with_processes').with_args(
@ -109,10 +108,10 @@ def test_restore_database_dump_restores_database():
flexmock(module.os).should_receive('remove').once() flexmock(module.os).should_receive('remove').once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='database', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={'restore_path': None}, connection_params={'restore_path': None},
@ -120,7 +119,7 @@ def test_restore_database_dump_restores_database():
def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore(): def test_restore_database_dump_with_connection_params_uses_connection_params_for_restore():
databases_config = [ hook_config = [
{'path': '/path/to/database', 'name': 'database', 'restore_path': 'config/path/to/database'} {'path': '/path/to/database', 'name': 'database', 'restore_path': 'config/path/to/database'}
] ]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
@ -138,10 +137,10 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
flexmock(module.os).should_receive('remove').once() flexmock(module.os).should_receive('remove').once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='database', database={'name': 'database'},
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={'restore_path': 'cli/path/to/database'}, connection_params={'restore_path': 'cli/path/to/database'},
@ -149,7 +148,7 @@ def test_restore_database_dump_with_connection_params_uses_connection_params_for
def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore(): def test_restore_database_dump_without_connection_params_uses_restore_params_in_config_for_restore():
databases_config = [ hook_config = [
{'path': '/path/to/database', 'name': 'database', 'restore_path': 'config/path/to/database'} {'path': '/path/to/database', 'name': 'database', 'restore_path': 'config/path/to/database'}
] ]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
@ -167,10 +166,10 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
flexmock(module.os).should_receive('remove').once() flexmock(module.os).should_receive('remove').once()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='database', database=hook_config[0],
dry_run=False, dry_run=False,
extract_process=extract_process, extract_process=extract_process,
connection_params={'restore_path': None}, connection_params={'restore_path': None},
@ -178,34 +177,18 @@ def test_restore_database_dump_without_connection_params_uses_restore_params_in_
def test_restore_database_dump_does_not_restore_database_if_dry_run(): def test_restore_database_dump_does_not_restore_database_if_dry_run():
databases_config = [{'path': '/path/to/database', 'name': 'database'}] hook_config = [{'path': '/path/to/database', 'name': 'database'}]
extract_process = flexmock(stdout=flexmock()) extract_process = flexmock(stdout=flexmock())
flexmock(module).should_receive('execute_command_with_processes').never() flexmock(module).should_receive('execute_command_with_processes').never()
flexmock(module.os).should_receive('remove').never() flexmock(module.os).should_receive('remove').never()
module.restore_database_dump( module.restore_database_dump(
databases_config, hook_config,
{}, {},
'test.yaml', 'test.yaml',
database_name='database', database={'name': 'database'},
dry_run=True, dry_run=True,
extract_process=extract_process, extract_process=extract_process,
connection_params={'restore_path': None}, connection_params={'restore_path': None},
) )
def test_restore_database_dump_raises_error_if_database_config_is_empty():
databases_config = []
extract_process = flexmock(stdout=flexmock())
with pytest.raises(ValueError):
module.restore_database_dump(
databases_config,
{},
'test.yaml',
database_name='database',
dry_run=False,
extract_process=extract_process,
connection_params={'restore_path': None},
)