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
19logger = logging.getLogger(__name__)
25 Service client dependencies hook. Feel free to override, e.g.:
29 def extra_client_deps(some_fixtures_to_wait_before_service_start):
32 @ingroup userver_testsuite_fixtures
39 Service client dependencies hook that knows about pgsql, mongodb,
40 clickhouse, rabbitmq, kafka, redis_store, ydb, and mysql dependencies.
41 To add some other dependencies prefer overriding the
42 extra_client_deps() fixture.
44 @ingroup userver_testsuite_fixtures
59 fixture_lookup_error = pytest.FixtureLookupError
60 except AttributeError:
62 import _pytest.fixtures
64 fixture_lookup_error = _pytest.fixtures.FixtureLookupError
67 for dep
in known_deps:
69 request.getfixturevalue(dep)
70 resolved_deps.append(dep)
71 except fixture_lookup_error:
75 'userver fixture "auto_client_deps" resolved dependencies %s',
81async def service_client(
82 ensure_daemon_started,
86 cleanup_userver_dumps,
87 userver_client_cleanup,
88 _testsuite_client_config: client.TestsuiteClientConfig,
90 _service_client_testsuite,
97 Main fixture that provides access to userver based service.
99 @snippet samples/testsuite-support/tests/test_ping.py service_client
100 @anchor service_client
101 @ingroup userver_testsuite_fixtures
105 daemon = await ensure_daemon_started(service_daemon)
107 if not _testsuite_client_config.testsuite_action_path:
108 yield _service_client_base
110 service_client = _service_client_testsuite(daemon)
118 _userver_logging_plugin,
119 _dynamic_config_defaults_storage,
122) -> typing.Callable[[client.Client], typing.AsyncGenerator]:
124 Contains the pre-test and post-test setup that depends
125 on @ref service_client.
127 Feel free to override, but in that case make sure to call the original
128 `userver_client_cleanup` fixture instance.
130 @ingroup userver_testsuite_fixtures
132 marker = request.node.get_closest_marker(
'suspend_periodic_tasks')
134 tasks_to_suspend = marker.args
136 tasks_to_suspend = ()
138 @compat.asynccontextmanager
139 async def cleanup_manager(client: client.Client):
140 @_userver_logging_plugin.register_flusher
141 async def do_flush():
143 await client.log_flush()
144 except aiohttp.client_exceptions.ClientError:
151 _userver_logging_plugin.update_position()
153 await _dynamic_config_defaults_storage.update(client, dynamic_config)
154 _check_config_marks()
156 await client.suspend_periodic_tasks(tasks_to_suspend)
160 await client.resume_all_periodic_tasks()
162 return cleanup_manager
168 Fixture that provides access to userver based websocket service.
170 @anchor websocket_client
171 @ingroup userver_testsuite_fixtures
175 @compat.asynccontextmanager
176 async def get(self, path):
177 update_server_state = getattr(
178 service_client,
'update_server_state',
None,
180 if update_server_state:
181 await update_server_state()
182 ws_context = websockets.connect(
183 f
'ws://localhost:{service_port}/{path}',
185 async with ws_context
as socket:
194 service_client_options,
196 monitor_baseurl: str,
200 Main fixture that provides access to userver monitor listener.
202 @snippet samples/testsuite-support/tests/test_metrics.py metrics labels
203 @ingroup userver_testsuite_fixtures
205 aiohttp_client = client.AiohttpClientMonitor(
207 config=_testsuite_client_config,
208 headers={
'x-yatraceid': mockserver.trace_id},
209 **service_client_options,
215async def _service_client_base(service_baseurl, service_client_options):
216 class _ClientDiagnose(base_service_client.Client):
217 def __getattr__(self, name: str) ->
None:
218 raise AttributeError(
219 f
'"Client" object has no attribute "{name}". '
220 'Note that "service_client" fixture returned the basic '
221 '"testsuite.daemons.service_client.Client" client rather than '
222 'a "pytest_userver.client.Client" client with userver '
223 'extensions. That happened because the service '
224 'static configuration file contains no "tests-control" '
225 'component with "action" field.',
228 return _ClientDiagnose(service_baseurl, **service_client_options)
232def _service_client_testsuite(
234 service_client_options,
236 userver_cache_control,
240 cache_invalidation_state,
241 service_periodic_tasks_state,
242 _testsuite_client_config: client.TestsuiteClientConfig,
245 def create_client(daemon):
246 aiohttp_client = client.AiohttpClient(
248 config=_testsuite_client_config,
250 testpoint_control=testpoint_control,
251 periodic_tasks_state=service_periodic_tasks_state,
252 log_capture_fixture=userver_log_capture,
253 mocked_time=mocked_time,
254 cache_invalidation_state=cache_invalidation_state,
255 cache_control=userver_cache_control(daemon),
256 asyncexc_check=asyncexc_check,
257 **service_client_options,
264@pytest.fixture(scope='session')
267 Returns the main listener URL of the service.
269 Override this fixture to change the main listener URL that the testsuite
272 @ingroup userver_testsuite_fixtures
274 return f
'http://localhost:{service_port}/'
277@pytest.fixture(scope='session')
280 Returns the main monitor URL of the service.
282 Override this fixture to change the main monitor URL that the testsuite
285 @ingroup userver_testsuite_fixtures
287 return f
'http://localhost:{monitor_port}/'
290@pytest.fixture(scope='session')
291def service_periodic_tasks_state() -> client.PeriodicTasksState:
295@pytest.fixture(scope='session')
296def _testsuite_client_config(
297 pytestconfig, service_config,
298) -> client.TestsuiteClientConfig:
299 components = service_config[
'components_manager'][
'components']
301 def get_component_path(name, argname=None):
302 if name
in components:
303 path = components[name][
'path']
304 path = path.rstrip(
'*')
306 if argname
and f
'{{{argname}}}' not in path:
308 f
'Component {name} must provide path argument {argname}',
314 server_monitor_path=get_component_path(
'handler-server-monitor'),
315 testsuite_action_path=get_component_path(
'tests-control',
'action'),