Coverage for mlos_bench/mlos_bench/tests/services/config_persistence_test.py: 100%
60 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-21 01:50 +0000
1#
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4#
5"""Unit tests for configuration persistence service."""
7import os
8from importlib.resources import files
10import pytest
12from mlos_bench.config.schemas import ConfigSchema
13from mlos_bench.services.config_persistence import ConfigPersistenceService
14from mlos_bench.util import path_join
16# pylint: disable=redefined-outer-name
19@pytest.fixture
20def config_persistence_service() -> ConfigPersistenceService:
21 """Test fixture for ConfigPersistenceService."""
22 return ConfigPersistenceService(
23 {
24 "config_path": [
25 "./non-existent-dir/test/foo/bar", # Non-existent config path
26 ".", # cwd
27 str(
28 files("mlos_bench.tests.config").joinpath("")
29 ), # Test configs (relative to mlos_bench/tests)
30 # Shouldn't be necessary since we automatically add this.
31 # str(files("mlos_bench.config").joinpath("")), # Stock configs
32 ]
33 }
34 )
37def test_cwd_in_explicit_search_path(config_persistence_service: ConfigPersistenceService) -> None:
38 """Check that CWD is in the search path in the correct place."""
39 # pylint: disable=protected-access
40 assert config_persistence_service._config_path is not None
41 cwd = path_join(os.getcwd(), abs_path=True)
42 assert config_persistence_service._config_path.index(cwd) == 1
43 with pytest.raises(ValueError):
44 config_persistence_service._config_path.index(cwd, 2)
47def test_cwd_in_default_search_path() -> None:
48 """Checks that the CWD is prepended to the search path if not explicitly present."""
49 # pylint: disable=protected-access
50 config_persistence_service = ConfigPersistenceService()
51 assert config_persistence_service._config_path is not None
52 cwd = path_join(os.getcwd(), abs_path=True)
53 assert config_persistence_service._config_path.index(cwd) == 0
54 with pytest.raises(ValueError):
55 config_persistence_service._config_path.index(cwd, 1)
58def test_resolve_stock_path(config_persistence_service: ConfigPersistenceService) -> None:
59 """Check if we can actually find a file somewhere in `config_path`."""
60 # pylint: disable=protected-access
61 assert config_persistence_service._config_path is not None
62 assert ConfigPersistenceService.BUILTIN_CONFIG_PATH in config_persistence_service._config_path
63 file_path = "storage/in-memory.jsonc"
64 path = config_persistence_service.resolve_path(file_path)
65 assert path.endswith(file_path)
66 assert os.path.exists(path)
67 assert os.path.samefile(
68 ConfigPersistenceService.BUILTIN_CONFIG_PATH,
69 os.path.commonpath([ConfigPersistenceService.BUILTIN_CONFIG_PATH, path]),
70 )
73def test_resolve_path(config_persistence_service: ConfigPersistenceService) -> None:
74 """Check if we can actually find a file somewhere in `config_path`."""
75 file_path = "tunable-values/tunable-values-example.jsonc"
76 path = config_persistence_service.resolve_path(file_path)
77 assert path.endswith(file_path)
78 assert os.path.exists(path)
81def test_resolve_path_fail(config_persistence_service: ConfigPersistenceService) -> None:
82 """Check if non-existent file resolves without using `config_path`."""
83 file_path = "foo/non-existent-config.json"
84 path = config_persistence_service.resolve_path(file_path)
85 assert not os.path.exists(path)
86 assert path == file_path
89def test_load_config(config_persistence_service: ConfigPersistenceService) -> None:
90 """Check if we can successfully load a config file located relative to
91 `config_path`.
92 """
93 tunables_data = config_persistence_service.load_config(
94 "tunable-values/tunable-values-example.jsonc",
95 ConfigSchema.TUNABLE_VALUES,
96 )
97 assert tunables_data is not None
98 assert isinstance(tunables_data, dict)
99 assert len(tunables_data) >= 1
102def test_load_bad_config_path(config_persistence_service: ConfigPersistenceService) -> None:
103 """Check if we can successfully load a config file located relative to
104 `config_path`.
105 """
106 with pytest.raises(FileNotFoundError) as exc_info:
107 _ = config_persistence_service.load_config(
108 "DNE/tunable-values/tunable-values-example.jsonc-DNE-}]",
109 ConfigSchema.TUNABLE_VALUES,
110 )
111 assert "No such file or directory" in str(exc_info.value)
114def test_load_config_string(config_persistence_service: ConfigPersistenceService) -> None:
115 """Check if we can load a valid json string as well."""
116 json_str = """
117 {
118 "tunable_param_1": "value_1",
119 "tunable_param_2": "value_2",
120 }
121 """
122 tunables_data = config_persistence_service.load_config(json_str, ConfigSchema.TUNABLE_VALUES)
123 assert tunables_data is not None
124 assert isinstance(tunables_data, dict)
125 assert len(tunables_data) >= 1
128def test_load_bad_config_string(config_persistence_service: ConfigPersistenceService) -> None:
129 """Check how we handle loading a bad config string."""
130 json_str = """
131 {
132 "tunable_param_1": "value_1",
133 "tunable_param_2": "value_2",
134 //} // Missing closing brace
135 """
136 with pytest.raises(ValueError) as exc_info:
137 _ = config_persistence_service.load_config(json_str, ConfigSchema.TUNABLE_VALUES)
138 assert "Failed to parse config from JSON string" in str(exc_info.value)