userver: /data/code/userver/testsuite/pytest_plugins/pytest_userver/plugins/scylla.py Source File
Loading...
Searching...
No Matches
scylla.py
1"""
2Plugin that waits for a ScyllaDB cluster to become reachable and adjusts
3the `scylla-*` components of the static config to point at it.
4"""
5
6# pylint: disable=redefined-outer-name
7import dataclasses
8import logging
9
10import pytest
11
12from testsuite.environment import utils as env_utils
13
14pytest_plugins = ['pytest_userver.plugins.core']
15
16USERVER_CONFIG_HOOKS = ['userver_config_scylla']
17
18logger = logging.getLogger(__name__)
19
20DEFAULT_HOST = 'localhost'
21DEFAULT_CQL_PORT = 9042
22DEFAULT_WAIT_TIMEOUT = 60.0
23
24_SCYLLA_COMPONENT_PREFIX = 'scylla-'
25
26
27def pytest_addoption(parser) -> None:
28 group = parser.getgroup('scylla')
29 group.addoption(
30 '--scylla-host',
31 help=(
32 'Host of the ScyllaDB cluster used by functional tests. Defaults to $TESTSUITE_SCYLLA_HOST or "localhost".'
33 ),
34 )
35 group.addoption(
36 '--scylla-port',
37 type=int,
38 help=('CQL native transport port. Defaults to $TESTSUITE_SCYLLA_PORT or 9042.'),
39 )
40 group.addoption(
41 '--scylla-wait-timeout',
42 type=float,
43 help=(
44 'Seconds to wait for the CQL port to start accepting '
45 'connections before failing service start. '
46 'Defaults to $TESTSUITE_SCYLLA_WAIT_TIMEOUT or 60.'
47 ),
48 )
49
50
51@dataclasses.dataclass(frozen=True)
53 host: str
54 port: int
55
56 def contact_points(self) -> str:
57 if self.port == DEFAULT_CQL_PORT:
58 return self.host
59 return f'{self.host}:{self.port}'
60
61
62@pytest.fixture(scope='session')
63def scylla_connection_info(pytestconfig) -> ConnectionInfo:
64 """
65 Where the ScyllaDB cluster is expected to be running.
66
67 @ingroup userver_testsuite_fixtures
68 """
69 host = pytestconfig.option.scylla_host or env_utils.getenv_str(
70 'TESTSUITE_SCYLLA_HOST',
71 DEFAULT_HOST,
72 )
73 port = pytestconfig.option.scylla_port or env_utils.getenv_int(
74 'TESTSUITE_SCYLLA_PORT',
75 DEFAULT_CQL_PORT,
76 )
77 return ConnectionInfo(host=host, port=port)
78
79
80@pytest.fixture(scope='session')
81def scylla_wait_timeout(pytestconfig) -> float:
82 """@ingroup userver_testsuite_fixtures"""
83 return pytestconfig.option.scylla_wait_timeout or env_utils.getenv_float(
84 'TESTSUITE_SCYLLA_WAIT_TIMEOUT',
85 DEFAULT_WAIT_TIMEOUT,
86 )
87
88
89@pytest.fixture(scope='session')
90def _scylla_tcp_ready(scylla_connection_info, scylla_wait_timeout) -> None:
91 info = scylla_connection_info
92 logger.info(
93 'Waiting up to %.1fs for ScyllaDB CQL port at %s:%d',
94 scylla_wait_timeout,
95 info.host,
96 info.port,
97 )
98 if not env_utils.wait_tcp_connection(
99 host=info.host,
100 port=info.port,
101 timeout=scylla_wait_timeout,
102 ):
103 raise RuntimeError(
104 f'ScyllaDB is not reachable at {info.host}:{info.port} after '
105 f'{scylla_wait_timeout:.1f}s. Start the cluster or set '
106 '--scylla-host / TESTSUITE_SCYLLA_HOST to a reachable endpoint.',
107 )
108
109
110@pytest.fixture
111def scylla(_scylla_tcp_ready, scylla_connection_info) -> ConnectionInfo:
112 """@ingroup userver_testsuite_fixtures"""
113 return scylla_connection_info
114
115
116@pytest.fixture(scope='session')
117def userver_config_scylla(scylla_connection_info, _scylla_tcp_ready):
118 """@ingroup userver_testsuite_fixtures"""
119 contact_points = scylla_connection_info.contact_points()
120
121 def _patch(config_yaml, config_vars):
122 components = config_yaml['components_manager']['components']
123 for name, params in components.items():
124 if not isinstance(params, dict):
125 continue
126 if not name.startswith(_SCYLLA_COMPONENT_PREFIX):
127 continue
128 if 'dbalias' in params and params['dbalias']:
129 continue
130 if 'dbconnection' not in params:
131 continue
132 params['dbconnection'] = contact_points
133
134 return _patch