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