Support for Borg 2's rcreate and rinfo sub-commands (#557).
This commit is contained in:
parent
22149c6401
commit
622caa0c21
18 changed files with 434 additions and 239 deletions
3
NEWS
3
NEWS
|
@ -1,4 +1,5 @@
|
|||
1.6.7.dev0
|
||||
2.0.0.dev0
|
||||
* #557: Support for Borg 2 while still working with Borg 1.
|
||||
* #565: Fix handling of "repository" and "data" consistency checks to prevent invalid Borg flags.
|
||||
* #566: Modify "mount" and "extract" actions to require the "--repository" flag when multiple
|
||||
repositories are configured.
|
||||
|
|
|
@ -5,7 +5,7 @@ import logging
|
|||
import os
|
||||
import pathlib
|
||||
|
||||
from borgmatic.borg import environment, extract, info, state
|
||||
from borgmatic.borg import environment, extract, rinfo, state
|
||||
from borgmatic.execute import DO_NOT_CAPTURE, execute_command
|
||||
|
||||
DEFAULT_CHECKS = (
|
||||
|
@ -241,6 +241,7 @@ def check_archives(
|
|||
location_config,
|
||||
storage_config,
|
||||
consistency_config,
|
||||
local_borg_version,
|
||||
local_path='borg',
|
||||
remote_path=None,
|
||||
progress=None,
|
||||
|
@ -260,10 +261,11 @@ def check_archives(
|
|||
'''
|
||||
try:
|
||||
borg_repository_id = json.loads(
|
||||
info.display_archives_info(
|
||||
rinfo.display_repository_info(
|
||||
repository,
|
||||
storage_config,
|
||||
argparse.Namespace(json=True, archive=None),
|
||||
local_borg_version,
|
||||
argparse.Namespace(json=True),
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
|
|
|
@ -9,6 +9,10 @@ class Feature(Enum):
|
|||
NOFLAGS = 3
|
||||
NUMERIC_IDS = 4
|
||||
UPLOAD_RATELIMIT = 5
|
||||
SEPARATE_REPOSITORY_ARCHIVE = 6
|
||||
RCREATE = 7
|
||||
RLIST = 8
|
||||
RINFO = 9
|
||||
|
||||
|
||||
FEATURE_TO_MINIMUM_BORG_VERSION = {
|
||||
|
@ -17,6 +21,10 @@ FEATURE_TO_MINIMUM_BORG_VERSION = {
|
|||
Feature.NOFLAGS: parse_version('1.2.0a8'), # borg create --noflags
|
||||
Feature.NUMERIC_IDS: parse_version('1.2.0b3'), # borg create/extract/mount --numeric-ids
|
||||
Feature.UPLOAD_RATELIMIT: parse_version('1.2.0b3'), # borg create --upload-ratelimit
|
||||
Feature.SEPARATE_REPOSITORY_ARCHIVE: parse_version('2.0.0a2'), # --repo with separate archive
|
||||
Feature.RCREATE: parse_version('2.0.0a2'), # borg rcreate
|
||||
Feature.RLIST: parse_version('2.0.0a2'), # borg rlist
|
||||
Feature.RINFO: parse_version('2.0.0a2'), # borg rinfo
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import logging
|
||||
|
||||
from borgmatic.borg import environment
|
||||
from borgmatic.borg import environment, feature
|
||||
from borgmatic.borg.flags import make_flags, make_flags_from_arguments
|
||||
from borgmatic.execute import execute_command
|
||||
|
||||
|
@ -8,12 +8,17 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
|
||||
def display_archives_info(
|
||||
repository, storage_config, info_arguments, local_path='borg', remote_path=None
|
||||
repository,
|
||||
storage_config,
|
||||
local_borg_version,
|
||||
info_arguments,
|
||||
local_path='borg',
|
||||
remote_path=None,
|
||||
):
|
||||
'''
|
||||
Given a local or remote repository path, a storage config dict, and the arguments to the info
|
||||
action, display summary information for Borg archives in the repository or return JSON summary
|
||||
information.
|
||||
Given a local or remote repository path, a storage config dict, the local Borg version, and the
|
||||
arguments to the info action, display summary information for Borg archives in the repository or
|
||||
return JSON summary information.
|
||||
'''
|
||||
lock_wait = storage_config.get('lock_wait', None)
|
||||
|
||||
|
@ -33,11 +38,18 @@ def display_archives_info(
|
|||
+ make_flags('lock-wait', lock_wait)
|
||||
+ make_flags_from_arguments(info_arguments, excludes=('repository', 'archive'))
|
||||
+ (
|
||||
(
|
||||
('--repo', repository)
|
||||
+ (('--glob-archives', info_arguments.archive) if info_arguments.archive else ())
|
||||
)
|
||||
if feature.available(feature.Feature.SEPARATE_REPOSITORY_ARCHIVE, local_borg_version)
|
||||
else (
|
||||
'::'.join((repository, info_arguments.archive))
|
||||
if info_arguments.archive
|
||||
else repository,
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return execute_command(
|
||||
full_command,
|
||||
|
|
|
@ -2,18 +2,19 @@ import argparse
|
|||
import logging
|
||||
import subprocess
|
||||
|
||||
from borgmatic.borg import environment, info
|
||||
from borgmatic.borg import environment, feature, rinfo
|
||||
from borgmatic.execute import DO_NOT_CAPTURE, execute_command
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
INFO_REPOSITORY_NOT_FOUND_EXIT_CODE = 2
|
||||
RINFO_REPOSITORY_NOT_FOUND_EXIT_CODE = 2
|
||||
|
||||
|
||||
def initialize_repository(
|
||||
def create_repository(
|
||||
repository,
|
||||
storage_config,
|
||||
local_borg_version,
|
||||
encryption_mode,
|
||||
append_only=None,
|
||||
storage_quota=None,
|
||||
|
@ -21,28 +22,34 @@ def initialize_repository(
|
|||
remote_path=None,
|
||||
):
|
||||
'''
|
||||
Given a local or remote repository path, a storage configuration dict, a Borg encryption mode,
|
||||
whether the repository should be append-only, and the storage quota to use, initialize the
|
||||
repository. If the repository already exists, then log and skip initialization.
|
||||
Given a local or remote repository path, a storage configuration dict, the local Borg version, a
|
||||
Borg encryption mode, whether the repository should be append-only, and the storage quota to
|
||||
use, create the repository. If the repository already exists, then log and skip creation.
|
||||
'''
|
||||
try:
|
||||
info.display_archives_info(
|
||||
rinfo.display_repository_info(
|
||||
repository,
|
||||
storage_config,
|
||||
argparse.Namespace(json=True, archive=None),
|
||||
local_borg_version,
|
||||
argparse.Namespace(json=True),
|
||||
local_path,
|
||||
remote_path,
|
||||
)
|
||||
logger.info('Repository already exists. Skipping initialization.')
|
||||
logger.info('Repository already exists. Skipping creation.')
|
||||
return
|
||||
except subprocess.CalledProcessError as error:
|
||||
if error.returncode != INFO_REPOSITORY_NOT_FOUND_EXIT_CODE:
|
||||
if error.returncode != RINFO_REPOSITORY_NOT_FOUND_EXIT_CODE:
|
||||
raise
|
||||
|
||||
extra_borg_options = storage_config.get('extra_borg_options', {}).get('init', '')
|
||||
extra_borg_options = storage_config.get('extra_borg_options', {}).get('rcreate', '')
|
||||
|
||||
init_command = (
|
||||
(local_path, 'init')
|
||||
rcreate_command = (
|
||||
(local_path,)
|
||||
+ (
|
||||
('rcreate',)
|
||||
if feature.available(feature.Feature.RCREATE, local_borg_version)
|
||||
else ('init',)
|
||||
)
|
||||
+ (('--encryption', encryption_mode) if encryption_mode else ())
|
||||
+ (('--append-only',) if append_only else ())
|
||||
+ (('--storage-quota', storage_quota) if storage_quota else ())
|
||||
|
@ -50,12 +57,17 @@ def initialize_repository(
|
|||
+ (('--debug',) if logger.isEnabledFor(logging.DEBUG) else ())
|
||||
+ (('--remote-path', remote_path) if remote_path else ())
|
||||
+ (tuple(extra_borg_options.split(' ')) if extra_borg_options else ())
|
||||
+ (
|
||||
('--repo',)
|
||||
if feature.available(feature.Feature.SEPARATE_REPOSITORY_ARCHIVE, local_borg_version)
|
||||
else ()
|
||||
)
|
||||
+ (repository,)
|
||||
)
|
||||
|
||||
# Do not capture output here, so as to support interactive prompts.
|
||||
execute_command(
|
||||
init_command,
|
||||
rcreate_command,
|
||||
output_file=DO_NOT_CAPTURE,
|
||||
borg_local_path=local_path,
|
||||
extra_environment=environment.make_environment(storage_config),
|
|
@ -4,7 +4,7 @@ from argparse import Action, ArgumentParser
|
|||
from borgmatic.config import collect
|
||||
|
||||
SUBPARSER_ALIASES = {
|
||||
'init': ['--init', '-I'],
|
||||
'rcreate': ['init', '--init', '-I'],
|
||||
'prune': ['--prune', '-p'],
|
||||
'compact': [],
|
||||
'create': ['--create', '-C'],
|
||||
|
@ -222,33 +222,35 @@ def make_parsers():
|
|||
metavar='',
|
||||
help='Specify zero or more actions. Defaults to prune, compact, create, and check. Use --help with action for details:',
|
||||
)
|
||||
init_parser = subparsers.add_parser(
|
||||
'init',
|
||||
aliases=SUBPARSER_ALIASES['init'],
|
||||
help='Initialize an empty Borg repository',
|
||||
description='Initialize an empty Borg repository',
|
||||
rcreate_parser = subparsers.add_parser(
|
||||
'rcreate',
|
||||
aliases=SUBPARSER_ALIASES['rcreate'],
|
||||
help='Create a new, empty Borg repository',
|
||||
description='Create a new, empty Borg repository',
|
||||
add_help=False,
|
||||
)
|
||||
init_group = init_parser.add_argument_group('init arguments')
|
||||
init_group.add_argument(
|
||||
rcreate_group = rcreate_parser.add_argument_group('rcreate arguments')
|
||||
rcreate_group.add_argument(
|
||||
'-e',
|
||||
'--encryption',
|
||||
dest='encryption_mode',
|
||||
help='Borg repository encryption mode',
|
||||
required=True,
|
||||
)
|
||||
init_group.add_argument(
|
||||
rcreate_group.add_argument(
|
||||
'--append-only',
|
||||
dest='append_only',
|
||||
action='store_true',
|
||||
help='Create an append-only repository',
|
||||
)
|
||||
init_group.add_argument(
|
||||
rcreate_group.add_argument(
|
||||
'--storage-quota',
|
||||
dest='storage_quota',
|
||||
help='Create a repository with a fixed storage quota',
|
||||
)
|
||||
init_group.add_argument('-h', '--help', action='help', help='Show this help message and exit')
|
||||
rcreate_group.add_argument(
|
||||
'-h', '--help', action='help', help='Show this help message and exit'
|
||||
)
|
||||
|
||||
prune_parser = subparsers.add_parser(
|
||||
'prune',
|
||||
|
@ -688,11 +690,11 @@ def parse_arguments(*unparsed_arguments):
|
|||
|
||||
if arguments['global'].excludes_filename:
|
||||
raise ValueError(
|
||||
'The --excludes option has been replaced with exclude_patterns in configuration'
|
||||
'The --excludes flag has been replaced with exclude_patterns in configuration'
|
||||
)
|
||||
|
||||
if 'init' in arguments and arguments['global'].dry_run:
|
||||
raise ValueError('The init action cannot be used with the --dry-run option')
|
||||
if 'rcreate' in arguments and arguments['global'].dry_run:
|
||||
raise ValueError('The rcreate/init action cannot be used with the --dry-run flag')
|
||||
|
||||
if (
|
||||
'list' in arguments
|
||||
|
@ -700,6 +702,11 @@ def parse_arguments(*unparsed_arguments):
|
|||
and arguments['list'].json
|
||||
and arguments['info'].json
|
||||
):
|
||||
raise ValueError('With the --json option, list and info actions cannot be used together')
|
||||
raise ValueError('With the --json flag, list and info actions cannot be used together')
|
||||
|
||||
if 'info' in arguments and arguments['info'].archive and arguments['info'].glob_archives:
|
||||
raise ValueError(
|
||||
'With the info action, the --archive and --glob-archives flags cannot be used together'
|
||||
)
|
||||
|
||||
return arguments
|
||||
|
|
|
@ -20,10 +20,10 @@ from borgmatic.borg import export_tar as borg_export_tar
|
|||
from borgmatic.borg import extract as borg_extract
|
||||
from borgmatic.borg import feature as borg_feature
|
||||
from borgmatic.borg import info as borg_info
|
||||
from borgmatic.borg import init as borg_init
|
||||
from borgmatic.borg import list as borg_list
|
||||
from borgmatic.borg import mount as borg_mount
|
||||
from borgmatic.borg import prune as borg_prune
|
||||
from borgmatic.borg import rcreate as borg_rcreate
|
||||
from borgmatic.borg import umount as borg_umount
|
||||
from borgmatic.borg import version as borg_version
|
||||
from borgmatic.commands.arguments import parse_arguments
|
||||
|
@ -249,14 +249,15 @@ def run_actions(
|
|||
'repositories': ','.join(location['repositories']),
|
||||
}
|
||||
|
||||
if 'init' in arguments:
|
||||
logger.info('{}: Initializing repository'.format(repository))
|
||||
borg_init.initialize_repository(
|
||||
if 'rcreate' in arguments:
|
||||
logger.info('{}: Creating repository'.format(repository))
|
||||
borg_rcreate.create_repository(
|
||||
repository,
|
||||
storage,
|
||||
arguments['init'].encryption_mode,
|
||||
arguments['init'].append_only,
|
||||
arguments['init'].storage_quota,
|
||||
local_borg_version,
|
||||
arguments['rcreate'].encryption_mode,
|
||||
arguments['rcreate'].append_only,
|
||||
arguments['rcreate'].storage_quota,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
)
|
||||
|
@ -396,6 +397,7 @@ def run_actions(
|
|||
location,
|
||||
storage,
|
||||
consistency,
|
||||
local_borg_version,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
progress=arguments['check'].progress,
|
||||
|
@ -624,6 +626,7 @@ def run_actions(
|
|||
json_output = borg_info.display_archives_info(
|
||||
repository,
|
||||
storage,
|
||||
local_borg_version,
|
||||
info_arguments=info_arguments,
|
||||
local_path=local_path,
|
||||
remote_path=remote_path,
|
||||
|
|
|
@ -27,9 +27,6 @@ borgmatic create
|
|||
borgmatic check
|
||||
```
|
||||
|
||||
(No borgmatic `prune`, `create`, or `check` actions? Try the old-style
|
||||
`--prune`, `--create`, or `--check`. Or upgrade borgmatic!)
|
||||
|
||||
You can run with only one of these actions provided, or you can mix and match
|
||||
any number of them in a single borgmatic run. This supports approaches like
|
||||
skipping certain actions while running others. For instance, this skips
|
||||
|
@ -70,7 +67,9 @@ Here are the available checks from fastest to slowest:
|
|||
* `extract`: Performs an extraction dry-run of the most recent archive.
|
||||
* `data`: Verifies the data integrity of all archives contents, decrypting and decompressing all data (implies `archives` as well).
|
||||
|
||||
See [Borg's check documentation](https://borgbackup.readthedocs.io/en/stable/usage/check.html) for more information.
|
||||
See [Borg's check
|
||||
documentation](https://borgbackup.readthedocs.io/en/stable/usage/check.html)
|
||||
for more information.
|
||||
|
||||
### Check frequency
|
||||
|
||||
|
|
|
@ -37,19 +37,22 @@ borgmatic --stats
|
|||
## Existing backups
|
||||
|
||||
borgmatic provides convenient actions for Borg's
|
||||
[list](https://borgbackup.readthedocs.io/en/stable/usage/list.html) and
|
||||
[info](https://borgbackup.readthedocs.io/en/stable/usage/info.html)
|
||||
[`list`](https://borgbackup.readthedocs.io/en/stable/usage/list.html) and
|
||||
[`info`](https://borgbackup.readthedocs.io/en/stable/usage/info.html)
|
||||
functionality:
|
||||
|
||||
|
||||
```bash
|
||||
borgmatic list
|
||||
borgmatic info
|
||||
```
|
||||
|
||||
(No borgmatic `list` or `info` actions? Try the old-style `--list` or
|
||||
`--info`. Or upgrade borgmatic!)
|
||||
<span class="minilink minilink-addedin">New in borgmatic version 2.0.0</span>
|
||||
There's also an `rinfo` action for displaying repository information with Borg
|
||||
2.x:
|
||||
|
||||
```bash
|
||||
borgmatic rinfo
|
||||
```
|
||||
|
||||
### Searching for a file
|
||||
|
||||
|
|
|
@ -186,32 +186,36 @@ files via configuration management, or you want to double check that your hand
|
|||
edits are valid.
|
||||
|
||||
|
||||
## Initialization
|
||||
## Repository creation
|
||||
|
||||
Before you can create backups with borgmatic, you first need to initialize a
|
||||
Borg repository so you have a destination for your backup archives. (But skip
|
||||
this step if you already have a Borg repository.) To create a repository, run
|
||||
a command like the following:
|
||||
Before you can create backups with borgmatic, you first need to create a Borg
|
||||
repository so you have a destination for your backup archives. (But skip this
|
||||
step if you already have a Borg repository.) To create a repository, run a
|
||||
command like the following with Borg 1.x:
|
||||
|
||||
```bash
|
||||
sudo borgmatic init --encryption repokey
|
||||
```
|
||||
|
||||
(No borgmatic `init` action? Try the old-style `--init` flag, or upgrade
|
||||
borgmatic!)
|
||||
<span class="minilink minilink-addedin">New in borgmatic version 2.0.0</span>
|
||||
Or, with Borg 2.x:
|
||||
|
||||
```bash
|
||||
sudo borgmatic rcreate --encryption repokey-aes-ocb
|
||||
```
|
||||
|
||||
This uses the borgmatic configuration file you created above to determine
|
||||
which local or remote repository to create, and encrypts it with the
|
||||
encryption passphrase specified there if one is provided. Read about [Borg
|
||||
encryption
|
||||
modes](https://borgbackup.readthedocs.io/en/stable/usage/init.html#encryption-modes)
|
||||
modes](https://borgbackup.readthedocs.io/en/stable/usage/init.html#encryption-mode-tldr)
|
||||
for the menu of available encryption modes.
|
||||
|
||||
Also, optionally check out the [Borg Quick
|
||||
Start](https://borgbackup.readthedocs.org/en/stable/quickstart.html) for more
|
||||
background about repository initialization.
|
||||
background about repository creation.
|
||||
|
||||
Note that borgmatic skips repository initialization if the repository already
|
||||
Note that borgmatic skips repository creation if the repository already
|
||||
exists. This supports use cases like ensuring a repository exists prior to
|
||||
performing a backup.
|
||||
|
||||
|
@ -221,8 +225,8 @@ key-based SSH access to the desired user account on the remote host.
|
|||
|
||||
## Backups
|
||||
|
||||
Now that you've configured borgmatic and initialized a repository, it's a
|
||||
good idea to test that borgmatic is working. So to run borgmatic and start a
|
||||
Now that you've configured borgmatic and created a repository, it's a good
|
||||
idea to test that borgmatic is working. So to run borgmatic and start a
|
||||
backup, you can invoke it like this:
|
||||
|
||||
```bash
|
||||
|
@ -230,7 +234,7 @@ sudo borgmatic create --verbosity 1 --files --stats
|
|||
```
|
||||
|
||||
(No borgmatic `--files` flag? It's only present in newer versions of
|
||||
borgmatic. So try leaving it out, or upgrade borgmatic!)
|
||||
borgmatic. So try leaving it out or upgrade borgmatic!)
|
||||
|
||||
The `--verbosity` flag makes borgmatic show the steps it's performing. The
|
||||
`--files` flag lists each file that's new or changed since the last backup.
|
||||
|
|
|
@ -14,8 +14,8 @@ apk add --no-cache python3 py3-pip borgbackup postgresql-client mariadb-client m
|
|||
py3-ruamel.yaml py3-ruamel.yaml.clib bash
|
||||
# If certain dependencies of black are available in this version of Alpine, install them.
|
||||
apk add --no-cache py3-typed-ast py3-regex || true
|
||||
python3 -m pip install --no-cache --upgrade pip==22.0.3 setuptools==60.8.1
|
||||
pip3 install tox==3.24.5
|
||||
python3 -m pip install --no-cache --upgrade pip==22.2.2 setuptools==64.0.1
|
||||
pip3 install --ignore-installed tox==3.25.1
|
||||
export COVERAGE_FILE=/tmp/.coverage
|
||||
tox --workdir /tmp/.tox --sitepackages
|
||||
tox --workdir /tmp/.tox --sitepackages -e end-to-end
|
||||
|
|
2
setup.py
2
setup.py
|
@ -1,6 +1,6 @@
|
|||
from setuptools import find_packages, setup
|
||||
|
||||
VERSION = '1.6.7.dev0'
|
||||
VERSION = '2.0.0.dev0'
|
||||
|
||||
|
||||
setup(
|
||||
|
|
|
@ -496,6 +496,13 @@ def test_parse_arguments_disallows_json_with_both_list_and_info():
|
|||
module.parse_arguments('list', 'info', '--json')
|
||||
|
||||
|
||||
def test_parse_arguments_disallows_info_with_both_archive_and_glob_archives():
|
||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.parse_arguments('info', '--archive', 'foo', '--glob-archives', '*bar')
|
||||
|
||||
|
||||
def test_parse_arguments_check_only_extract_does_not_raise_extract_subparser_error():
|
||||
flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default'])
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ def test_check_archives_with_progress_calls_borg_with_progress_parameter():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').and_return(())
|
||||
|
@ -315,6 +315,7 @@ def test_check_archives_with_progress_calls_borg_with_progress_parameter():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
progress=True,
|
||||
)
|
||||
|
||||
|
@ -324,7 +325,7 @@ def test_check_archives_with_repair_calls_borg_with_repair_parameter():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').and_return(())
|
||||
|
@ -343,6 +344,7 @@ def test_check_archives_with_repair_calls_borg_with_repair_parameter():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
repair=True,
|
||||
)
|
||||
|
||||
|
@ -361,7 +363,7 @@ def test_check_archives_calls_borg_with_parameters(checks):
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').with_args(
|
||||
|
@ -376,6 +378,7 @@ def test_check_archives_calls_borg_with_parameters(checks):
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -385,7 +388,7 @@ def test_check_archives_with_json_error_raises():
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"unexpected": {"id": "repo"}}'
|
||||
)
|
||||
|
||||
|
@ -395,6 +398,7 @@ def test_check_archives_with_json_error_raises():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -404,7 +408,7 @@ def test_check_archives_with_missing_json_keys_raises():
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return('{invalid JSON')
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return('{invalid JSON')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.check_archives(
|
||||
|
@ -412,6 +416,7 @@ def test_check_archives_with_missing_json_keys_raises():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -421,7 +426,7 @@ def test_check_archives_with_extract_check_calls_extract_only():
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').never()
|
||||
|
@ -434,6 +439,7 @@ def test_check_archives_with_extract_check_calls_extract_only():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -442,7 +448,7 @@ def test_check_archives_with_log_info_calls_borg_with_info_parameter():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').and_return(())
|
||||
|
@ -456,6 +462,7 @@ def test_check_archives_with_log_info_calls_borg_with_info_parameter():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -464,7 +471,7 @@ def test_check_archives_with_log_debug_calls_borg_with_debug_parameter():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').and_return(())
|
||||
|
@ -478,6 +485,7 @@ def test_check_archives_with_log_debug_calls_borg_with_debug_parameter():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -485,7 +493,7 @@ def test_check_archives_without_any_checks_bails():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(())
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
insert_execute_command_never()
|
||||
|
@ -495,6 +503,7 @@ def test_check_archives_without_any_checks_bails():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -504,7 +513,7 @@ def test_check_archives_with_local_path_calls_borg_via_local_path():
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').with_args(
|
||||
|
@ -519,6 +528,7 @@ def test_check_archives_with_local_path_calls_borg_via_local_path():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
local_path='borg1',
|
||||
)
|
||||
|
||||
|
@ -529,7 +539,7 @@ def test_check_archives_with_remote_path_calls_borg_with_remote_path_parameters(
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').with_args(
|
||||
|
@ -544,6 +554,7 @@ def test_check_archives_with_remote_path_calls_borg_with_remote_path_parameters(
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
remote_path='borg1',
|
||||
)
|
||||
|
||||
|
@ -554,7 +565,7 @@ def test_check_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
|||
consistency_config = {'check_last': check_last}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').with_args(
|
||||
|
@ -569,6 +580,7 @@ def test_check_archives_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
|||
location_config={},
|
||||
storage_config={'lock_wait': 5},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -579,7 +591,7 @@ def test_check_archives_with_retention_prefix():
|
|||
consistency_config = {'check_last': check_last, 'prefix': prefix}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').with_args(
|
||||
|
@ -594,6 +606,7 @@ def test_check_archives_with_retention_prefix():
|
|||
location_config={},
|
||||
storage_config={},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
||||
|
||||
|
@ -602,7 +615,7 @@ def test_check_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
|||
consistency_config = {'check_last': None}
|
||||
flexmock(module).should_receive('parse_checks')
|
||||
flexmock(module).should_receive('filter_checks_on_frequency').and_return(checks)
|
||||
flexmock(module.info).should_receive('display_archives_info').and_return(
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_return(
|
||||
'{"repository": {"id": "repo"}}'
|
||||
)
|
||||
flexmock(module).should_receive('make_check_flags').and_return(())
|
||||
|
@ -615,4 +628,5 @@ def test_check_archives_with_extra_borg_options_calls_borg_with_extra_options():
|
|||
location_config={},
|
||||
storage_config={'extra_borg_options': {'check': '--extra --options'}},
|
||||
consistency_config=consistency_config,
|
||||
local_borg_version='1.2.3',
|
||||
)
|
||||
|
|
|
@ -9,6 +9,25 @@ from ..test_verbosity import insert_logging_mock
|
|||
|
||||
|
||||
def test_display_archives_info_calls_borg_with_parameters():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
)
|
||||
|
||||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_without_borg_features_calls_borg_without_repo_flag():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', 'repo'),
|
||||
|
@ -18,28 +37,36 @@ def test_display_archives_info_calls_borg_with_parameters():
|
|||
)
|
||||
|
||||
module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_log_info_calls_borg_with_info_parameter():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--info', 'repo'),
|
||||
('borg', 'info', '--info', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
)
|
||||
insert_logging_mock(logging.INFO)
|
||||
module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_output():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--json', 'repo'),
|
||||
('borg', 'info', '--json', '--repo', 'repo'),
|
||||
output_log_level=None,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -47,16 +74,20 @@ def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_outpu
|
|||
|
||||
insert_logging_mock(logging.INFO)
|
||||
json_output = module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=True),
|
||||
)
|
||||
|
||||
assert json_output == '[]'
|
||||
|
||||
|
||||
def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--debug', '--show-rc', 'repo'),
|
||||
('borg', 'info', '--debug', '--show-rc', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -64,14 +95,18 @@ def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter():
|
|||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=False)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_output():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--json', 'repo'),
|
||||
('borg', 'info', '--json', '--repo', 'repo'),
|
||||
output_log_level=None,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -79,29 +114,55 @@ def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_outp
|
|||
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
json_output = module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=True),
|
||||
)
|
||||
|
||||
assert json_output == '[]'
|
||||
|
||||
|
||||
def test_display_archives_info_with_json_calls_borg_with_json_parameter():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--json', 'repo'),
|
||||
('borg', 'info', '--json', '--repo', 'repo'),
|
||||
output_log_level=None,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
).and_return('[]')
|
||||
|
||||
json_output = module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive=None, json=True)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=True),
|
||||
)
|
||||
|
||||
assert json_output == '[]'
|
||||
|
||||
|
||||
def test_display_archives_info_with_archive_calls_borg_with_archive_parameter():
|
||||
def test_display_archives_info_with_archive_calls_borg_with_glob_archives_parameter():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--repo', 'repo', '--glob-archives', 'archive'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
)
|
||||
|
||||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive='archive', json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_archive_and_without_borg_features_calls_borg_with_repo_archive_parameter():
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', 'repo::archive'),
|
||||
|
@ -111,14 +172,18 @@ def test_display_archives_info_with_archive_calls_borg_with_archive_parameter():
|
|||
)
|
||||
|
||||
module.display_archives_info(
|
||||
repository='repo', storage_config={}, info_arguments=flexmock(archive='archive', json=False)
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive='archive', json=False),
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_local_path_calls_borg_via_local_path():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg1', 'info', 'repo'),
|
||||
('borg1', 'info', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg1',
|
||||
extra_environment=None,
|
||||
|
@ -127,15 +192,17 @@ def test_display_archives_info_with_local_path_calls_borg_via_local_path():
|
|||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
local_path='borg1',
|
||||
)
|
||||
|
||||
|
||||
def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_parameters():
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--remote-path', 'borg1', 'repo'),
|
||||
('borg', 'info', '--remote-path', 'borg1', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -144,6 +211,7 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para
|
|||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
remote_path='borg1',
|
||||
)
|
||||
|
@ -151,9 +219,10 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para
|
|||
|
||||
def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_parameters():
|
||||
storage_config = {'lock_wait': 5}
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--lock-wait', '5', 'repo'),
|
||||
('borg', 'info', '--lock-wait', '5', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -162,15 +231,17 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete
|
|||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config=storage_config,
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('argument_name', ('prefix', 'glob_archives', 'sort_by', 'first', 'last'))
|
||||
def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
('borg', 'info', '--' + argument_name.replace('_', '-'), 'value', 'repo'),
|
||||
('borg', 'info', '--' + argument_name.replace('_', '-'), 'value', '--repo', 'repo'),
|
||||
output_log_level=logging.WARNING,
|
||||
borg_local_path='borg',
|
||||
extra_environment=None,
|
||||
|
@ -179,5 +250,6 @@ def test_display_archives_info_passes_through_arguments_to_borg(argument_name):
|
|||
module.display_archives_info(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
info_arguments=flexmock(archive=None, json=False, **{argument_name: 'value'}),
|
||||
)
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
import logging
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.borg import init as module
|
||||
|
||||
from ..test_verbosity import insert_logging_mock
|
||||
|
||||
INFO_SOME_UNKNOWN_EXIT_CODE = -999
|
||||
INIT_COMMAND = ('borg', 'init', '--encryption', 'repokey')
|
||||
|
||||
|
||||
def insert_info_command_found_mock():
|
||||
flexmock(module.info).should_receive('display_archives_info')
|
||||
|
||||
|
||||
def insert_info_command_not_found_mock():
|
||||
flexmock(module.info).should_receive('display_archives_info').and_raise(
|
||||
subprocess.CalledProcessError(module.INFO_REPOSITORY_NOT_FOUND_EXIT_CODE, [])
|
||||
)
|
||||
|
||||
|
||||
def insert_init_command_mock(init_command, **kwargs):
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
init_command,
|
||||
output_file=module.DO_NOT_CAPTURE,
|
||||
borg_local_path=init_command[0],
|
||||
extra_environment=None,
|
||||
).once()
|
||||
|
||||
|
||||
def test_initialize_repository_calls_borg_with_parameters():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('repo',))
|
||||
|
||||
module.initialize_repository(repository='repo', storage_config={}, encryption_mode='repokey')
|
||||
|
||||
|
||||
def test_initialize_repository_raises_for_borg_init_error():
|
||||
insert_info_command_not_found_mock()
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').and_raise(
|
||||
module.subprocess.CalledProcessError(2, 'borg init')
|
||||
)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_skips_initialization_when_repository_already_exists():
|
||||
insert_info_command_found_mock()
|
||||
|
||||
module.initialize_repository(repository='repo', storage_config={}, encryption_mode='repokey')
|
||||
|
||||
|
||||
def test_initialize_repository_raises_for_unknown_info_command_error():
|
||||
flexmock(module.info).should_receive('display_archives_info').and_raise(
|
||||
subprocess.CalledProcessError(INFO_SOME_UNKNOWN_EXIT_CODE, [])
|
||||
)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_with_append_only_calls_borg_with_append_only_parameter():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--append-only', 'repo'))
|
||||
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey', append_only=True
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_with_storage_quota_calls_borg_with_storage_quota_parameter():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--storage-quota', '5G', 'repo'))
|
||||
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey', storage_quota='5G'
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_with_log_info_calls_borg_with_info_parameter():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--info', 'repo'))
|
||||
insert_logging_mock(logging.INFO)
|
||||
|
||||
module.initialize_repository(repository='repo', storage_config={}, encryption_mode='repokey')
|
||||
|
||||
|
||||
def test_initialize_repository_with_log_debug_calls_borg_with_debug_parameter():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--debug', 'repo'))
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
|
||||
module.initialize_repository(repository='repo', storage_config={}, encryption_mode='repokey')
|
||||
|
||||
|
||||
def test_initialize_repository_with_local_path_calls_borg_via_local_path():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(('borg1',) + INIT_COMMAND[1:] + ('repo',))
|
||||
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey', local_path='borg1'
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_with_remote_path_calls_borg_with_remote_path_parameter():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--remote-path', 'borg1', 'repo'))
|
||||
|
||||
module.initialize_repository(
|
||||
repository='repo', storage_config={}, encryption_mode='repokey', remote_path='borg1'
|
||||
)
|
||||
|
||||
|
||||
def test_initialize_repository_with_extra_borg_options_calls_borg_with_extra_options():
|
||||
insert_info_command_not_found_mock()
|
||||
insert_init_command_mock(INIT_COMMAND + ('--extra', '--options', 'repo'))
|
||||
|
||||
module.initialize_repository(
|
||||
repository='repo',
|
||||
storage_config={'extra_borg_options': {'init': '--extra --options'}},
|
||||
encryption_mode='repokey',
|
||||
)
|
183
tests/unit/borg/test_rcreate.py
Normal file
183
tests/unit/borg/test_rcreate.py
Normal file
|
@ -0,0 +1,183 @@
|
|||
import logging
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
from flexmock import flexmock
|
||||
|
||||
from borgmatic.borg import rcreate as module
|
||||
|
||||
from ..test_verbosity import insert_logging_mock
|
||||
|
||||
RINFO_SOME_UNKNOWN_EXIT_CODE = -999
|
||||
RCREATE_COMMAND = ('borg', 'rcreate', '--encryption', 'repokey')
|
||||
|
||||
|
||||
def insert_rinfo_command_found_mock():
|
||||
flexmock(module.rinfo).should_receive('display_repository_info')
|
||||
|
||||
|
||||
def insert_rinfo_command_not_found_mock():
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_raise(
|
||||
subprocess.CalledProcessError(module.RINFO_REPOSITORY_NOT_FOUND_EXIT_CODE, [])
|
||||
)
|
||||
|
||||
|
||||
def insert_rcreate_command_mock(rcreate_command, **kwargs):
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').with_args(
|
||||
rcreate_command,
|
||||
output_file=module.DO_NOT_CAPTURE,
|
||||
borg_local_path=rcreate_command[0],
|
||||
extra_environment=None,
|
||||
).once()
|
||||
|
||||
|
||||
def test_create_repository_calls_borg_with_parameters():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo', storage_config={}, local_borg_version='2.3.4', encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_without_borg_features_calls_borg_with_init_sub_command():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(('borg', 'init', '--encryption', 'repokey', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(False)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo', storage_config={}, local_borg_version='2.3.4', encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_raises_for_borg_rcreate_error():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
flexmock(module.environment).should_receive('make_environment')
|
||||
flexmock(module).should_receive('execute_command').and_raise(
|
||||
module.subprocess.CalledProcessError(2, 'borg rcreate')
|
||||
)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_skips_creation_when_repository_already_exists():
|
||||
insert_rinfo_command_found_mock()
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo', storage_config={}, local_borg_version='2.3.4', encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_raises_for_unknown_rinfo_command_error():
|
||||
flexmock(module.rinfo).should_receive('display_repository_info').and_raise(
|
||||
subprocess.CalledProcessError(RINFO_SOME_UNKNOWN_EXIT_CODE, [])
|
||||
)
|
||||
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_append_only_calls_borg_with_append_only_parameter():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--append-only', '--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
append_only=True,
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_storage_quota_calls_borg_with_storage_quota_parameter():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--storage-quota', '5G', '--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
storage_quota='5G',
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_log_info_calls_borg_with_info_parameter():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--info', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.INFO)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo', storage_config={}, local_borg_version='2.3.4', encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_log_debug_calls_borg_with_debug_parameter():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--debug', '--repo', 'repo'))
|
||||
insert_logging_mock(logging.DEBUG)
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo', storage_config={}, local_borg_version='2.3.4', encryption_mode='repokey'
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_local_path_calls_borg_via_local_path():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(('borg1',) + RCREATE_COMMAND[1:] + ('--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
local_path='borg1',
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_remote_path_calls_borg_with_remote_path_parameter():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--remote-path', 'borg1', '--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
remote_path='borg1',
|
||||
)
|
||||
|
||||
|
||||
def test_create_repository_with_extra_borg_options_calls_borg_with_extra_options():
|
||||
insert_rinfo_command_not_found_mock()
|
||||
insert_rcreate_command_mock(RCREATE_COMMAND + ('--extra', '--options', '--repo', 'repo'))
|
||||
flexmock(module.feature).should_receive('available').and_return(True)
|
||||
|
||||
module.create_repository(
|
||||
repository='repo',
|
||||
storage_config={'extra_borg_options': {'rcreate': '--extra --options'}},
|
||||
local_borg_version='2.3.4',
|
||||
encryption_mode='repokey',
|
||||
)
|
|
@ -340,11 +340,11 @@ def test_run_configuration_retries_timeout_multiple_repos():
|
|||
assert results == error_logs
|
||||
|
||||
|
||||
def test_run_actions_does_not_raise_for_init_action():
|
||||
flexmock(module.borg_init).should_receive('initialize_repository')
|
||||
def test_run_actions_does_not_raise_for_rcreate_action():
|
||||
flexmock(module.borg_rcreate).should_receive('create_repository')
|
||||
arguments = {
|
||||
'global': flexmock(monitoring_verbosity=1, dry_run=False),
|
||||
'init': flexmock(
|
||||
'rcreate': flexmock(
|
||||
encryption_mode=flexmock(), append_only=flexmock(), storage_quota=flexmock()
|
||||
),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue