32 cache_invalidation_state,
33 _dynamic_config_defaults_storage,
34 config_service_defaults,
35 dynamic_config_changelog,
36 _dynconf_load_json_cached,
38) -> dynconf.DynamicConfig:
40 Fixture that allows to control dynamic config values used by the service.
44 @snippet core/functional_tests/basic_chaos/tests-nonchaos/handlers/test_log_request_headers.py dynamic_config usage
46 Example with @ref kill_switches "kill switches":
48 @snippet core/functional_tests/dynamic_configs/tests/test_examples.py dynamic_config usage with kill switches
50 HTTP and gRPC client requests call `update_server_state` automatically before each request.
52 For main dynamic config documentation:
54 @see @ref dynamic_config_testsuite
56 See also other related fixtures:
57 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "config_service_defaults"
58 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "dynamic_config_fallback_patch"
59 * @ref pytest_userver.plugins.dynamic_config.dynamic_config "mock_configs_service"
61 @ingroup userver_testsuite_fixtures
64 initial_values=config_service_defaults,
65 defaults=_dynamic_config_defaults_storage.snapshot,
66 config_cache_components=dynconf_cache_names,
67 cache_invalidation_state=cache_invalidation_state,
68 changelog=dynamic_config_changelog,
71 with dynamic_config_changelog.rollback(config_service_defaults):
73 for path
in reversed(list(search_path(
'config.json'))):
74 values = _dynconf_load_json_cached(path)
75 updates.update(values)
76 for marker
in request.node.iter_markers(
'config'):
77 value_update_kwargs = {
78 key: value
for key, value
in marker.kwargs.items()
if value
is not dynconf.USE_STATIC_DEFAULT
80 value_updates_json = object_substitute(value_update_kwargs)
81 updates.update(value_updates_json)
82 config.set_values_unsafe(updates)
84 kill_switches_disabled = []
85 for marker
in request.node.iter_markers(
'config'):
86 kill_switches_disabled.extend(
87 key
for key, value
in marker.kwargs.items()
if value
is dynconf.USE_STATIC_DEFAULT
89 config.switch_to_static_default(*kill_switches_disabled)
97def pytest_configure(config):
98 config.addinivalue_line(
100 'config: per-test dynamic config values',
102 config.addinivalue_line(
104 'disable_config_check: disable config mark keys check',
111@pytest.fixture(scope='session')
158 config_fallback_path,
159 dynamic_config_fallback_patch,
160) -> dynconf.ConfigValuesDict:
162 Fixture that returns default values for dynamic config. You may override
163 it in your local conftest.py or fixture:
166 @pytest.fixture(scope='session')
167 def config_service_defaults():
168 with open('defaults.json') as fp:
172 @ingroup userver_testsuite_fixtures
174 if not config_fallback_path:
175 return dynamic_config_fallback_patch
177 if pathlib.Path(config_fallback_path).exists():
178 with open(config_fallback_path,
'r', encoding=
'utf-8')
as file:
179 fallback = json.load(file)
180 fallback.update(dynamic_config_fallback_patch)
184 'Invalid path specified in config_fallback_path fixture. '
185 'Probably invalid path was passed in --config-fallback pytest option.',
189@dataclasses.dataclass(frozen=False)
191 snapshot: Optional[dynconf.ConfigValuesDict]
193 async def update(self, client, dynamic_config) -> None:
195 defaults = await client.get_dynamic_config_defaults()
196 if not isinstance(defaults, dict):
200 dynamic_config._defaults = defaults
211@pytest.fixture(scope='session')
219 Returns a function that adjusts the static configuration file for
221 Sets `dynamic-config.fs-cache-path` to a file that is reset after the tests
222 to avoid leaking dynamic config values between test sessions.
224 @ingroup userver_testsuite_fixtures
227 def patch_config(config, _config_vars) -> None:
228 components = config[
'components_manager'][
'components']
229 dynamic_config_component = components.get(
'dynamic-config',
None)
or {}
230 if dynamic_config_component.get(
'fs-cache-path',
'') ==
'':
233 cache_path = service_tmpdir /
'configs' /
'config_cache.json'
235 if cache_path.is_file():
239 dynamic_config_component[
'fs-cache-path'] = str(cache_path)
244@pytest.fixture(scope='session')
247 Returns a function that adjusts the static configuration file for
249 Removes `dynamic-config.defaults-path`.
250 Updates `dynamic-config.defaults` with `config_service_defaults`.
252 @ingroup userver_testsuite_fixtures
255 def extract_defaults_dict(component_config, config_vars) -> dict:
256 defaults_field = component_config.get(
'defaults',
None)
or {}
257 if isinstance(defaults_field, dict):
258 return defaults_field
259 elif isinstance(defaults_field, str):
260 if defaults_field.startswith(
'$'):
261 return config_vars.get(defaults_field[1:], {})
262 assert False, f
'Unexpected static config option `dynamic-config.defaults`: {defaults_field!r}'
264 def _patch_config(config_yaml, config_vars):
265 components = config_yaml[
'components_manager'][
'components']
266 if components.get(
'dynamic-config',
None)
is None:
267 components[
'dynamic-config'] = {}
268 dynconf_component = components[
'dynamic-config']
270 dynconf_component.pop(
'defaults-path',
None)
272 extract_defaults_dict(dynconf_component, config_vars),
273 **config_service_defaults,
275 dynconf_component[
'defaults'] = defaults
280@pytest.fixture(scope='session')
319 dynamic_config: dynconf.DynamicConfig,
323 Adds a mockserver handler that forwards dynamic_config to service's
324 `dynamic-config-client` component.
326 @ingroup userver_testsuite_fixtures
329 @mockserver.json_handler('/configs-service/configs/values')
330 def _mock_configs(request):
331 updates = dynamic_config_changelog.get_updated_since(
332 dynconf._create_config_dict(
333 dynamic_config.get_values_unsafe(),
334 dynamic_config.get_kill_switches_disabled_unsafe(),
336 request.json.get(
'updated_since',
''),
337 request.json.get(
'ids'),
339 response = {
'configs': updates.values,
'updated_at': updates.timestamp}
341 response[
'removed'] = updates.removed
342 if updates.kill_switches_disabled:
343 response[
'kill_switches_disabled'] = updates.kill_switches_disabled
346 @mockserver.json_handler('/configs-service/configs/status')
347 def _mock_configs_status(_request):
349 'updated_at': dynamic_config_changelog.timestamp.strftime(
350 '%Y-%m-%dT%H:%M:%SZ',