|
@@ -1,10 +1,221 @@
|
|
|
import sys
|
|
|
|
|
|
+import pytest
|
|
|
from flexmock import flexmock
|
|
|
|
|
|
from borgmatic.actions import create as module
|
|
|
|
|
|
|
|
|
+def test_create_borgmatic_manifest_creates_manifest_file():
|
|
|
+ flexmock(module.os.path).should_receive('join').with_args(
|
|
|
+ '/run/borgmatic', 'bootstrap', 'manifest.json'
|
|
|
+ ).and_return('/run/borgmatic/bootstrap/manifest.json')
|
|
|
+ flexmock(module.os.path).should_receive('exists').and_return(False)
|
|
|
+ flexmock(module.os).should_receive('makedirs').and_return(True)
|
|
|
+
|
|
|
+ flexmock(module.importlib.metadata).should_receive('version').and_return('1.0.0')
|
|
|
+ flexmock(sys.modules['builtins']).should_receive('open').with_args(
|
|
|
+ '/run/borgmatic/bootstrap/manifest.json', 'w'
|
|
|
+ ).and_return(
|
|
|
+ flexmock(
|
|
|
+ __enter__=lambda *args: flexmock(write=lambda *args: None, close=lambda *args: None),
|
|
|
+ __exit__=lambda *args: None,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.json).should_receive('dump').and_return(True).once()
|
|
|
+
|
|
|
+ module.create_borgmatic_manifest({}, 'test.yaml', '/run/borgmatic', False)
|
|
|
+
|
|
|
+
|
|
|
+def test_create_borgmatic_manifest_creates_manifest_file_with_custom_borgmatic_runtime_directory():
|
|
|
+ flexmock(module.os.path).should_receive('join').with_args(
|
|
|
+ '/run/borgmatic', 'bootstrap', 'manifest.json'
|
|
|
+ ).and_return('/run/borgmatic/bootstrap/manifest.json')
|
|
|
+ flexmock(module.os.path).should_receive('exists').and_return(False)
|
|
|
+ flexmock(module.os).should_receive('makedirs').and_return(True)
|
|
|
+
|
|
|
+ flexmock(module.importlib.metadata).should_receive('version').and_return('1.0.0')
|
|
|
+ flexmock(sys.modules['builtins']).should_receive('open').with_args(
|
|
|
+ '/run/borgmatic/bootstrap/manifest.json', 'w'
|
|
|
+ ).and_return(
|
|
|
+ flexmock(
|
|
|
+ __enter__=lambda *args: flexmock(write=lambda *args: None, close=lambda *args: None),
|
|
|
+ __exit__=lambda *args: None,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ flexmock(module.json).should_receive('dump').and_return(True).once()
|
|
|
+
|
|
|
+ module.create_borgmatic_manifest(
|
|
|
+ {'borgmatic_runtime_directory': '/borgmatic'}, 'test.yaml', '/run/borgmatic', False
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_create_borgmatic_manifest_does_not_create_manifest_file_on_dry_run():
|
|
|
+ flexmock(module.json).should_receive('dump').never()
|
|
|
+
|
|
|
+ module.create_borgmatic_manifest({}, 'test.yaml', '/run/borgmatic', True)
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directory_with_basic_path_passes_it_through():
|
|
|
+ flexmock(module.os.path).should_receive('expanduser').and_return('foo')
|
|
|
+ flexmock(module.glob).should_receive('glob').and_return([])
|
|
|
+
|
|
|
+ paths = module.expand_directory('foo', None)
|
|
|
+
|
|
|
+ assert paths == ['foo']
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directory_with_glob_expands():
|
|
|
+ flexmock(module.os.path).should_receive('expanduser').and_return('foo*')
|
|
|
+ flexmock(module.glob).should_receive('glob').and_return(['foo', 'food'])
|
|
|
+
|
|
|
+ paths = module.expand_directory('foo*', None)
|
|
|
+
|
|
|
+ assert paths == ['foo', 'food']
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directory_with_working_directory_passes_it_through():
|
|
|
+ flexmock(module.os.path).should_receive('expanduser').and_return('foo')
|
|
|
+ flexmock(module.glob).should_receive('glob').with_args('/working/dir/foo').and_return([]).once()
|
|
|
+
|
|
|
+ paths = module.expand_directory('foo', working_directory='/working/dir')
|
|
|
+
|
|
|
+ assert paths == ['/working/dir/foo']
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directory_with_glob_passes_through_working_directory():
|
|
|
+ flexmock(module.os.path).should_receive('expanduser').and_return('foo*')
|
|
|
+ flexmock(module.glob).should_receive('glob').with_args('/working/dir/foo*').and_return(
|
|
|
+ ['/working/dir/foo', '/working/dir/food']
|
|
|
+ ).once()
|
|
|
+
|
|
|
+ paths = module.expand_directory('foo*', working_directory='/working/dir')
|
|
|
+
|
|
|
+ assert paths == ['/working/dir/foo', '/working/dir/food']
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directories_flattens_expanded_directories():
|
|
|
+ flexmock(module).should_receive('expand_directory').with_args('~/foo', None).and_return(
|
|
|
+ ['/root/foo']
|
|
|
+ )
|
|
|
+ flexmock(module).should_receive('expand_directory').with_args('bar*', None).and_return(
|
|
|
+ ['bar', 'barf']
|
|
|
+ )
|
|
|
+
|
|
|
+ paths = module.expand_directories(('~/foo', 'bar*'))
|
|
|
+
|
|
|
+ assert paths == ('/root/foo', 'bar', 'barf')
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directories_with_working_directory_passes_it_through():
|
|
|
+ flexmock(module).should_receive('expand_directory').with_args('foo', '/working/dir').and_return(
|
|
|
+ ['/working/dir/foo']
|
|
|
+ )
|
|
|
+
|
|
|
+ paths = module.expand_directories(('foo',), working_directory='/working/dir')
|
|
|
+
|
|
|
+ assert paths == ('/working/dir/foo',)
|
|
|
+
|
|
|
+
|
|
|
+def test_expand_directories_considers_none_as_no_directories():
|
|
|
+ paths = module.expand_directories(None, None)
|
|
|
+
|
|
|
+ assert paths == ()
|
|
|
+
|
|
|
+
|
|
|
+def test_map_directories_to_devices_gives_device_id_per_path():
|
|
|
+ flexmock(module.os.path).should_receive('exists').and_return(True)
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/bar').and_return(flexmock(st_dev=66))
|
|
|
+
|
|
|
+ device_map = module.map_directories_to_devices(('/foo', '/bar'))
|
|
|
+
|
|
|
+ assert device_map == {
|
|
|
+ '/foo': 55,
|
|
|
+ '/bar': 66,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def test_map_directories_to_devices_with_missing_path_does_not_error():
|
|
|
+ flexmock(module.os.path).should_receive('exists').and_return(True).and_return(False)
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/bar').never()
|
|
|
+
|
|
|
+ device_map = module.map_directories_to_devices(('/foo', '/bar'))
|
|
|
+
|
|
|
+ assert device_map == {
|
|
|
+ '/foo': 55,
|
|
|
+ '/bar': None,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def test_map_directories_to_devices_uses_working_directory_to_construct_path():
|
|
|
+ flexmock(module.os.path).should_receive('exists').and_return(True)
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/foo').and_return(flexmock(st_dev=55))
|
|
|
+ flexmock(module.os).should_receive('stat').with_args('/working/dir/bar').and_return(
|
|
|
+ flexmock(st_dev=66)
|
|
|
+ )
|
|
|
+
|
|
|
+ device_map = module.map_directories_to_devices(
|
|
|
+ ('/foo', 'bar'), working_directory='/working/dir'
|
|
|
+ )
|
|
|
+
|
|
|
+ assert device_map == {
|
|
|
+ '/foo': 55,
|
|
|
+ 'bar': 66,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+@pytest.mark.parametrize(
|
|
|
+ 'directories,additional_directories,expected_directories',
|
|
|
+ (
|
|
|
+ ({'/': 1, '/root': 1}, {}, ['/']),
|
|
|
+ ({'/': 1, '/root/': 1}, {}, ['/']),
|
|
|
+ ({'/': 1, '/root': 2}, {}, ['/', '/root']),
|
|
|
+ ({'/root': 1, '/': 1}, {}, ['/']),
|
|
|
+ ({'/root': 1, '/root/foo': 1}, {}, ['/root']),
|
|
|
+ ({'/root/': 1, '/root/foo': 1}, {}, ['/root/']),
|
|
|
+ ({'/root': 1, '/root/foo/': 1}, {}, ['/root']),
|
|
|
+ ({'/root': 1, '/root/foo': 2}, {}, ['/root', '/root/foo']),
|
|
|
+ ({'/root/foo': 1, '/root': 1}, {}, ['/root']),
|
|
|
+ ({'/root': None, '/root/foo': None}, {}, ['/root', '/root/foo']),
|
|
|
+ ({'/root': 1, '/etc': 1, '/root/foo/bar': 1}, {}, ['/etc', '/root']),
|
|
|
+ ({'/root': 1, '/root/foo': 1, '/root/foo/bar': 1}, {}, ['/root']),
|
|
|
+ ({'/dup': 1, '/dup': 1}, {}, ['/dup']),
|
|
|
+ ({'/foo': 1, '/bar': 1}, {}, ['/bar', '/foo']),
|
|
|
+ ({'/foo': 1, '/bar': 2}, {}, ['/bar', '/foo']),
|
|
|
+ ({'/root/foo': 1}, {'/root': 1}, []),
|
|
|
+ ({'/root/foo': 1}, {'/root': 2}, ['/root/foo']),
|
|
|
+ ({'/root/foo': 1}, {}, ['/root/foo']),
|
|
|
+ ),
|
|
|
+)
|
|
|
+def test_deduplicate_directories_removes_child_paths_on_the_same_filesystem(
|
|
|
+ directories, additional_directories, expected_directories
|
|
|
+):
|
|
|
+ assert (
|
|
|
+ module.deduplicate_directories(directories, additional_directories) == expected_directories
|
|
|
+ )
|
|
|
+
|
|
|
+
|
|
|
+def test_pattern_root_directories_deals_with_none_patterns():
|
|
|
+ assert module.pattern_root_directories(patterns=None) == []
|
|
|
+
|
|
|
+
|
|
|
+def test_pattern_root_directories_parses_roots_and_ignores_others():
|
|
|
+ assert module.pattern_root_directories(
|
|
|
+ ['R /root', '+ /root/foo', '- /root/foo/bar', 'R /baz']
|
|
|
+ ) == ['/root', '/baz']
|
|
|
+
|
|
|
+
|
|
|
+# TODO
|
|
|
+# def test_process_source_directories_...
|
|
|
+# flexmock(module).should_receive('deduplicate_directories').and_return(('foo', 'bar'))
|
|
|
+# flexmock(module).should_receive('map_directories_to_devices').and_return({})
|
|
|
+# flexmock(module).should_receive('expand_directories').and_return(())
|
|
|
+# flexmock(module).should_receive('pattern_root_directories').and_return([])
|
|
|
+# ...
|
|
|
+
|
|
|
+
|
|
|
def test_run_create_executes_and_calls_hooks_for_configured_repository():
|
|
|
flexmock(module.logger).answer = lambda message: None
|
|
|
flexmock(module.borgmatic.config.validate).should_receive('repositories_match').never()
|
|
@@ -18,6 +229,8 @@ def test_run_create_executes_and_calls_hooks_for_configured_repository():
|
|
|
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
|
|
'call_hooks_even_if_unconfigured'
|
|
|
).and_return({})
|
|
|
+ flexmock(module).should_receive('process_source_directories').and_return([])
|
|
|
+ flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
|
|
|
create_arguments = flexmock(
|
|
|
repository=None,
|
|
|
progress=flexmock(),
|
|
@@ -57,6 +270,8 @@ def test_run_create_with_store_config_files_false_does_not_create_borgmatic_mani
|
|
|
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
|
|
'call_hooks_even_if_unconfigured'
|
|
|
).and_return({})
|
|
|
+ flexmock(module).should_receive('process_source_directories').and_return([])
|
|
|
+ flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
|
|
|
create_arguments = flexmock(
|
|
|
repository=None,
|
|
|
progress=flexmock(),
|
|
@@ -98,6 +313,8 @@ def test_run_create_runs_with_selected_repository():
|
|
|
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
|
|
'call_hooks_even_if_unconfigured'
|
|
|
).and_return({})
|
|
|
+ flexmock(module).should_receive('process_source_directories').and_return([])
|
|
|
+ flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
|
|
|
create_arguments = flexmock(
|
|
|
repository=flexmock(),
|
|
|
progress=flexmock(),
|
|
@@ -177,6 +394,8 @@ def test_run_create_produces_json():
|
|
|
flexmock(module.borgmatic.hooks.dispatch).should_receive(
|
|
|
'call_hooks_even_if_unconfigured'
|
|
|
).and_return({})
|
|
|
+ flexmock(module).should_receive('process_source_directories').and_return([])
|
|
|
+ flexmock(module.os.path).should_receive('join').and_return('/run/borgmatic/bootstrap')
|
|
|
create_arguments = flexmock(
|
|
|
repository=flexmock(),
|
|
|
progress=flexmock(),
|
|
@@ -201,53 +420,3 @@ def test_run_create_produces_json():
|
|
|
remote_path=None,
|
|
|
)
|
|
|
) == [parsed_json]
|
|
|
-
|
|
|
-
|
|
|
-def test_create_borgmatic_manifest_creates_manifest_file():
|
|
|
- flexmock(module.os.path).should_receive('join').with_args(
|
|
|
- '/run/borgmatic', 'bootstrap', 'manifest.json'
|
|
|
- ).and_return('/run/borgmatic/bootstrap/manifest.json')
|
|
|
- flexmock(module.os.path).should_receive('exists').and_return(False)
|
|
|
- flexmock(module.os).should_receive('makedirs').and_return(True)
|
|
|
-
|
|
|
- flexmock(module.importlib.metadata).should_receive('version').and_return('1.0.0')
|
|
|
- flexmock(sys.modules['builtins']).should_receive('open').with_args(
|
|
|
- '/run/borgmatic/bootstrap/manifest.json', 'w'
|
|
|
- ).and_return(
|
|
|
- flexmock(
|
|
|
- __enter__=lambda *args: flexmock(write=lambda *args: None, close=lambda *args: None),
|
|
|
- __exit__=lambda *args: None,
|
|
|
- )
|
|
|
- )
|
|
|
- flexmock(module.json).should_receive('dump').and_return(True).once()
|
|
|
-
|
|
|
- module.create_borgmatic_manifest({}, 'test.yaml', '/run/borgmatic', False)
|
|
|
-
|
|
|
-
|
|
|
-def test_create_borgmatic_manifest_creates_manifest_file_with_custom_borgmatic_runtime_directory():
|
|
|
- flexmock(module.os.path).should_receive('join').with_args(
|
|
|
- '/run/borgmatic', 'bootstrap', 'manifest.json'
|
|
|
- ).and_return('/run/borgmatic/bootstrap/manifest.json')
|
|
|
- flexmock(module.os.path).should_receive('exists').and_return(False)
|
|
|
- flexmock(module.os).should_receive('makedirs').and_return(True)
|
|
|
-
|
|
|
- flexmock(module.importlib.metadata).should_receive('version').and_return('1.0.0')
|
|
|
- flexmock(sys.modules['builtins']).should_receive('open').with_args(
|
|
|
- '/run/borgmatic/bootstrap/manifest.json', 'w'
|
|
|
- ).and_return(
|
|
|
- flexmock(
|
|
|
- __enter__=lambda *args: flexmock(write=lambda *args: None, close=lambda *args: None),
|
|
|
- __exit__=lambda *args: None,
|
|
|
- )
|
|
|
- )
|
|
|
- flexmock(module.json).should_receive('dump').and_return(True).once()
|
|
|
-
|
|
|
- module.create_borgmatic_manifest(
|
|
|
- {'borgmatic_runtime_directory': '/borgmatic'}, 'test.yaml', '/run/borgmatic', False
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
-def test_create_borgmatic_manifest_does_not_create_manifest_file_on_dry_run():
|
|
|
- flexmock(module.json).should_receive('dump').never()
|
|
|
-
|
|
|
- module.create_borgmatic_manifest({}, 'test.yaml', '/run/borgmatic', True)
|