31 cache_invalidation_state,
32 _dynamic_config_defaults_storage,
33 config_service_defaults,
34 dynamic_config_changelog,
35 _dynconf_load_json_cached,
37) -> dynconf.DynamicConfig:
39 Fixture that allows to control dynamic config values used by the service.
43 @snippet core/functional_tests/basic_chaos/tests-nonchaos/handlers/test_log_request_headers.py dynamic_config usage
45 Example with @ref kill_switches "kill switches":
47 @snippet core/functional_tests/dynamic_configs/tests/test_examples.py dynamic_config usage with kill switches
49 HTTP and gRPC client requests call `update_server_state` automatically before each request.
51 For main dynamic config documentation:
53 @see @ref dynamic_config_testsuite
55 See also other related fixtures:
56 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "config_service_defaults"
57 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "dynamic_config_fallback_patch"
58 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "mock_configs_service"
60 @ingroup userver_testsuite_fixtures
63 initial_values=config_service_defaults,
64 defaults=_dynamic_config_defaults_storage.snapshot,
65 config_cache_components=dynconf_cache_names,
66 cache_invalidation_state=cache_invalidation_state,
67 changelog=dynamic_config_changelog,
70 with dynamic_config_changelog.rollback(config_service_defaults):
72 for path
in reversed(list(search_path(
'config.json'))):
73 values = _dynconf_load_json_cached(path)
74 updates.update(values)
75 for marker
in request.node.iter_markers(
'config'):
76 value_update_kwargs = {
77 key: value
for key, value
in marker.kwargs.items()
if value
is not dynconf.USE_STATIC_DEFAULT
79 value_updates_json = object_substitute(value_update_kwargs)
80 updates.update(value_updates_json)
81 config.set_values_unsafe(updates)
83 kill_switches_disabled = []
84 for marker
in request.node.iter_markers(
'config'):
85 kill_switches_disabled.extend(
86 key
for key, value
in marker.kwargs.items()
if value
is dynconf.USE_STATIC_DEFAULT
88 config.switch_to_static_default(*kill_switches_disabled)
96def pytest_configure(config):
97 config.addinivalue_line(
99 'config: per-test dynamic config values',
101 config.addinivalue_line(
103 'disable_config_check: disable config mark keys check',
110@pytest.fixture(scope='session')
157 config_fallback_path,
158 dynamic_config_fallback_patch,
159) -> dynconf.ConfigValuesDict:
161 Fixture that returns default values for dynamic config. You may override
162 it in your local conftest.py or fixture:
165 @pytest.fixture(scope='session')
166 def config_service_defaults():
167 with open('defaults.json') as fp:
171 @ingroup userver_testsuite_fixtures
173 if not config_fallback_path:
174 return dynamic_config_fallback_patch
176 if pathlib.Path(config_fallback_path).exists():
177 with open(config_fallback_path,
'r', encoding=
'utf-8')
as file:
178 fallback = json.load(file)
179 fallback.update(dynamic_config_fallback_patch)
183 'Invalid path specified in config_fallback_path fixture. '
184 'Probably invalid path was passed in --config-fallback pytest option.',
188@dataclasses.dataclass(frozen=False)
190 snapshot: dynconf.ConfigValuesDict |
None
192 async def update(self, client, dynamic_config) -> None:
194 defaults = await client.get_dynamic_config_defaults()
195 if not isinstance(defaults, dict):
199 dynamic_config._defaults = defaults
210@pytest.fixture(scope='session')
218 Returns a function that adjusts the static configuration file for
220 Sets `dynamic-config.fs-cache-path` to a file that is reset after the tests
221 to avoid leaking dynamic config values between test sessions.
223 @ingroup userver_testsuite_fixtures
226 def patch_config(config, _config_vars) -> None:
227 components = config[
'components_manager'][
'components']
228 dynamic_config_component = components.get(
'dynamic-config',
None)
or {}
229 if dynamic_config_component.get(
'fs-cache-path',
'') ==
'':
232 cache_path = service_tmpdir /
'configs' /
'config_cache.json'
234 if cache_path.is_file():
238 dynamic_config_component[
'fs-cache-path'] = str(cache_path)
243@pytest.fixture(scope='session')
246 Returns a function that adjusts the static configuration file for
248 Removes `dynamic-config.defaults-path`.
249 Updates `dynamic-config.defaults` with `config_service_defaults`.
251 @ingroup userver_testsuite_fixtures
254 def extract_defaults_dict(component_config, config_vars) -> dict:
255 defaults_field = component_config.get(
'defaults',
None)
or {}
256 if isinstance(defaults_field, dict):
257 return defaults_field
258 elif isinstance(defaults_field, str):
259 if defaults_field.startswith(
'$'):
260 return config_vars.get(defaults_field[1:], {})
261 assert False, f
'Unexpected static config option `dynamic-config.defaults`: {defaults_field!r}'
263 def _patch_config(config_yaml, config_vars):
264 components = config_yaml[
'components_manager'][
'components']
265 if components.get(
'dynamic-config',
None)
is None:
266 components[
'dynamic-config'] = {}
267 dynconf_component = components[
'dynamic-config']
269 dynconf_component.pop(
'defaults-path',
None)
271 extract_defaults_dict(dynconf_component, config_vars),
272 **config_service_defaults,
274 dynconf_component[
'defaults'] = defaults
279@pytest.fixture(scope='session')
318 dynamic_config: dynconf.DynamicConfig,
322 Adds a mockserver handler that forwards dynamic_config to service's
323 `dynamic-config-client` component.
325 @ingroup userver_testsuite_fixtures
328 @mockserver.json_handler('/configs-service/configs/values')
329 def _mock_configs(request):
330 updates = dynamic_config_changelog.get_updated_since(
331 dynconf._create_config_dict(
332 dynamic_config.get_values_unsafe(),
333 dynamic_config.get_kill_switches_disabled_unsafe(),
335 request.json.get(
'updated_since',
''),
336 request.json.get(
'ids'),
338 response = {
'configs': updates.values,
'updated_at': updates.timestamp}
340 response[
'removed'] = updates.removed
341 if updates.kill_switches_disabled:
342 response[
'kill_switches_disabled'] = updates.kill_switches_disabled
345 @mockserver.json_handler('/configs-service/configs/status')
346 def _mock_configs_status(_request):
348 'updated_at': dynamic_config_changelog.timestamp.strftime(
349 '%Y-%m-%dT%H:%M:%SZ',