From 8b3a682edfa833383f53ef8b2f1dd9b6b5e08baf Mon Sep 17 00:00:00 2001 From: Vandal <86826719+VandalByte@users.noreply.github.com> Date: Sat, 29 Mar 2025 01:26:20 +0530 Subject: [PATCH] add tests and minor fixes --- borgmatic/borg/recreate.py | 15 +- borgmatic/commands/arguments.py | 12 -- tests/unit/borg/test_recreate.py | 269 +++++++++++++++++++++++++++---- 3 files changed, 243 insertions(+), 53 deletions(-) diff --git a/borgmatic/borg/recreate.py b/borgmatic/borg/recreate.py index 81d5a6ed..bea11b58 100644 --- a/borgmatic/borg/recreate.py +++ b/borgmatic/borg/recreate.py @@ -33,6 +33,8 @@ def recreate_archive( exclude_flags = make_exclude_flags(config) compression = config.get('compression', None) chunker_params = config.get('chunker_params', None) + # Available recompress MODES: 'if-different' (default), 'always', 'never' + recompress = config.get('recompress', None) # Write patterns to a temporary file and use that file with --patterns-from. patterns_file = write_patterns_file( @@ -42,11 +44,6 @@ def recreate_archive( recreate_command = ( (local_path, 'recreate') + (('--remote-path', remote_path) if remote_path else ()) - # + ( - # ('--path', recreate_arguments.path) - # if recreate_arguments.path - # else () - # ) + (('--log-json',) if global_arguments.log_json else ()) + (('--lock-wait', str(lock_wait)) if lock_wait is not None else ()) + (('--info',) if logger.getEffectiveLevel() == logging.INFO else ()) @@ -62,11 +59,7 @@ def recreate_archive( else () ) # Flag --target works only for a single archive - + ( - ('--target', recreate_arguments.target) - if recreate_arguments.target and recreate_arguments.archive - else () - ) + + (('--target', recreate_arguments.target) if recreate_arguments.target and archive else ()) + ( ('--comment', shlex.quote(recreate_arguments.comment)) if recreate_arguments.comment @@ -84,7 +77,7 @@ def recreate_archive( if recreate_arguments.match_archives else () ) - + (('--recompress', recreate_arguments.recompress) if recreate_arguments.recompress else ()) + + (('--recompress', recompress) if recompress else ()) + exclude_flags + ( flags.make_repository_archive_flags(repository, archive, local_borg_version) diff --git a/borgmatic/commands/arguments.py b/borgmatic/commands/arguments.py index 8e468e8a..b0185348 100644 --- a/borgmatic/commands/arguments.py +++ b/borgmatic/commands/arguments.py @@ -1562,13 +1562,6 @@ def make_parsers(): '--archive', help='Archive name, hash, or series to recreate', ) - # recreate_group.add_argument( - # '--path', - # metavar='PATH', - # dest='path', - # help='Path to recreate the repository/archive', - # required=True, - # ) recreate_group.add_argument( '--list', dest='list', action='store_true', help='Show per-file details' ) @@ -1595,11 +1588,6 @@ def make_parsers(): metavar='PATTERN', help='Only consider archive names, hashes, or series matching this pattern', ) - recreate_group.add_argument( - '--recompress', - metavar='MODE', - help='Recompress data chunks according to MODE: [if-different (default), always, never]', - ) recreate_group.add_argument( '-h', '--help', action='help', help='Show this help message and exit' ) diff --git a/tests/unit/borg/test_recreate.py b/tests/unit/borg/test_recreate.py index aaa3c3fd..5ec0eeaf 100644 --- a/tests/unit/borg/test_recreate.py +++ b/tests/unit/borg/test_recreate.py @@ -1,4 +1,5 @@ import logging +import shlex from flexmock import flexmock @@ -34,10 +35,7 @@ def test_recreate_archive_dry_run_skips_execution(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ) result = module.recreate_archive( @@ -66,10 +64,7 @@ def test_recreate_calls_borg_with_required_flags(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -91,10 +86,7 @@ def test_recreate_with_remote_path(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -116,10 +108,7 @@ def test_recreate_with_lock_wait(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -142,10 +131,7 @@ def test_recreate_with_log_info(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -167,10 +153,7 @@ def test_recreate_with_log_debug(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -191,10 +174,7 @@ def test_recreate_with_log_json(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=True), local_path='borg', @@ -218,10 +198,7 @@ def test_recreate_with_list_filter_flags(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -246,10 +223,7 @@ def test_recreate_with_patterns_from_flag(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', @@ -271,13 +245,248 @@ def test_recreate_with_exclude_flags(): target=None, comment=None, timestamp=None, - compression=None, - chunker_params=None, match_archives=None, - recompress=None, ), global_arguments=flexmock(dry_run=False, log_json=False), local_path='borg', patterns=None, ) + +def test_recreate_with_target_flag(): + insert_execute_command_mock(('borg', 'recreate', '--target', 'new-archive', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target='new-archive', + comment=None, + timestamp=None, + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_comment_flag(): + insert_execute_command_mock( + ('borg', 'recreate', '--comment', shlex.quote('This is a test comment'), 'repo::archive') + ) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment='This is a test comment', + timestamp=None, + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_timestamp_flag(): + insert_execute_command_mock( + ('borg', 'recreate', '--timestamp', '2023-10-01T12:00:00', 'repo::archive') + ) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp='2023-10-01T12:00:00', + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_compression_flag(): + insert_execute_command_mock(('borg', 'recreate', '--compression', 'lz4', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={'compression': 'lz4'}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_chunker_params_flag(): + insert_execute_command_mock( + ('borg', 'recreate', '--chunker-params', '19,23,21,4095', 'repo::archive') + ) + + module.recreate_archive( + repository='repo', + archive='archive', + config={'chunker_params': '19,23,21,4095'}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_recompress_flag(): + insert_execute_command_mock(('borg', 'recreate', '--recompress', 'always', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={'recompress': 'always'}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives=None, + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_match_archives_star(): + insert_execute_command_mock(('borg', 'recreate', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives='*', + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_match_archives_regex(): + insert_execute_command_mock(('borg', 'recreate', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives='re:.*', + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_match_archives_shell(): + insert_execute_command_mock(('borg', 'recreate', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives='sh:*', + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_glob_archives_flag(): + insert_execute_command_mock(('borg', 'recreate', '--glob-archives', 'foo-*', 'repo::archive')) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='1.2.3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives='foo-*', + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + ) + + +def test_recreate_with_match_archives_flag(): + insert_execute_command_mock( + ('borg', 'recreate', '--match-archives', 'sh:foo-*', '--repo', 'repo', 'archive') + ) + + module.recreate_archive( + repository='repo', + archive='archive', + config={}, + local_borg_version='2.0.0b3', + recreate_arguments=flexmock( + list=None, + target=None, + comment=None, + timestamp=None, + match_archives='sh:foo-*', + ), + global_arguments=flexmock(dry_run=False, log_json=False), + local_path='borg', + patterns=None, + )