userver: /data/code/userver/testsuite/pytest_plugins/pytest_userver/plugins/service.py Source File
Loading...
Searching...
No Matches
service.py
1"""
2Start the service in testsuite.
3"""
4
5# pylint: disable=redefined-outer-name
6import logging
7import pathlib
8import time
9import typing
10
11import pytest
12
13from testsuite.utils import url_util
14
15from ..utils import net
16
17logger_testsuite = logging.getLogger(__name__)
18
19
20def pytest_addoption(parser) -> None:
21 group = parser.getgroup('userver')
22 group.addoption(
23 '--service-logs-file',
24 type=pathlib.Path,
25 help='Write service output to specified file',
26 )
27 group.addoption(
28 '--service-logs-pretty',
29 action='store_true',
30 help='Enable pretty print and colorize service logs',
31 )
32 group.addoption(
33 '--service-logs-pretty-verbose',
34 dest='service_logs_pretty',
35 action='store_const',
36 const='verbose',
37 help='Enable pretty print and colorize service logs in verbose mode',
38 )
39 group.addoption(
40 '--service-logs-pretty-disable',
41 action='store_false',
42 dest='service_logs_pretty',
43 help='Disable pretty print and colorize service logs',
44 )
45 group.addoption(
46 '--service-live-logs-disable',
47 action='store_true',
48 help='Disable service live logs (enabled with -s)',
49 )
50
51
52@pytest.fixture(scope='session')
54 """
55 Override this to pass extra environment variables to the service.
56
57 @snippet samples/redis_service/testsuite/conftest.py service_env
58 @ingroup userver_testsuite_fixtures
59 """
60 return None
61
62
63@pytest.fixture(scope='session')
65 service_config, service_baseurl,
66) -> typing.Optional[str]:
67 """
68 Returns the service HTTP ping URL that is used by the testsuite to detect
69 that the service is ready to work. Returns None if there's no such URL.
70
71 By default attempts to find server::handlers::Ping component by
72 "handler-ping" name in static config. Override this fixture to change the
73 behavior.
74
75 @ingroup userver_testsuite_fixtures
76 """
77 components = service_config['components_manager']['components']
78 ping_handler = components.get('handler-ping')
79 if ping_handler:
80 return url_util.join(service_baseurl, ping_handler['path'])
81 return None
82
83
84@pytest.fixture(scope='session')
85def service_non_http_health_checks( # pylint: disable=invalid-name
86 service_config,
87) -> net.HealthChecks:
88 """
89 Returns a health checks info.
90
91 By default, returns pytest_userver.utils.net.get_health_checks_info().
92
93 Override this fixture to change the way testsuite detects the tested
94 service being alive.
95
96 @ingroup userver_testsuite_fixtures
97 """
98
99 return net.get_health_checks_info(service_config)
100
101
102@pytest.fixture(scope='session')
104 pytestconfig,
105 create_daemon_scope,
106 service_env,
107 service_http_ping_url,
108 service_config_path_temp,
109 service_config,
110 service_binary,
111 service_non_http_health_checks,
112):
113 """
114 Configures the health checking to use service_http_ping_url fixture value
115 if it is not None; otherwise uses the service_non_http_health_checks info.
116 Starts the service daemon.
117
118 @ingroup userver_testsuite_fixtures
119 """
120 assert service_http_ping_url or service_non_http_health_checks.tcp, (
121 '"service_http_ping_url" and "create_health_checker" fixtures '
122 'returned None. Testsuite is unable to detect if the service is ready '
123 'to accept requests.',
124 )
125
126 logger_testsuite.debug(
127 'userver fixture "service_daemon" would check for "%s"',
128 service_non_http_health_checks,
129 )
130
131 class LocalCounters:
132 last_log_time = 0.0
133 attempts = 0
134
135 async def _checker(*, session, process) -> bool:
136 LocalCounters.attempts += 1
137 new_log_time = time.monotonic()
138 if new_log_time - LocalCounters.last_log_time > 1.0:
139 LocalCounters.last_log_time = new_log_time
140 logger_testsuite.debug(
141 'userver fixture "service_daemon" checking "%s", attempt %s',
142 service_non_http_health_checks,
143 LocalCounters.attempts,
144 )
145
146 return await net.check_availability(service_non_http_health_checks)
147
148 health_check = _checker
149 if service_http_ping_url:
150 health_check = None
151
152 async with create_daemon_scope(
153 args=[str(service_binary), '--config', str(service_config_path_temp)],
154 ping_url=service_http_ping_url,
155 health_check=health_check,
156 env=service_env,
157 ) as scope:
158 yield scope