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',