2Work with the configuration files of the service in testsuite.
29USERVER_CONFIG_HOOKS = [
30 'userver_config_http_server',
31 'userver_config_http_client',
32 'userver_config_logging',
33 'userver_config_testsuite',
34 'userver_config_testsuite_support',
35 'userver_config_secdist',
42logger = logging.getLogger(__name__)
45class _UserverConfigPlugin:
47 self._config_hooks = []
50 def userver_config_hooks(self):
51 return self._config_hooks
53 def pytest_plugin_registered(self, plugin, manager):
54 if not isinstance(plugin, types.ModuleType):
56 uhooks = getattr(plugin,
'USERVER_CONFIG_HOOKS',
None)
57 if uhooks
is not None:
58 self._config_hooks.extend(uhooks)
61class _UserverConfig(typing.NamedTuple):
66def pytest_configure(config):
67 config.pluginmanager.register(_UserverConfigPlugin(),
'userver_config')
68 config.addinivalue_line(
69 'markers',
'config: per-test dynamic config values',
73def pytest_addoption(parser) -> None:
74 group = parser.getgroup(
'userver-config')
76 '--service-log-level',
79 choices=[
'trace',
'debug',
'info',
'warning',
'error',
'critical'],
84 help=
'Path to service.yaml file.',
87 '--service-config-vars',
89 help=
'Path to config_vars.yaml file.',
94 help=
'Path to secure_data.json file.',
99 help=
'Path to dynamic config fallback file.',
106@pytest.fixture(scope='session')
109 Returns the path to service.yaml file set by command line
110 `--service-config` option.
112 Override this fixture to change the way path to service.yaml is provided.
114 @ingroup userver_testsuite_fixtures
116 return pytestconfig.option.service_config
119@pytest.fixture(scope='session')
122 Returns the path to config_vars.yaml file set by command line
123 `--service-config-vars` option.
125 Override this fixture to change the way path to config_vars.yaml is
128 @ingroup userver_testsuite_fixtures
130 return pytestconfig.option.service_config_vars
133@pytest.fixture(scope='session')
136 Returns the path to secure_data.json file set by command line
137 `--service-secdist` option.
139 Override this fixture to change the way path to secure_data.json is
142 @ingroup userver_testsuite_fixtures
144 return pytestconfig.option.service_secdist
147@pytest.fixture(scope='session')
150 Returns the path to dynamic config fallback file set by command line
151 `--config-fallback` option.
153 Override this fixture to change the way path to dynamic config fallback is
156 @ingroup userver_testsuite_fixtures
158 return pytestconfig.option.config_fallback
161@pytest.fixture(scope='session')
164 Returns the path for temporary files. The path is the same for the whole
165 session and files are not removed (at least by this fixture) between
168 @ingroup userver_testsuite_fixtures
170 return tmp_path_factory.mktemp(pathlib.Path(service_binary).name)
173@pytest.fixture(scope='session')
175 service_tmpdir, service_config_yaml,
178 Dumps the contents of the service_config_yaml into a static config for
179 testsuite and returns the path to the config file.
181 @ingroup userver_testsuite_fixtures
183 dst_path = service_tmpdir /
'config.yaml'
185 config_text = yaml.dump(service_config_yaml)
187 'userver fixture "service_config_path_temp" writes the patched static '
188 'config to "%s":\n%s',
192 dst_path.write_text(config_text)
197@pytest.fixture(scope='session')
200 Returns the static config values after the USERVER_CONFIG_HOOKS were
203 @ingroup userver_testsuite_fixtures
205 return _service_config.config_yaml
208@pytest.fixture(scope='session')
211 Returns the static config variables (config_vars.yaml) values after the
212 USERVER_CONFIG_HOOKS were applied (if any).
214 @ingroup userver_testsuite_fixtures
216 return _service_config.config_vars
219@pytest.fixture(scope='session')
225 service_config_vars_path,
230 with open(service_config_path, mode=
'rt')
as fp:
231 config_yaml = yaml.safe_load(fp)
233 if service_config_vars_path:
234 with open(service_config_vars_path, mode=
'rt')
as fp:
235 config_vars = yaml.safe_load(fp)
239 plugin = pytestconfig.pluginmanager.get_plugin(
'userver_config')
240 for hook
in plugin.userver_config_hooks:
241 if not callable(hook):
242 hook_func = request.getfixturevalue(hook)
245 hook_func(config_yaml, config_vars)
248 config_yaml.pop(
'config_vars',
None)
250 config_vars_path = service_tmpdir /
'config_vars.yaml'
251 config_vars_text = yaml.dump(config_vars)
253 'userver fixture "service_config" writes the patched static '
254 'config vars to "%s":\n%s',
258 config_vars_path.write_text(config_vars_text)
259 config_yaml[
'config_vars'] = str(config_vars_path)
261 return _UserverConfig(config_yaml=config_yaml, config_vars=config_vars)
264@pytest.fixture(scope='session')
267 Returns a function that adjusts the static configuration file for testsuite.
268 Sets the `server.listener.port` to listen on
269 @ref pytest_userver.plugins.base.service_port "service_port" fixture value;
270 sets the `server.listener-monitor.port` to listen on
271 @ref pytest_userver.plugins.base.monitor_port "monitor_port"
274 @ingroup userver_testsuite_fixtures
277 def _patch_config(config_yaml, config_vars):
278 components = config_yaml[
'components_manager'][
'components']
279 if 'server' in components:
280 server = components[
'server']
281 if 'listener' in server:
282 server[
'listener'][
'port'] = service_port
284 if 'listener-monitor' in server:
285 server[
'listener-monitor'][
'port'] = monitor_port
290@pytest.fixture(scope='session')
293 By default, userver HTTP client is only allowed to talk to mockserver
294 when running in testsuite. This makes tests repeatable and encapsulated.
296 Override this fixture to whitelist some additional URLs.
297 It is still strongly advised to only talk to localhost in tests.
299 @ingroup userver_testsuite_fixtures
304@pytest.fixture(scope='session')
306 mockserver_info, mockserver_ssl_info, allowed_url_prefixes_extra,
309 Returns a function that adjusts the static configuration file for testsuite.
310 Sets increased timeout and limits allowed URLs for `http-client` component.
312 @ingroup userver_testsuite_fixtures
315 def patch_config(config, config_vars):
316 components: dict = config[
'components_manager'][
'components']
317 if not {
'http-client',
'testsuite-support'}.issubset(
321 http_client = components[
'http-client']
or {}
322 http_client[
'testsuite-enabled'] =
True
323 http_client[
'testsuite-timeout'] =
'10s'
325 allowed_urls = [mockserver_info.base_url]
326 if mockserver_ssl_info:
327 allowed_urls.append(mockserver_ssl_info.base_url)
328 allowed_urls += allowed_url_prefixes_extra
329 http_client[
'testsuite-allowed-url-prefixes'] = allowed_urls
334@pytest.fixture(scope='session')
337 Returns a function that adjusts the static configuration file for testsuite.
338 Sets the `logging.loggers.default` to log to `@stderr` with level set
339 from `--service-log-level` pytest configuration option.
341 @ingroup userver_testsuite_fixtures
343 log_level = pytestconfig.option.service_log_level
345 def _patch_config(config_yaml, config_vars):
346 components = config_yaml[
'components_manager'][
'components']
347 if 'logging' in components:
348 components[
'logging'][
'loggers'] = {
350 'file_path':
'@stderr',
352 'overflow_behavior':
'discard',
355 config_vars[
'logger_level'] = log_level
360@pytest.fixture(scope='session')
363 Returns a function that adjusts the static configuration file for testsuite.
364 Sets the `testsuite-enabled` in config_vars.yaml to `True`; sets the
365 `tests-control.testpoint-url` to mockserver URL.
367 @ingroup userver_testsuite_fixtures
370 def _patch_config(config_yaml, config_vars):
371 config_vars[
'testsuite-enabled'] =
True
372 components = config_yaml[
'components_manager'][
'components']
373 if 'tests-control' in components:
374 components[
'tests-control'][
'testpoint-url'] = mockserver_info.url(
381@pytest.fixture(scope='session')
384 Returns a function that adjusts the static configuration file for testsuite.
385 Sets up `testsuite-support` component, which:
387 - increases timeouts for userver drivers
388 - disables periodic cache updates
389 - enables testsuite tasks
391 @ingroup userver_testsuite_fixtures
394 def _set_postgresql_options(testsuite_support: dict) ->
None:
395 testsuite_support[
'testsuite-pg-execute-timeout'] =
'35s'
396 testsuite_support[
'testsuite-pg-statement-timeout'] =
'30s'
397 testsuite_support[
'testsuite-pg-readonly-master-expected'] =
True
399 def _set_redis_timeout(testsuite_support: dict) ->
None:
400 testsuite_support[
'testsuite-redis-timeout-connect'] =
'40s'
401 testsuite_support[
'testsuite-redis-timeout-single'] =
'30s'
402 testsuite_support[
'testsuite-redis-timeout-all'] =
'30s'
404 def _disable_cache_periodic_update(testsuite_support: dict) ->
None:
405 testsuite_support[
'testsuite-periodic-update-enabled'] =
False
407 def patch_config(config, config_vars) -> None:
408 components: dict = config[
'components_manager'][
'components']
409 if 'testsuite-support' not in components:
411 testsuite_support = components[
'testsuite-support']
or {}
412 _set_postgresql_options(testsuite_support)
413 _set_redis_timeout(testsuite_support)
414 service_runner = pytestconfig.getoption(
'--service-runner-mode',
False)
415 if not service_runner:
416 _disable_cache_periodic_update(testsuite_support)
417 testsuite_support[
'testsuite-tasks-enabled'] =
not service_runner
418 components[
'testsuite-support'] = testsuite_support
423@pytest.fixture(scope='session')
426 Returns a function that adjusts the static configuration file for testsuite.
427 Sets the `default-secdist-provider.config` to the value of
428 @ref pytest_userver.plugins.config.service_secdist_path "service_secdist_path"
431 @ingroup userver_testsuite_fixtures
434 def _patch_config(config_yaml, config_vars):
435 if not service_secdist_path:
438 components = config_yaml[
'components_manager'][
'components']
439 if 'default-secdist-provider' not in components:
442 if not service_secdist_path.is_file():
444 f
'"{service_secdist_path}" is not a file. Provide a '
445 f
'"--service-secdist" pytest option or override the '
446 f
'"service_secdist_path" fixture.',
448 components[
'default-secdist-provider'][
'config'] = str(
449 service_secdist_path,