2Service main and monitor clients.
9import aiohttp.client_exceptions
13from testsuite.daemons
import service_client
as base_service_client
14from testsuite.daemons.pytest_plugin
import DaemonInstance
15from testsuite.utils
import compat
17from pytest_userver
import client
20logger = logging.getLogger(__name__)
26 Service client dependencies hook. Feel free to override, e.g.:
30 def extra_client_deps(some_fixtures_to_wait_before_service_start):
33 @ingroup userver_testsuite_fixtures
40 Service client dependencies hook that knows about pgsql, mongodb,
41 clickhouse, rabbitmq, redis_store, ydb, and mysql dependencies.
42 To add some other dependencies prefer overriding the
43 extra_client_deps() fixture.
45 @ingroup userver_testsuite_fixtures
58 fixture_lookup_error = pytest.FixtureLookupError
59 except AttributeError:
61 import _pytest.fixtures
62 fixture_lookup_error = _pytest.fixtures.FixtureLookupError
65 for dep
in known_deps:
67 request.getfixturevalue(dep)
68 resolved_deps.append(dep)
69 except fixture_lookup_error:
73 'userver fixture "auto_client_deps" resolved dependencies %s',
79async def service_client(
80 ensure_daemon_started,
84 cleanup_userver_dumps,
85 userver_client_cleanup,
86 _testsuite_client_config: client.TestsuiteClientConfig,
88 _service_client_testsuite,
95 Main fixture that provides access to userver based service.
97 @snippet samples/testsuite-support/tests/test_ping.py service_client
98 @anchor service_client
99 @ingroup userver_testsuite_fixtures
103 daemon = await ensure_daemon_started(service_daemon)
105 if not _testsuite_client_config.testsuite_action_path:
106 yield _service_client_base
108 service_client = _service_client_testsuite(daemon)
116 _userver_logging_plugin,
117 _dynamic_config_defaults_storage,
120) -> typing.Callable[[client.Client], typing.AsyncGenerator]:
122 Contains the pre-test and post-test setup that depends
123 on @ref service_client.
125 Feel free to override, but in that case make sure to call the original
126 `userver_client_cleanup` fixture instance.
128 @ingroup userver_testsuite_fixtures
130 marker = request.node.get_closest_marker(
'suspend_periodic_tasks')
132 tasks_to_suspend = marker.args
134 tasks_to_suspend = ()
136 @compat.asynccontextmanager
137 async def cleanup_manager(client: client.Client):
138 @_userver_logging_plugin.register_flusher
139 async def do_flush():
141 await client.log_flush()
142 except aiohttp.client_exceptions.ClientError:
149 _userver_logging_plugin.update_position()
151 await _dynamic_config_defaults_storage.update(client, dynamic_config)
152 _check_config_marks()
154 await client.suspend_periodic_tasks(tasks_to_suspend)
158 await client.resume_all_periodic_tasks()
160 return cleanup_manager
166 Fixture that provides access to userver based websocket service.
168 @anchor websocket_client
169 @ingroup userver_testsuite_fixtures
173 @compat.asynccontextmanager
174 async def get(self, path):
175 update_server_state = getattr(
176 service_client,
'update_server_state',
None,
178 if update_server_state:
179 await update_server_state()
180 ws_context = websockets.connect(
181 f
'ws://localhost:{service_port}/{path}',
183 async with ws_context
as socket:
192 service_client_options,
194 monitor_baseurl: str,
198 Main fixture that provides access to userver monitor listener.
200 @snippet samples/testsuite-support/tests/test_metrics.py metrics labels
201 @ingroup userver_testsuite_fixtures
203 aiohttp_client = client.AiohttpClientMonitor(
205 config=_testsuite_client_config,
206 headers={
'x-yatraceid': mockserver.trace_id},
207 **service_client_options,
213async def _service_client_base(service_baseurl, service_client_options):
214 class _ClientDiagnose(base_service_client.Client):
215 def __getattr__(self, name: str) ->
None:
216 raise AttributeError(
217 f
'"Client" object has no attribute "{name}". '
218 'Note that "service_client" fixture returned the basic '
219 '"testsuite.daemons.service_client.Client" client rather than '
220 'a "pytest_userver.client.Client" client with userver '
221 'extensions. That happened because the service '
222 'static configuration file contains no "tests-control" '
223 'component with "action" field.',
226 return _ClientDiagnose(service_baseurl, **service_client_options)
230def _service_client_testsuite(
232 service_client_options,
234 userver_cache_control,
238 cache_invalidation_state,
239 service_periodic_tasks_state,
240 _testsuite_client_config: client.TestsuiteClientConfig,
242 def create_client(daemon):
243 aiohttp_client = client.AiohttpClient(
245 config=_testsuite_client_config,
247 testpoint_control=testpoint_control,
248 periodic_tasks_state=service_periodic_tasks_state,
249 log_capture_fixture=userver_log_capture,
250 mocked_time=mocked_time,
251 cache_invalidation_state=cache_invalidation_state,
252 cache_control=userver_cache_control(daemon),
253 **service_client_options,
260@pytest.fixture(scope='session')
263 Returns the main listener URL of the service.
265 Override this fixture to change the main listener URL that the testsuite
268 @ingroup userver_testsuite_fixtures
270 return f
'http://localhost:{service_port}/'
273@pytest.fixture(scope='session')
276 Returns the main monitor URL of the service.
278 Override this fixture to change the main monitor URL that the testsuite
281 @ingroup userver_testsuite_fixtures
283 return f
'http://localhost:{monitor_port}/'
286@pytest.fixture(scope='session')
287def service_periodic_tasks_state() -> client.PeriodicTasksState:
291@pytest.fixture(scope='session')
292def _testsuite_client_config(
293 pytestconfig, service_config,
294) -> client.TestsuiteClientConfig:
295 components = service_config[
'components_manager'][
'components']
297 def get_component_path(name, argname=None):
298 if name
in components:
299 path = components[name][
'path']
300 path = path.rstrip(
'*')
302 if argname
and f
'{{{argname}}}' not in path:
304 f
'Component {name} must provide path argument {argname}',
310 server_monitor_path=get_component_path(
'handler-server-monitor'),
311 testsuite_action_path=get_component_path(
'tests-control',
'action'),