mirror of
https://github.com/borgmatic-collective/borgmatic.git
synced 2026-08-03 15:03:02 +02:00
When a configuration include is a relative path, load it from either the current working directory or from the directory containing the file doing the including (#532).
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import io
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
@@ -14,49 +15,133 @@ def test_load_configuration_parses_contents():
|
||||
assert module.load_configuration('config.yaml') == {'key': 'value'}
|
||||
|
||||
|
||||
def test_load_configuration_inlines_include():
|
||||
def test_load_configuration_inlines_include_relative_to_current_directory():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('include.yaml').and_return('value')
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(
|
||||
'key: !include include.yaml'
|
||||
)
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
include_file = io.StringIO('value')
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/tmp/include.yaml').and_return(include_file)
|
||||
config_file = io.StringIO('key: !include include.yaml')
|
||||
config_file.name = 'config.yaml'
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
|
||||
|
||||
assert module.load_configuration('config.yaml') == {'key': 'value'}
|
||||
|
||||
|
||||
def test_load_configuration_inlines_include_relative_to_config_parent_directory():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('/etc').and_return(True)
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('/etc/config.yaml').and_return(True)
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('include.yaml').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').with_args('/tmp/include.yaml').and_return(
|
||||
False
|
||||
)
|
||||
flexmock(module.os.path).should_receive('exists').with_args('/etc/include.yaml').and_return(
|
||||
True
|
||||
)
|
||||
include_file = io.StringIO('value')
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/etc/include.yaml').and_return(include_file)
|
||||
config_file = io.StringIO('key: !include include.yaml')
|
||||
config_file.name = '/etc/config.yaml'
|
||||
builtins.should_receive('open').with_args('/etc/config.yaml').and_return(config_file)
|
||||
|
||||
assert module.load_configuration('/etc/config.yaml') == {'key': 'value'}
|
||||
|
||||
|
||||
def test_load_configuration_raises_if_relative_include_does_not_exist():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('/etc').and_return(True)
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('/etc/config.yaml').and_return(True)
|
||||
flexmock(module.os.path).should_receive('isabs').with_args('include.yaml').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(False)
|
||||
config_file = io.StringIO('key: !include include.yaml')
|
||||
config_file.name = '/etc/config.yaml'
|
||||
builtins.should_receive('open').with_args('/etc/config.yaml').and_return(config_file)
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
module.load_configuration('/etc/config.yaml')
|
||||
|
||||
|
||||
def test_load_configuration_inlines_absolute_include():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(True)
|
||||
flexmock(module.os.path).should_receive('exists').never()
|
||||
include_file = io.StringIO('value')
|
||||
include_file.name = '/root/include.yaml'
|
||||
builtins.should_receive('open').with_args('/root/include.yaml').and_return(include_file)
|
||||
config_file = io.StringIO('key: !include /root/include.yaml')
|
||||
config_file.name = 'config.yaml'
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
|
||||
|
||||
assert module.load_configuration('config.yaml') == {'key': 'value'}
|
||||
|
||||
|
||||
def test_load_configuration_raises_if_absolute_include_does_not_exist():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(True)
|
||||
builtins.should_receive('open').with_args('/root/include.yaml').and_raise(FileNotFoundError)
|
||||
config_file = io.StringIO('key: !include /root/include.yaml')
|
||||
config_file.name = 'config.yaml'
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
assert module.load_configuration('config.yaml')
|
||||
|
||||
|
||||
def test_load_configuration_merges_include():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('include.yaml').and_return(
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
include_file = io.StringIO(
|
||||
'''
|
||||
foo: bar
|
||||
baz: quux
|
||||
'''
|
||||
)
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/tmp/include.yaml').and_return(include_file)
|
||||
config_file = io.StringIO(
|
||||
'''
|
||||
foo: override
|
||||
<<: !include include.yaml
|
||||
'''
|
||||
)
|
||||
config_file.name = 'config.yaml'
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
|
||||
|
||||
assert module.load_configuration('config.yaml') == {'foo': 'override', 'baz': 'quux'}
|
||||
|
||||
|
||||
def test_load_configuration_does_not_merge_include_list():
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('include.yaml').and_return(
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
include_file = io.StringIO(
|
||||
'''
|
||||
- one
|
||||
- two
|
||||
'''
|
||||
)
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/tmp/include.yaml').and_return(include_file)
|
||||
config_file = io.StringIO(
|
||||
'''
|
||||
foo: bar
|
||||
repositories:
|
||||
<<: !include include.yaml
|
||||
'''
|
||||
)
|
||||
config_file.name = 'config.yaml'
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_file)
|
||||
|
||||
with pytest.raises(ruamel.yaml.error.YAMLError):
|
||||
assert module.load_configuration('config.yaml')
|
||||
|
||||
@@ -21,14 +21,20 @@ def mock_config_and_schema(config_yaml, schema_yaml=None):
|
||||
when parsing the configuration.
|
||||
'''
|
||||
config_stream = io.StringIO(config_yaml)
|
||||
config_stream.name = 'config.yaml'
|
||||
|
||||
if schema_yaml is None:
|
||||
schema_stream = open(module.schema_filename())
|
||||
else:
|
||||
schema_stream = io.StringIO(schema_yaml)
|
||||
schema_stream.name = 'schema.yaml'
|
||||
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('config.yaml').and_return(config_stream)
|
||||
builtins.should_receive('open').with_args('schema.yaml').and_return(schema_stream)
|
||||
flexmock(module.os).should_receive('getcwd').and_return('/tmp')
|
||||
flexmock(module.os.path).should_receive('isabs').and_return(False)
|
||||
flexmock(module.os.path).should_receive('exists').and_return(True)
|
||||
builtins.should_receive('open').with_args('/tmp/config.yaml').and_return(config_stream)
|
||||
builtins.should_receive('open').with_args('/tmp/schema.yaml').and_return(schema_stream)
|
||||
|
||||
|
||||
def test_parse_configuration_transforms_file_into_mapping():
|
||||
@@ -54,7 +60,7 @@ def test_parse_configuration_transforms_file_into_mapping():
|
||||
'''
|
||||
)
|
||||
|
||||
result = module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
result = module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
assert result == {
|
||||
'location': {'source_directories': ['/home', '/etc'], 'repositories': ['hostname.borg']},
|
||||
@@ -79,7 +85,7 @@ def test_parse_configuration_passes_through_quoted_punctuation():
|
||||
)
|
||||
)
|
||||
|
||||
result = module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
result = module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
assert result == {
|
||||
'location': {
|
||||
@@ -115,7 +121,7 @@ def test_parse_configuration_with_schema_lacking_examples_does_not_raise():
|
||||
''',
|
||||
)
|
||||
|
||||
module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
|
||||
def test_parse_configuration_inlines_include():
|
||||
@@ -133,14 +139,16 @@ def test_parse_configuration_inlines_include():
|
||||
'''
|
||||
)
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('include.yaml').and_return(
|
||||
include_file = io.StringIO(
|
||||
'''
|
||||
keep_daily: 7
|
||||
keep_hourly: 24
|
||||
'''
|
||||
)
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/tmp/include.yaml').and_return(include_file)
|
||||
|
||||
result = module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
result = module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
assert result == {
|
||||
'location': {'source_directories': ['/home'], 'repositories': ['hostname.borg']},
|
||||
@@ -164,14 +172,16 @@ def test_parse_configuration_merges_include():
|
||||
'''
|
||||
)
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('include.yaml').and_return(
|
||||
include_file = io.StringIO(
|
||||
'''
|
||||
keep_daily: 7
|
||||
keep_hourly: 24
|
||||
'''
|
||||
)
|
||||
include_file.name = 'include.yaml'
|
||||
builtins.should_receive('open').with_args('/tmp/include.yaml').and_return(include_file)
|
||||
|
||||
result = module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
result = module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
assert result == {
|
||||
'location': {'source_directories': ['/home'], 'repositories': ['hostname.borg']},
|
||||
@@ -181,23 +191,23 @@ def test_parse_configuration_merges_include():
|
||||
|
||||
def test_parse_configuration_raises_for_missing_config_file():
|
||||
with pytest.raises(FileNotFoundError):
|
||||
module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
|
||||
def test_parse_configuration_raises_for_missing_schema_file():
|
||||
mock_config_and_schema('')
|
||||
builtins = flexmock(sys.modules['builtins'])
|
||||
builtins.should_receive('open').with_args('schema.yaml').and_raise(FileNotFoundError)
|
||||
builtins.should_receive('open').with_args('/tmp/schema.yaml').and_raise(FileNotFoundError)
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
|
||||
def test_parse_configuration_raises_for_syntax_error():
|
||||
mock_config_and_schema('foo:\nbar')
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
|
||||
def test_parse_configuration_raises_for_validation_error():
|
||||
@@ -211,7 +221,7 @@ def test_parse_configuration_raises_for_validation_error():
|
||||
)
|
||||
|
||||
with pytest.raises(module.Validation_error):
|
||||
module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
|
||||
def test_parse_configuration_applies_overrides():
|
||||
@@ -229,7 +239,7 @@ def test_parse_configuration_applies_overrides():
|
||||
)
|
||||
|
||||
result = module.parse_configuration(
|
||||
'config.yaml', 'schema.yaml', overrides=['location.local_path=borg2']
|
||||
'/tmp/config.yaml', '/tmp/schema.yaml', overrides=['location.local_path=borg2']
|
||||
)
|
||||
|
||||
assert result == {
|
||||
@@ -255,7 +265,7 @@ def test_parse_configuration_applies_normalization():
|
||||
'''
|
||||
)
|
||||
|
||||
result = module.parse_configuration('config.yaml', 'schema.yaml')
|
||||
result = module.parse_configuration('/tmp/config.yaml', '/tmp/schema.yaml')
|
||||
|
||||
assert result == {
|
||||
'location': {
|
||||
|
||||
Reference in New Issue
Block a user