userver: en/testsuite/databases/redis/pytest_plugin.py Source File
Loading...
Searching...
No Matches
pytest_plugin.py
1import json
2
3import pytest
4import redis as redisdb
5
6from . import service
7
8
9def pytest_addoption(parser):
10 group = parser.getgroup('redis')
11 group.addoption('--redis-host', help='Redis host')
12 group.addoption('--redis-master-port', type=int, help='Redis master port')
13 group.addoption(
14 '--redis-sentinel-port',
15 type=int,
16 help='Redis sentinel port',
17 )
18 group.addoption(
19 '--no-redis',
20 help='Do not fill redis storage',
21 action='store_true',
22 )
23
24
25def pytest_configure(config):
26 config.addinivalue_line(
27 'markers',
28 'redis_store: per-test redis initialization',
29 )
30 config.addinivalue_line(
31 'markers',
32 'redis_cluster_store: per-test redis cluster initialization',
33 )
34 config.addinivalue_line(
35 'markers',
36 'redis_standalone_store: per-test standalone redis initialization',
37 )
38
39
40def pytest_service_register(register_service):
41 register_service('redis', service.create_redis_service)
42 register_service('redis-cluster', service.create_cluster_redis_service)
43 register_service(
44 'redis-standalone', service.create_standalone_redis_service
45 )
46
47
48@pytest.fixture(scope='session')
49def redis_service(
50 pytestconfig,
51 ensure_service_started,
52 _redis_service_settings,
53):
54 if not pytestconfig.option.no_redis and not pytestconfig.option.redis_host:
55 ensure_service_started('redis', settings=_redis_service_settings)
56
57
58@pytest.fixture(scope='session')
59def redis_cluster_service(
60 pytestconfig, ensure_service_started, _redis_cluster_service_settings
61):
62 if not pytestconfig.option.no_redis and not pytestconfig.option.redis_host:
63 ensure_service_started(
64 'redis-cluster', settings=_redis_cluster_service_settings
65 )
66
67
68@pytest.fixture(scope='session')
69async def redis_standalone_service(
70 pytestconfig, ensure_service_started, _redis_standalone_service_settings
71):
72 if not pytestconfig.option.no_redis and not pytestconfig.option.redis_host:
73 ensure_service_started(
74 'redis-standalone', settings=_redis_standalone_service_settings
75 )
76
77
78@pytest.fixture
79def redis_store(
80 pytestconfig,
81 _redis_store,
82 _redis_execute_commands_from_file,
83):
84 """Returns a Redis client for the test store.
85
86 Commands from static files are applied before the test; the database is
87 flushed afterwards.
88
89 @ingroup userver_testsuite_fixtures
90 Part of the [yandex-taxi-testsuite](https://github.com/yandex/yandex-taxi-testsuite/blob/develop/testsuite/databases/redis/pytest_plugin.py#L79)
91 """
92 if pytestconfig.option.no_redis:
93 yield
94 return
95
96 redis_db = _redis_store
97
98 try:
99 _redis_execute_commands_from_file('redis_store', redis_db)
100 yield redis_db
101 finally:
102 redis_db.flushall()
103
104
105@pytest.fixture
106def redis_sentinel(
107 pytestconfig,
108 request,
109 load_json,
110 redis_service,
111 redis_sentinels,
112):
113 if pytestconfig.option.no_redis:
114 yield
115 return
116
117 redis_db = redisdb.StrictRedis(
118 host=redis_sentinels[0]['host'],
119 port=redis_sentinels[0]['port'],
120 )
121
122 yield redis_db
123
124
125@pytest.fixture
126def redis_cluster_store(
127 pytestconfig,
128 _redis_cluster_store,
129 _redis_execute_commands_from_file,
130):
131 def _flush_all(redis_db):
132 slot_infos = redis_db.cluster_slots()
133 nodes = redis_db.get_primaries()
134 redis_db.flushall(target_nodes=nodes)
135 redis_db.wait(1, 10, target_nodes=nodes)
136
137 if pytestconfig.option.no_redis:
138 yield
139 return
140
141 redis_db = _redis_cluster_store
142
143 try:
144 _redis_execute_commands_from_file('redis_cluster_store', redis_db)
145 yield redis_db
146 finally:
147 _flush_all(redis_db)
148
149
150@pytest.fixture(scope='session')
151def _redis_masters(pytestconfig, _redis_service_settings):
152 if pytestconfig.option.redis_host:
153 # external Redis instance
154 return [
155 {
156 'host': pytestconfig.option.redis_host,
157 'port': (
158 pytestconfig.option.redis_master_port
159 or _redis_service_settings.master_ports[0]
160 ),
161 },
162 ]
163 return [
164 {'host': _redis_service_settings.host, 'port': port}
165 for port in _redis_service_settings.master_ports
166 ]
167
168
169@pytest.fixture(scope='session')
170def redis_sentinels(pytestconfig, _redis_service_settings):
171 if pytestconfig.option.redis_host:
172 # external Redis instance
173 return [
174 {
175 'host': pytestconfig.option.redis_host,
176 'port': (
177 pytestconfig.option.redis_sentinel_port
178 or _redis_service_settings.sentinel_port
179 ),
180 },
181 ]
182 return [
183 {
184 'host': _redis_service_settings.host,
185 'port': _redis_service_settings.sentinel_port,
186 },
187 ]
188
189
190@pytest.fixture(scope='session')
191def redis_cluster_nodes(_redis_cluster_service_settings):
192 return [
193 {
194 'host': _redis_cluster_service_settings.host,
195 'port': port,
196 }
197 for port in _redis_cluster_service_settings.cluster_ports
198 ]
199
200
201@pytest.fixture(scope='session')
202def redis_standalone_node(_redis_standalone_service_settings):
203 return {
204 'host': _redis_standalone_service_settings.host,
205 'port': _redis_standalone_service_settings.port,
206 }
207
208
209@pytest.fixture(scope='session')
210def redis_cluster_replicas(_redis_cluster_service_settings):
211 return _redis_cluster_service_settings.cluster_replicas
212
213
214@pytest.fixture(scope='session')
215def _redis_service_settings():
216 return service.get_service_settings()
217
218
219@pytest.fixture(scope='session')
220def _redis_cluster_service_settings():
221 return service.get_cluster_service_settings()
222
223
224@pytest.fixture(scope='session')
225def _redis_standalone_service_settings():
226 return service.get_standalone_service_settings()
227
228
229def _json_object_hook(dct):
230 if '$json' in dct:
231 return json.dumps(dct['$json'])
232 return dct
233
234
235@pytest.fixture(scope='session')
236def _redis_store(
237 pytestconfig,
238 redis_service,
239 _redis_masters,
240):
241 if pytestconfig.option.no_redis:
242 yield
243 return
244
245 redis_db = redisdb.StrictRedis(
246 host=_redis_masters[0]['host'],
247 port=_redis_masters[0]['port'],
248 )
249
250 yield redis_db
251
252
253# creating RedisCluster is costly, so we do it once at session scope
254@pytest.fixture(scope='session')
255def _redis_cluster_store(
256 pytestconfig,
257 redis_cluster_service,
258 redis_cluster_nodes,
259):
260 if pytestconfig.option.no_redis:
261 yield
262 return
263
264 redis_db = redisdb.RedisCluster( # type: ignore[abstract]
265 host=redis_cluster_nodes[0]['host'],
266 port=redis_cluster_nodes[0]['port'],
267 )
268
269 yield redis_db
270
271
272@pytest.fixture
273def redis_standalone_store(
274 pytestconfig,
275 redis_standalone_service,
276 redis_standalone_node,
277 _redis_execute_commands_from_file,
278):
279 if pytestconfig.option.no_redis:
280 yield
281 return
282
283 redis_db = redisdb.StrictRedis(
284 host=redis_standalone_node['host'],
285 port=redis_standalone_node['port'],
286 )
287
288 try:
289 _redis_execute_commands_from_file('redis_standalone_store', redis_db)
290 yield redis_db
291 finally:
292 redis_db.flushall()
293
294
295@pytest.fixture
296def _redis_execute_commands_from_file(request, load_json):
297 def _execute_commands(markers, redis_db):
298 redis_commands = []
299
300 for mark in request.node.iter_markers(markers):
301 store_file = mark.kwargs.get('file')
302 if store_file is not None:
303 redis_commands_from_file = load_json(
304 '%s.json' % store_file,
305 object_hook=_json_object_hook,
306 )
307 redis_commands.extend(redis_commands_from_file)
308
309 if mark.args:
310 redis_commands.extend(mark.args)
311
312 for redis_command in redis_commands:
313 func = getattr(redis_db, redis_command[0])
314 func(*redis_command[1:])
315
316 return _execute_commands