33 """Simple dynamic config backend."""
38 initial_values: typing.Dict[str, typing.Any],
39 config_cache_components: typing.Iterable[str],
42 self._values = copy.deepcopy(initial_values)
43 self._cache_invalidation_state = cache_invalidation_state
44 self._config_cache_components = config_cache_components
46 def set_values(self, values):
47 self._values.update(values)
48 self._sync_with_service()
51 return self._values.copy()
53 def remove_values(self, keys):
54 extra_keys = set(keys).difference(self._values.keys())
57 f
'Attempting to remove nonexistent configs: {extra_keys}',
61 self._sync_with_service()
63 def set(self, **values):
64 self.set_values(values)
66 def get(self, key, default=None):
67 if key
not in self._values:
68 if default
is not None:
71 return self._values[key]
73 def remove(self, key):
74 return self.remove_values([key])
76 def _sync_with_service(self):
77 self._cache_invalidation_state.invalidate(
78 self._config_cache_components,
88 config_service_defaults,
89 cache_invalidation_state,
92 Fixture that allows to control dynamic config values used by the service.
94 After change to the config, be sure to call:
96 await service_client.update_server_state()
99 HTTP client requests call it automatically before each request.
101 @ingroup userver_testsuite_fixtures
103 all_values = config_service_defaults.copy()
104 for path
in reversed(list(search_path(
'config.json'))):
105 values = load_json(path)
106 all_values.update(values)
107 for marker
in request.node.iter_markers(
'config'):
108 marker_json = object_substitute(marker.kwargs)
109 all_values.update(marker_json)
111 initial_values=all_values,
112 config_cache_components=_CONFIG_CACHES,
113 cache_invalidation_state=cache_invalidation_state,
144 config_fallback_path, dynamic_config_fallback_patch,
145) -> typing.Dict[str, typing.Any]:
147 Fixture that returns default values for dynamic config. You may override
148 it in your local conftest.py or fixture:
151 @pytest.fixture(scope='session')
152 def config_service_defaults():
153 with open('defaults.json') as fp:
157 @ingroup userver_testsuite_fixtures
159 if config_fallback_path
and pathlib.Path(config_fallback_path).exists():
160 with open(config_fallback_path,
'r', encoding=
'utf-8')
as file:
161 fallback = json.load(file)
162 fallback.update(dynamic_config_fallback_patch)
166 'Either provide the path to dynamic config defaults file using '
167 '--config-fallback pytest option, or override '
168 f
'{config_service_defaults.__name__} fixture to provide custom '
169 'dynamic config loading behavior.',
173@pytest.fixture(scope='session')
200 pytestconfig, config_service_defaults, service_tmpdir,
203 Returns a function that adjusts the static configuration file for
205 Sets the `fallback-path` of the `dynamic-config-client-updater` and
206 `dynamic-config-fallbacks` according to `config_service_defaults`.
208 @ingroup userver_testsuite_fixtures
211 def _patch_config(config_yaml, _config_vars):
212 components = config_yaml[
'components_manager'][
'components']
213 if not (components.keys() & _COMPONENTS_WITH_FALLBACK):
217 service_tmpdir /
'configs' /
'dynamic_config_fallback.json'
219 fallback_path.parent.mkdir(exist_ok=
True)
220 with open(fallback_path,
'w', encoding=
'utf-8')
as file:
221 json.dump(config_service_defaults, file)
223 for component_name
in _COMPONENTS_WITH_FALLBACK:
224 if component_name
not in components:
226 component = components[component_name]
227 component[
'fallback-path'] = str(fallback_path)
232@pytest.fixture(scope='session')