From 616eb6b6daa5827395da1533ad4423fb2ce450aa Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Tue, 4 Apr 2023 21:25:10 -0700 Subject: [PATCH] Fix error with "info --match-archives" and fix "--match-archives" overriding logic (#666). --- NEWS | 5 + borgmatic/borg/info.py | 11 +- borgmatic/borg/rlist.py | 4 +- borgmatic/borg/transfer.py | 10 +- borgmatic/commands/arguments.py | 20 +++- docs/how-to/make-per-application-backups.md | 8 +- setup.py | 2 +- tests/integration/borg/test_commands.py | 104 +++++++++++++++++++ tests/integration/commands/test_arguments.py | 14 +++ tests/unit/borg/test_info.py | 90 ++++++++++++---- tests/unit/borg/test_rlist.py | 81 +++++++++++---- tests/unit/borg/test_transfer.py | 12 +-- 12 files changed, 292 insertions(+), 69 deletions(-) create mode 100644 tests/integration/borg/test_commands.py diff --git a/NEWS b/NEWS index f693e25f..96634fd0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,8 @@ +1.7.12.dev0 + * #666: Fix error when running the "info" action with the "--match-archives" flag. Also fix the + "--match-archives" flag to correctly override the "match_archives" configuration option for + the "transfer", "list", "rlist", and "info" actions. + 1.7.11 * #479, #588: BREAKING: Automatically use the "archive_name_format" option to filter which archives get used for borgmatic actions that operate on multiple archives. Override this behavior with the diff --git a/borgmatic/borg/info.py b/borgmatic/borg/info.py index a7ed98ed..80739c07 100644 --- a/borgmatic/borg/info.py +++ b/borgmatic/borg/info.py @@ -46,21 +46,18 @@ def display_archives_info( if info_arguments.prefix else ( flags.make_match_archives_flags( - storage_config.get('match_archives'), + info_arguments.match_archives + or info_arguments.archive + or storage_config.get('match_archives'), storage_config.get('archive_name_format'), local_borg_version, ) ) ) + flags.make_flags_from_arguments( - info_arguments, excludes=('repository', 'archive', 'prefix') + info_arguments, excludes=('repository', 'archive', 'prefix', 'match_archives') ) + flags.make_repository_flags(repository_path, local_borg_version) - + ( - flags.make_flags('match-archives', info_arguments.archive) - if feature.available(feature.Feature.MATCH_ARCHIVES, local_borg_version) - else flags.make_flags('glob-archives', info_arguments.archive) - ) ) if info_arguments.json: diff --git a/borgmatic/borg/rlist.py b/borgmatic/borg/rlist.py index f84499ce..9686b67b 100644 --- a/borgmatic/borg/rlist.py +++ b/borgmatic/borg/rlist.py @@ -52,7 +52,7 @@ def resolve_archive_name( return latest_archive -MAKE_FLAGS_EXCLUDES = ('repository', 'prefix') +MAKE_FLAGS_EXCLUDES = ('repository', 'prefix', 'match_archives') def make_rlist_command( @@ -96,7 +96,7 @@ def make_rlist_command( if rlist_arguments.prefix else ( flags.make_match_archives_flags( - storage_config.get('match_archives'), + rlist_arguments.match_archives or storage_config.get('match_archives'), storage_config.get('archive_name_format'), local_borg_version, ) diff --git a/borgmatic/borg/transfer.py b/borgmatic/borg/transfer.py index 78a76124..9fd05b76 100644 --- a/borgmatic/borg/transfer.py +++ b/borgmatic/borg/transfer.py @@ -28,12 +28,6 @@ def transfer_archives( + (('--debug', '--show-rc') if logger.isEnabledFor(logging.DEBUG) else ()) + flags.make_flags('remote-path', remote_path) + flags.make_flags('lock-wait', storage_config.get('lock_wait', None)) - + (('--progress',) if transfer_arguments.progress else ()) - + ( - flags.make_flags( - 'match-archives', transfer_arguments.match_archives or transfer_arguments.archive - ) - ) + ( flags.make_flags_from_arguments( transfer_arguments, @@ -41,7 +35,9 @@ def transfer_archives( ) or ( flags.make_match_archives_flags( - storage_config.get('match_archives'), + transfer_arguments.match_archives + or transfer_arguments.archive + or storage_config.get('match_archives'), storage_config.get('archive_name_format'), local_borg_version, ) diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index 84ab79fc..13ee3153 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -652,7 +652,7 @@ def make_parsers(): '--json', default=False, action='store_true', help='Output results as JSON' ) rlist_group.add_argument( - '-P', '--prefix', help='Only list archive names starting with this prefix' + '-P', '--prefix', help='Deprecated. Only list archive names starting with this prefix' ) rlist_group.add_argument( '-a', @@ -707,7 +707,7 @@ def make_parsers(): '--json', default=False, action='store_true', help='Output results as JSON' ) list_group.add_argument( - '-P', '--prefix', help='Only list archive names starting with this prefix' + '-P', '--prefix', help='Deprecated. Only list archive names starting with this prefix' ) list_group.add_argument( '-a', @@ -779,7 +779,9 @@ def make_parsers(): '--json', dest='json', default=False, action='store_true', help='Output results as JSON' ) info_group.add_argument( - '-P', '--prefix', help='Only show info for archive names starting with this prefix' + '-P', + '--prefix', + help='Deprecated. Only show info for archive names starting with this prefix', ) info_group.add_argument( '-a', @@ -877,7 +879,17 @@ def parse_arguments(*unparsed_arguments): and arguments['transfer'].match_archives ): raise ValueError( - 'With the transfer action, only one of --archive and --glob-archives flags can be used.' + 'With the transfer action, only one of --archive and --match-archives flags can be used.' + ) + + if 'list' in arguments and (arguments['list'].prefix and arguments['list'].match_archives): + raise ValueError( + 'With the list action, only one of --prefix or --match-archives flags can be used.' + ) + + if 'rlist' in arguments and (arguments['rlist'].prefix and arguments['rlist'].match_archives): + raise ValueError( + 'With the rlist action, only one of --prefix or --match-archives flags can be used.' ) if 'info' in arguments and ( diff --git a/docs/how-to/make-per-application-backups.md b/docs/how-to/make-per-application-backups.md index a4898430..27c643f9 100644 --- a/docs/how-to/make-per-application-backups.md +++ b/docs/how-to/make-per-application-backups.md @@ -128,13 +128,17 @@ documentation](https://borgbackup.readthedocs.io/en/stable/usage/help.html#borg- for more information. For Borg 2.x, see the [match archives documentation](https://borgbackup.readthedocs.io/en/2.0.0b5/usage/help.html#borg-help-match-archives). +Some borgmatic command-line actions also have a `--match-archives` flag that +overrides both the auto-matching behavior and the `match_archives` +configuration option. + Prior to 1.7.11 The way to limit the archives used for the `prune` action was a `prefix` option in the `retention` section for matching against the start of archive names. And the option for limiting the archives used for the `check` action was a separate `prefix` in the `consistency` section. Both of these options are deprecated in -favor of the auto-matching behavior (or `match_archives`) in newer versions of -borgmatic. +favor of the auto-matching behavior (or `match_archives`/`--match-archives`) +in newer versions of borgmatic. ## Configuration includes diff --git a/setup.py b/setup.py index ad58f0e5..4b870eb4 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ from setuptools import find_packages, setup -VERSION = '1.7.11' +VERSION = '1.7.12.dev0' setup( diff --git a/tests/integration/borg/test_commands.py b/tests/integration/borg/test_commands.py new file mode 100644 index 00000000..4f9a6b25 --- /dev/null +++ b/tests/integration/borg/test_commands.py @@ -0,0 +1,104 @@ +import copy + +import flexmock + +import borgmatic.borg.info +import borgmatic.borg.list +import borgmatic.borg.rlist +import borgmatic.borg.transfer +import borgmatic.commands.arguments + + +def assert_command_does_not_duplicate_flags(command, *args, **kwargs): + ''' + Assert that the given Borg command sequence does not contain any duplicated flags, e.g. + "--match-archives" twice anywhere in the command. + ''' + flag_counts = {} + + for flag_name in command: + if not flag_name.startswith('--'): + continue + + if flag_name in flag_counts: + flag_counts[flag_name] += 1 + else: + flag_counts[flag_name] = 1 + + assert flag_counts == { + flag_name: 1 for flag_name in flag_counts + }, f"Duplicate flags found in: {' '.join(command)}" + + +def fuzz_argument(arguments, argument_name): + ''' + Given an argparse.Namespace instance of arguments and an argument name in it, copy the arguments + namespace and set the argument name in the copy with a fake value. Return the copied arguments. + + This is useful for "fuzzing" a unit under test by passing it each possible argument in turn, + making sure it doesn't blow up or duplicate Borg arguments. + ''' + arguments_copy = copy.copy(arguments) + value = getattr(arguments_copy, argument_name) + setattr(arguments_copy, argument_name, not value if isinstance(value, bool) else 'value') + + return arguments_copy + + +def test_transfer_archives_command_does_not_duplicate_flags_or_raise(): + arguments = borgmatic.commands.arguments.parse_arguments( + 'transfer', '--source-repository', 'foo' + )['transfer'] + flexmock(borgmatic.borg.transfer).should_receive('execute_command').replace_with( + assert_command_does_not_duplicate_flags + ) + + for argument_name in dir(arguments): + if argument_name.startswith('_'): + continue + + borgmatic.borg.transfer.transfer_archives( + False, 'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name) + ) + + +def test_make_list_command_does_not_duplicate_flags_or_raise(): + arguments = borgmatic.commands.arguments.parse_arguments('list')['list'] + + for argument_name in dir(arguments): + if argument_name.startswith('_'): + continue + + borgmatic.borg.list.make_list_command( + 'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name) + ) + + +def test_make_rlist_command_does_not_duplicate_flags_or_raise(): + arguments = borgmatic.commands.arguments.parse_arguments('rlist')['rlist'] + + for argument_name in dir(arguments): + if argument_name.startswith('_'): + continue + + borgmatic.borg.rlist.make_rlist_command( + 'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name) + ) + + +def test_display_archives_info_command_does_not_duplicate_flags_or_raise(): + arguments = borgmatic.commands.arguments.parse_arguments('info')['info'] + flexmock(borgmatic.borg.info).should_receive('execute_command_and_capture_output').replace_with( + assert_command_does_not_duplicate_flags + ) + flexmock(borgmatic.borg.info).should_receive('execute_command').replace_with( + assert_command_does_not_duplicate_flags + ) + + for argument_name in dir(arguments): + if argument_name.startswith('_'): + continue + + borgmatic.borg.info.display_archives_info( + 'repo', {}, '2.3.4', fuzz_argument(arguments, argument_name) + ) diff --git a/tests/integration/commands/test_arguments.py b/tests/integration/commands/test_arguments.py index 754564b2..1fc8f8c8 100644 --- a/tests/integration/commands/test_arguments.py +++ b/tests/integration/commands/test_arguments.py @@ -465,6 +465,20 @@ def test_parse_arguments_disallows_transfer_with_both_archive_and_match_archives ) +def test_parse_arguments_disallows_list_with_both_prefix_and_match_archives(): + flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) + + with pytest.raises(ValueError): + module.parse_arguments('list', '--prefix', 'foo', '--match-archives', 'sh:*bar') + + +def test_parse_arguments_disallows_rlist_with_both_prefix_and_match_archives(): + flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) + + with pytest.raises(ValueError): + module.parse_arguments('rlist', '--prefix', 'foo', '--match-archives', 'sh:*bar') + + def test_parse_arguments_disallows_info_with_both_archive_and_match_archives(): flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) diff --git a/tests/unit/borg/test_info.py b/tests/unit/borg/test_info.py index ee525857..d51bf14d 100644 --- a/tests/unit/borg/test_info.py +++ b/tests/unit/borg/test_info.py @@ -29,7 +29,7 @@ def test_display_archives_info_calls_borg_with_parameters(): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), ) @@ -54,7 +54,7 @@ def test_display_archives_info_with_log_info_calls_borg_with_info_parameter(): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), ) @@ -77,7 +77,7 @@ def test_display_archives_info_with_log_info_and_json_suppresses_most_borg_outpu repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=True, prefix=None), + info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None), ) assert json_output == '[]' @@ -105,7 +105,7 @@ def test_display_archives_info_with_log_debug_calls_borg_with_debug_parameter(): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), ) @@ -128,7 +128,7 @@ def test_display_archives_info_with_log_debug_and_json_suppresses_most_borg_outp repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=True, prefix=None), + info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None), ) assert json_output == '[]' @@ -152,7 +152,7 @@ def test_display_archives_info_with_json_calls_borg_with_json_parameter(): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=True, prefix=None), + info_arguments=flexmock(archive=None, json=True, prefix=None, match_archives=None), ) assert json_output == '[]' @@ -162,17 +162,14 @@ def test_display_archives_info_with_archive_calls_borg_with_match_archives_param flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module.flags).should_receive('make_flags').and_return(()) - flexmock(module.flags).should_receive('make_flags').with_args( - 'match-archives', 'archive' - ).and_return(('--match-archives', 'archive')) flexmock(module.flags).should_receive('make_match_archives_flags').with_args( - None, None, '2.3.4' - ).and_return(()) + 'archive', None, '2.3.4' + ).and_return(('--match-archives', 'archive')) flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) flexmock(module.environment).should_receive('make_environment') flexmock(module).should_receive('execute_command').with_args( - ('borg', 'info', '--repo', 'repo', '--match-archives', 'archive'), + ('borg', 'info', '--match-archives', 'archive', '--repo', 'repo'), output_log_level=module.borgmatic.logger.ANSWER, borg_local_path='borg', extra_environment=None, @@ -182,7 +179,7 @@ def test_display_archives_info_with_archive_calls_borg_with_match_archives_param repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive='archive', json=False, prefix=None), + info_arguments=flexmock(archive='archive', json=False, prefix=None, match_archives=None), ) @@ -207,7 +204,7 @@ def test_display_archives_info_with_local_path_calls_borg_via_local_path(): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), local_path='borg1', ) @@ -236,7 +233,7 @@ def test_display_archives_info_with_remote_path_calls_borg_with_remote_path_para repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), remote_path='borg1', ) @@ -266,7 +263,7 @@ def test_display_archives_info_with_lock_wait_calls_borg_with_lock_wait_paramete repository_path='repo', storage_config=storage_config, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), ) @@ -347,11 +344,64 @@ def test_display_archives_info_transforms_archive_name_format_into_match_archive repository_path='repo', storage_config={'archive_name_format': 'bar-{now}'}, # noqa: FS003 local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None), + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), ) -@pytest.mark.parametrize('argument_name', ('match_archives', 'sort_by', 'first', 'last')) +def test_display_archives_with_match_archives_option_calls_borg_with_match_archives_parameter(): + flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER + flexmock(module.flags).should_receive('make_flags').and_return(()) + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + 'sh:foo-*', 'bar-{now}', '2.3.4' # noqa: FS003 + ).and_return(('--match-archives', 'sh:foo-*')) + flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) + flexmock(module.environment).should_receive('make_environment') + flexmock(module).should_receive('execute_command').with_args( + ('borg', 'info', '--match-archives', 'sh:foo-*', '--repo', 'repo'), + output_log_level=module.borgmatic.logger.ANSWER, + borg_local_path='borg', + extra_environment=None, + ) + + module.display_archives_info( + repository_path='repo', + storage_config={ + 'archive_name_format': 'bar-{now}', # noqa: FS003 + 'match_archives': 'sh:foo-*', + }, + local_borg_version='2.3.4', + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives=None), + ) + + +def test_display_archives_with_match_archives_flag_calls_borg_with_match_archives_parameter(): + flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') + flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER + flexmock(module.flags).should_receive('make_flags').and_return(()) + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + 'sh:foo-*', 'bar-{now}', '2.3.4' # noqa: FS003 + ).and_return(('--match-archives', 'sh:foo-*')) + flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) + flexmock(module.environment).should_receive('make_environment') + flexmock(module).should_receive('execute_command').with_args( + ('borg', 'info', '--match-archives', 'sh:foo-*', '--repo', 'repo'), + output_log_level=module.borgmatic.logger.ANSWER, + borg_local_path='borg', + extra_environment=None, + ) + + module.display_archives_info( + repository_path='repo', + storage_config={'archive_name_format': 'bar-{now}'}, # noqa: FS003 + local_borg_version='2.3.4', + info_arguments=flexmock(archive=None, json=False, prefix=None, match_archives='sh:foo-*'), + ) + + +@pytest.mark.parametrize('argument_name', ('sort_by', 'first', 'last')) def test_display_archives_info_passes_through_arguments_to_borg(argument_name): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER @@ -376,5 +426,7 @@ def test_display_archives_info_passes_through_arguments_to_borg(argument_name): repository_path='repo', storage_config={}, local_borg_version='2.3.4', - info_arguments=flexmock(archive=None, json=False, prefix=None, **{argument_name: 'value'}), + info_arguments=flexmock( + archive=None, json=False, prefix=None, match_archives=None, **{argument_name: 'value'} + ), ) diff --git a/tests/unit/borg/test_rlist.py b/tests/unit/borg/test_rlist.py index 136821d6..6b1561a2 100644 --- a/tests/unit/borg/test_rlist.py +++ b/tests/unit/borg/test_rlist.py @@ -137,7 +137,9 @@ def test_make_rlist_command_includes_log_info(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--info', 'repo') @@ -156,7 +158,9 @@ def test_make_rlist_command_includes_json_but_not_info(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=True, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--json', 'repo') @@ -175,7 +179,9 @@ def test_make_rlist_command_includes_log_debug(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--debug', '--show-rc', 'repo') @@ -194,7 +200,9 @@ def test_make_rlist_command_includes_json_but_not_debug(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=True, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--json', 'repo') @@ -212,7 +220,9 @@ def test_make_rlist_command_includes_json(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=True, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=True, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--json', 'repo') @@ -232,7 +242,9 @@ def test_make_rlist_command_includes_lock_wait(): repository_path='repo', storage_config={'lock_wait': 5}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--lock-wait', '5', 'repo') @@ -250,7 +262,9 @@ def test_make_rlist_command_includes_local_path(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), local_path='borg2', ) @@ -271,7 +285,9 @@ def test_make_rlist_command_includes_remote_path(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), remote_path='borg2', ) @@ -328,7 +344,9 @@ def test_make_rlist_command_transforms_archive_name_format_into_match_archives() repository_path='repo', storage_config={'archive_name_format': 'bar-{now}'}, # noqa: FS003 local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None + ), ) assert command == ('borg', 'list', '--match-archives', 'sh:bar-*', 'repo') @@ -346,7 +364,9 @@ def test_make_rlist_command_includes_short(): repository_path='repo', storage_config={}, local_borg_version='1.2.3', - rlist_arguments=flexmock(archive=None, paths=None, json=False, prefix=None, short=True), + rlist_arguments=flexmock( + archive=None, paths=None, json=False, prefix=None, match_archives=None, short=True + ), ) assert command == ('borg', 'list', '--short', 'repo') @@ -354,16 +374,7 @@ def test_make_rlist_command_includes_short(): @pytest.mark.parametrize( 'argument_name', - ( - 'match_archives', - 'sort_by', - 'first', - 'last', - 'exclude', - 'exclude_from', - 'pattern', - 'patterns_from', - ), + ('sort_by', 'first', 'last', 'exclude', 'exclude_from', 'pattern', 'patterns_from',), ) def test_make_rlist_command_includes_additional_flags(argument_name): flexmock(module.flags).should_receive('make_flags').and_return(()) @@ -384,6 +395,7 @@ def test_make_rlist_command_includes_additional_flags(argument_name): paths=None, json=False, prefix=None, + match_archives=None, find_paths=None, format=None, **{argument_name: 'value'}, @@ -393,6 +405,35 @@ def test_make_rlist_command_includes_additional_flags(argument_name): assert command == ('borg', 'list', '--' + argument_name.replace('_', '-'), 'value', 'repo') +def test_make_rlist_command_with_match_archives_calls_borg_with_match_archives_parameters(): + flexmock(module.flags).should_receive('make_flags').and_return(()) + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + None, None, '1.2.3' + ).and_return(()) + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + 'foo-*', None, '1.2.3', + ).and_return(('--match-archives', 'foo-*')) + flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) + flexmock(module.flags).should_receive('make_repository_flags').and_return(('repo',)) + + command = module.make_rlist_command( + repository_path='repo', + storage_config={}, + local_borg_version='1.2.3', + rlist_arguments=flexmock( + archive=None, + paths=None, + json=False, + prefix=None, + match_archives='foo-*', + find_paths=None, + format=None, + ), + ) + + assert command == ('borg', 'list', '--match-archives', 'foo-*', 'repo') + + def test_list_repository_calls_borg_with_parameters(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER diff --git a/tests/unit/borg/test_transfer.py b/tests/unit/borg/test_transfer.py index 857c86ec..8f41bf5a 100644 --- a/tests/unit/borg/test_transfer.py +++ b/tests/unit/borg/test_transfer.py @@ -124,10 +124,9 @@ def test_transfer_archives_with_archive_calls_borg_with_match_archives_flag(): flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module.flags).should_receive('make_flags').and_return(()) - flexmock(module.flags).should_receive('make_flags').with_args( - 'match-archives', 'archive' + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + 'archive', 'bar-{now}', '2.3.4' # noqa: FS003 ).and_return(('--match-archives', 'archive')) - flexmock(module.flags).should_receive('make_match_archives_flags').and_return(()) flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) flexmock(module.environment).should_receive('make_environment') @@ -154,10 +153,9 @@ def test_transfer_archives_with_match_archives_calls_borg_with_match_archives_fl flexmock(module.borgmatic.logger).should_receive('add_custom_log_levels') flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module.flags).should_receive('make_flags').and_return(()) - flexmock(module.flags).should_receive('make_flags').with_args( - 'match-archives', 'sh:foo*' + flexmock(module.flags).should_receive('make_match_archives_flags').with_args( + 'sh:foo*', 'bar-{now}', '2.3.4' # noqa: FS003 ).and_return(('--match-archives', 'sh:foo*')) - flexmock(module.flags).should_receive('make_match_archives_flags').and_return(()) flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) flexmock(module.environment).should_receive('make_environment') @@ -304,7 +302,7 @@ def test_transfer_archives_with_progress_calls_borg_with_progress_flag(): flexmock(module.logging).ANSWER = module.borgmatic.logger.ANSWER flexmock(module.flags).should_receive('make_flags').and_return(()) flexmock(module.flags).should_receive('make_match_archives_flags').and_return(()) - flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(()) + flexmock(module.flags).should_receive('make_flags_from_arguments').and_return(('--progress',)) flexmock(module.flags).should_receive('make_repository_flags').and_return(('--repo', 'repo')) flexmock(module.environment).should_receive('make_environment') flexmock(module).should_receive('execute_command').with_args(