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 _config_service_defaults_updated,
87 _testsuite_client_config: client.TestsuiteClientConfig,
89 _service_client_testsuite,
96 Main fixture that provides access to userver based service.
98 @snippet samples/testsuite-support/tests/test_ping.py service_client
99 @anchor service_client
100 @ingroup userver_testsuite_fixtures
104 daemon = await ensure_daemon_started(service_daemon)
106 if not _testsuite_client_config.testsuite_action_path:
107 yield _service_client_base
109 service_client = _service_client_testsuite(daemon)
110 await _config_service_defaults_updated.update(
111 service_client, dynamic_config,
114 async with userver_client_cleanup(service_client):
119def userver_client_cleanup(request, userver_flush_logs):
120 marker = request.node.get_closest_marker(
'suspend_periodic_tasks')
122 tasks_to_suspend = marker.args
124 tasks_to_suspend = ()
126 @compat.asynccontextmanager
127 async def cleanup_manager(client: client.AiohttpClient):
129 await client.suspend_periodic_tasks(tasks_to_suspend)
133 await client.resume_all_periodic_tasks()
135 return cleanup_manager
140 """Flush logs in case of failure."""
142 @compat.asynccontextmanager
143 async def flush_logs(service_client: client.AiohttpClient):
144 async def do_flush():
146 await service_client.log_flush()
147 except aiohttp.client_exceptions.ClientResponseError:
158 if failed
or item.utestsuite_report.failed:
167 Fixture that provides access to userver based websocket service.
169 @anchor websocket_client
170 @ingroup userver_testsuite_fixtures
174 @compat.asynccontextmanager
175 async def get(self, path):
176 update_server_state = getattr(
177 service_client,
'update_server_state',
None,
179 if update_server_state:
180 await update_server_state()
181 ws_context = websockets.connect(
182 f
'ws://localhost:{service_port}/{path}',
184 async with ws_context
as socket:
193 service_client_options,
195 monitor_baseurl: str,
199 Main fixture that provides access to userver monitor listener.
201 @snippet samples/testsuite-support/tests/test_metrics.py metrics labels
202 @ingroup userver_testsuite_fixtures
204 aiohttp_client = client.AiohttpClientMonitor(
206 config=_testsuite_client_config,
207 headers={
'x-yatraceid': mockserver.trace_id},
208 **service_client_options,
214async def _service_client_base(service_baseurl, service_client_options):
215 class _ClientDiagnose(base_service_client.Client):
216 def __getattr__(self, name: str) ->
None:
217 raise AttributeError(
218 f
'"Client" object has no attribute "{name}". '
219 'Note that "service_client" fixture returned the basic '
220 '"testsuite.daemons.service_client.Client" client rather than '
221 'a "pytest_userver.client.Client" client with userver '
222 'extensions. That happened because the service '
223 'static configuration file contains no "tests-control" '
224 'component with "action" field.',
227 return _ClientDiagnose(service_baseurl, **service_client_options)
231def _service_client_testsuite(
233 service_client_options,
235 userver_cache_control,
239 cache_invalidation_state,
240 service_periodic_tasks_state,
241 _testsuite_client_config: client.TestsuiteClientConfig,
243 def create_client(daemon):
244 aiohttp_client = client.AiohttpClient(
246 config=_testsuite_client_config,
248 testpoint_control=testpoint_control,
249 periodic_tasks_state=service_periodic_tasks_state,
250 log_capture_fixture=userver_log_capture,
251 mocked_time=mocked_time,
252 cache_invalidation_state=cache_invalidation_state,
253 cache_control=userver_cache_control(daemon),
254 **service_client_options,
261@pytest.fixture(scope='session')
264 Returns the main listener URL of the service.
266 Override this fixture to change the main listener URL that the testsuite
269 @ingroup userver_testsuite_fixtures
271 return f
'http://localhost:{service_port}/'
274@pytest.fixture(scope='session')
277 Returns the main monitor URL of the service.
279 Override this fixture to change the main monitor URL that the testsuite
282 @ingroup userver_testsuite_fixtures
284 return f
'http://localhost:{monitor_port}/'
287@pytest.fixture(scope='session')
288def service_periodic_tasks_state() -> client.PeriodicTasksState:
292@pytest.fixture(scope='session')
293def _testsuite_client_config(
294 pytestconfig, service_config,
295) -> client.TestsuiteClientConfig:
296 components = service_config[
'components_manager'][
'components']
298 def get_component_path(name, argname=None):
299 if name
in components:
300 path = components[name][
'path']
301 path = path.rstrip(
'*')
303 if argname
and f
'{{{argname}}}' not in path:
305 f
'Component {name} must provide path argument {argname}',
311 server_monitor_path=get_component_path(
'handler-server-monitor'),
312 testsuite_action_path=get_component_path(
'tests-control',
'action'),