Skip to content

Commit dca2152

Browse files
add tests for multiple west config files
Verify that multiple config files can be specified in the according environment variable (WEST_CONFIG_SYSTEM, WEST_CONFIG_GLOBAL, WEST_CONFIG_LOCAL) for each config level.
1 parent a5295e7 commit dca2152

File tree

1 file changed

+122
-1
lines changed

1 file changed

+122
-1
lines changed

tests/test_config.py

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from typing import Any
1010

1111
import pytest
12-
from conftest import chdir, cmd, cmd_raises, update_env
12+
from conftest import WINDOWS, chdir, cmd, cmd_raises, tmp_west_topdir, update_env
1313

1414
from west import configuration as config
1515
from west.util import PathType, WestNotFound
@@ -614,6 +614,127 @@ def test_config_precedence():
614614
assert cfg(f=LOCAL)['pytest']['precedence'] == 'local'
615615

616616

617+
def test_config_multiple(config_tmpdir):
618+
# Verify that local settings take precedence over global ones,
619+
# but that both values are still available, and that setting
620+
# either doesn't affect system settings.
621+
def write_config(config_file, section, key1, value1, key2, value2):
622+
config_file.parent.mkdir(exist_ok=True)
623+
624+
content = textwrap.dedent(f'''
625+
[{section}]
626+
{key1} = {value1}
627+
{key2} = {value2}
628+
''')
629+
630+
with open(config_file, 'w') as conf:
631+
conf.write(content)
632+
633+
# config file paths
634+
config_dir = pathlib.Path(config_tmpdir) / 'configs'
635+
config_s1 = config_dir / 'system 1'
636+
config_s2 = config_dir / 'system 2'
637+
config_g1 = config_dir / 'global 1'
638+
config_g2 = config_dir / 'global 2'
639+
config_l1 = config_dir / 'local 1'
640+
config_l2 = config_dir / 'local 2'
641+
642+
# create some configs with
643+
# - some individual option per config file
644+
# - the same option defined in multiple configs
645+
write_config(config_s1, 'sec', 's', '1 !"$&/()=?', 's1', '1 !"$&/()=?')
646+
write_config(config_s2, 'sec', 's', '2', 's2', '2')
647+
write_config(config_g1, 'sec', 'g', '1', 'g1', '1')
648+
write_config(config_g2, 'sec', 'g', '2', 'g2', '2')
649+
write_config(config_l1, 'sec', 'l', '1', 'l1', '1')
650+
write_config(config_l2, 'sec', 'l', '2', 'l2', '2')
651+
652+
# use a non-readable config file (does not work on Windows)
653+
if not WINDOWS:
654+
config_non_readable = config_dir / 'non-readable'
655+
config_non_readable.touch()
656+
config_non_readable.chmod(0o000)
657+
os.environ["WEST_CONFIG_GLOBAL"] = f'{config_g1}{os.pathsep}{config_non_readable}'
658+
_, stderr = cmd_raises('config --global some.section', WestNotFound)
659+
expected = f"Error while reading one of '{[config_g1, config_non_readable]}'"
660+
assert expected in stderr
661+
662+
# specify multiple configs for each config level (separated by os.pathsep)
663+
os.environ["WEST_CONFIG_GLOBAL"] = f'{config_g1}{os.pathsep}{config_g2}'
664+
os.environ["WEST_CONFIG_SYSTEM"] = f'{config_s1}{os.pathsep}{config_s2}'
665+
os.environ["WEST_CONFIG_LOCAL"] = f'{config_l1}{os.pathsep}{config_l2}'
666+
667+
# check that all individual options are applied
668+
stdout = cmd('config --system sec.s1').rstrip()
669+
assert stdout == '1 !"$&/()=?'
670+
stdout = cmd('config --system sec.s2').rstrip()
671+
assert stdout == '2'
672+
stdout = cmd('config --global sec.g1').rstrip()
673+
assert stdout == '1'
674+
stdout = cmd('config --global sec.g2').rstrip()
675+
assert stdout == '2'
676+
stdout = cmd('config --local sec.l1').rstrip()
677+
assert stdout == '1'
678+
stdout = cmd('config --local sec.l2').rstrip()
679+
assert stdout == '2'
680+
681+
# check that options from latest config overrides
682+
stdout = cmd('config --system sec.s').rstrip()
683+
assert stdout == '2'
684+
stdout = cmd('config --global sec.g').rstrip()
685+
assert stdout == '2'
686+
stdout = cmd('config --local sec.l').rstrip()
687+
assert stdout == '2'
688+
689+
# check that list-paths gives correct output
690+
stdout = cmd('config --global --list-paths')
691+
assert [str(config_g1), str(config_g2)] == stdout.rstrip().splitlines()
692+
stdout = cmd('config --system --list-paths')
693+
assert [str(config_s1), str(config_s2)] == stdout.rstrip().splitlines()
694+
stdout = cmd('config --local --list-paths')
695+
assert [str(config_l1), str(config_l2)] == stdout.rstrip().splitlines()
696+
697+
# writing not possible if multiple configs are used
698+
_, stderr = cmd_raises('config --local sec.l3 3', ValueError)
699+
assert f'Cannot set value if multiple configs in use: {[config_l1, config_l2]}' in stderr
700+
701+
# specify multiple configs for each config level (separated by os.pathsep).
702+
# The paths may be relative relative paths, which are always anchored to
703+
# west topdir. For the test, the cwd is changed to another cwd to ensure
704+
# that relative paths are anchored correctly.
705+
# - Step 1: if no west topdir exists it should fail as relative path
706+
# cannot be resolved
707+
# - Step 2: relative paths are correctly resolved (anchored to west topdir)
708+
msg = "'{file}' is relative but 'west topdir' is not defined"
709+
cwd = pathlib.Path('any cwd')
710+
cwd.mkdir()
711+
with chdir(cwd):
712+
config_rel = pathlib.Path('configs') / 'global 2'
713+
with update_env({'WEST_CONFIG_GLOBAL': f'{config_g1}{os.pathsep}{config_rel}'}):
714+
command = 'config --global --list-paths'
715+
exc, _ = cmd_raises(command, WestNotFound)
716+
assert msg.format(file=config_rel) in str(exc.value)
717+
with tmp_west_topdir('..'):
718+
stdout = cmd(command)
719+
assert [str(config_g1), str(config_g2)] == stdout.rstrip().splitlines()
720+
config_rel = pathlib.Path('configs') / 'system 2'
721+
with update_env({'WEST_CONFIG_SYSTEM': f'{config_s1}{os.pathsep}{config_rel}'}):
722+
command = 'config --system --list-paths'
723+
exc, _ = cmd_raises(command, WestNotFound)
724+
assert msg.format(file=config_rel) in str(exc.value)
725+
with tmp_west_topdir('..'):
726+
stdout = cmd(command)
727+
assert [str(config_s1), str(config_s2)] == stdout.rstrip().splitlines()
728+
config_rel = pathlib.Path('configs') / 'local 2'
729+
with update_env({'WEST_CONFIG_LOCAL': f'{config_l1}{os.pathsep}{config_rel}'}):
730+
command = 'config --local --list-paths'
731+
exc, _ = cmd_raises(command, WestNotFound)
732+
assert msg.format(file=config_rel) in str(exc.value)
733+
with tmp_west_topdir('..'):
734+
stdout = cmd(command)
735+
assert [str(config_l1), str(config_l2)] == stdout.rstrip().splitlines()
736+
737+
617738
def test_config_missing_key():
618739
_, err_msg = cmd_raises('config pytest', SystemExit)
619740
assert 'invalid configuration option "pytest"; expected "section.key" format' in err_msg

0 commit comments

Comments
 (0)