Explorar el Código

Guard that the given repository occurs in config exactly once.

Dan Helfman hace 6 años
padre
commit
766a03375a

+ 1 - 2
borgmatic/commands/borgmatic.py

@@ -403,8 +403,7 @@ def collect_configuration_run_summary_logs(config_filenames, args):
             )
             yield logging.makeLogRecord(dict(levelno=logging.CRITICAL, msg=error))
 
-    # TODO: What to do if the given repository doesn't match any configured repositories (across all config
-    # files)? Where to validate and error on that?
+    validate.guard_configuration_contains_repository(args.repository, configs)
 
     for config_filename, config in configs.items():
         try:

+ 26 - 0
borgmatic/config/validate.py

@@ -107,3 +107,29 @@ def parse_configuration(config_filename, schema_filename):
     apply_logical_validation(config_filename, parsed_result)
 
     return parsed_result
+
+
+def guard_configuration_contains_repository(repository, configurations):
+    '''
+    Given a repository path and a dict mapping from config filename to corresponding parsed config
+    dict, ensure that the repository is declared exactly once in all of the configurations.
+
+    Raise ValueError if the repository is not found in a configuration, or is declared multiple
+    times.
+    '''
+    if not repository:
+        return
+
+    count = len(
+        tuple(
+            config_repository
+            for config in configurations.values()
+            for config_repository in config['repositories']
+            if repository == config_repository
+        )
+    )
+
+    if count == 0:
+        raise ValueError('Repository {} not found in configuration files'.format(repository))
+    if count > 1:
+        raise ValueError('Repository {} found in multiple configuration files'.format(repository))

+ 13 - 9
tests/unit/commands/test_borgmatic.py

@@ -49,38 +49,42 @@ def test_run_commands_handles_multiple_json_outputs_in_array():
 
 def test_collect_configuration_run_summary_logs_info_for_success():
     flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
+    flexmock(module.validate).should_receive('guard_configuration_contains_repository')
     flexmock(module).should_receive('run_configuration')
+    args = flexmock(repository=None)
 
-    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=()))
+    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
 
     assert any(log for log in logs if log.levelno == module.logging.INFO)
 
 
 def test_collect_configuration_run_summary_logs_critical_for_parse_error():
     flexmock(module.validate).should_receive('parse_configuration').and_raise(ValueError)
-    flexmock(module).should_receive('run_configuration')
+    flexmock(module.validate).should_receive('guard_configuration_contains_repository')
+    args = flexmock(repository=None)
 
-    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=()))
+    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
 
     assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
 
 
 def test_collect_configuration_run_summary_logs_critical_for_run_error():
     flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
+    flexmock(module.validate).should_receive('guard_configuration_contains_repository')
     flexmock(module).should_receive('run_configuration').and_raise(ValueError)
+    args = flexmock(repository=None)
 
-    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=()))
+    logs = tuple(module.collect_configuration_run_summary_logs(('test.yaml',), args=args))
 
     assert any(log for log in logs if log.levelno == module.logging.CRITICAL)
 
 
 def test_collect_configuration_run_summary_logs_critical_for_missing_configs():
     flexmock(module.validate).should_receive('parse_configuration').and_return({'test.yaml': {}})
+    flexmock(module.validate).should_receive('guard_configuration_contains_repository')
+    flexmock(module).should_receive('run_configuration')
+    args = flexmock(config_paths=(), repository=None)
 
-    logs = tuple(
-        module.collect_configuration_run_summary_logs(
-            config_filenames=(), args=flexmock(config_paths=())
-        )
-    )
+    logs = tuple(module.collect_configuration_run_summary_logs(config_filenames=(), args=args))
 
     assert any(log for log in logs if log.levelno == module.logging.CRITICAL)

+ 30 - 0
tests/unit/config/test_validate.py

@@ -90,3 +90,33 @@ def test_apply_logical_validation_does_not_raise_or_warn_if_archive_name_format_
 
 def test_apply_logical_validation_does_not_raise_otherwise():
     module.apply_logical_validation('config.yaml', {'retention': {'keep_secondly': 1000}})
+
+
+def test_guard_configuration_contains_repository_does_not_raise_when_repository_in_config():
+    module.guard_configuration_contains_repository(
+        repository='repo', configurations={'config.yaml': {'repositories': ['repo']}}
+    )
+
+
+def test_guard_configuration_contains_repository_does_not_raise_when_repository_not_given():
+    module.guard_configuration_contains_repository(
+        repository=None, configurations={'config.yaml': {'repositories': ['repo']}}
+    )
+
+
+def test_guard_configuration_contains_repository_errors_when_repository_missing_from_config():
+    with pytest.raises(ValueError):
+        module.guard_configuration_contains_repository(
+            repository='nope', configurations={'config.yaml': {'repositories': ['repo', 'repo2']}}
+        )
+
+
+def test_guard_configuration_contains_repository_errors_when_repository_matches_config_twice():
+    with pytest.raises(ValueError):
+        module.guard_configuration_contains_repository(
+            repository='repo',
+            configurations={
+                'config.yaml': {'repositories': ['repo', 'repo2']},
+                'other.yaml': {'repositories': ['repo']},
+            },
+        )