userver: samples/scylla_service/testsuite/test_scylla.py
Loading...
Searching...
No Matches
samples/scylla_service/testsuite/test_scylla.py
1import uuid
2
3
4async def test_schema_init_response(service_client):
5 response = await service_client.post('/v1/schema/init')
6
7 assert response.status == 200
8 body = response.json()
9
10 assert body['status'] == 'ok'
11 assert sorted(body['tables']) == ['basic', 'events']
12
13
14# /// [Functional test]
15async def test_kv_crud(service_client):
16 response = await service_client.post(
17 '/v1/kv',
18 json={'key': 'hello', 'bln': True, 'i32': 7, 'dbl': 2.5},
19 )
20 assert response.status == 200
21
22 response = await service_client.get('/v1/kv', params={'key': 'hello'})
23 assert response.status == 200
24 body = response.json()
25 assert body['key'] == 'hello'
26 assert body['bln'] is True
27 assert body['i32'] == 7
28 assert body['dbl'] == 2.5
29
30 response = await service_client.patch(
31 '/v1/kv',
32 params={'key': 'hello'},
33 json={'i32': 42},
34 )
35 assert response.status == 200
36
37 response = await service_client.get('/v1/kv', params={'key': 'hello'})
38 assert response.json()['i32'] == 42
39
40 response = await service_client.delete('/v1/kv', params={'key': 'hello'})
41 assert response.status == 200
42
43 response = await service_client.get('/v1/kv', params={'key': 'hello'})
44 assert response.status == 404
45 # /// [Functional test]
46
47
48async def test_kv_missing(service_client):
49 response = await service_client.get('/v1/kv', params={'key': 'absent'})
50 assert response.status == 404
51 assert response.json() == {'error': 'not_found'}
52
53
54async def test_kv_requires_key(service_client):
55 response = await service_client.post('/v1/kv', json={'i32': 1})
56 assert response.status == 400
57
58
59async def test_list_and_count(service_client):
60 for i in range(5):
61 response = await service_client.post(
62 '/v1/kv',
63 json={'key': f'k{i}', 'i32': i},
64 )
65 assert response.status == 200
66
67 response = await service_client.get('/v1/kv/list')
68 assert response.status == 200
69 body = response.json()
70 assert body['count'] == 5
71 assert {item['key'] for item in body['items']} == {f'k{i}' for i in range(5)}
72
73 response = await service_client.get('/v1/kv/list', params={'limit': 2})
74 assert response.json()['count'] == 2
75
76 response = await service_client.get('/v1/kv/count')
77 assert response.json() == {'count': 5}
78
79 response = await service_client.get('/v1/kv/count', params={'key': 'k0'})
80 assert response.json() == {'count': 1}
81
82
83async def test_bulk_insert(service_client):
84 payload = [{'key': f'b{i}', 'i64': i * 10} for i in range(4)]
85 response = await service_client.post('/v1/kv/bulk', json=payload)
86 assert response.status == 200
87 assert response.json() == {'inserted': 4}
88
89 response = await service_client.get('/v1/kv/list')
90 assert response.json()['count'] == 4
91
92
93async def test_bulk_rejects_empty(service_client):
94 response = await service_client.post('/v1/kv/bulk', json=[])
95 assert response.status == 400
96
97
98async def test_pagination(service_client):
99 for i in range(7):
100 response = await service_client.post(
101 '/v1/kv',
102 json={'key': f'p{i}', 'i32': i},
103 )
104 assert response.status == 200
105
106 seen = set()
107 cursor = None
108 for _ in range(10):
109 params = {'page_size': 3}
110 if cursor:
111 params['cursor'] = cursor
112 response = await service_client.get('/v1/kv/pages', params=params)
113 assert response.status == 200
114 body = response.json()
115 seen.update(item['key'] for item in body['items'])
116 if not body['has_more']:
117 break
118 cursor = body['next_cursor']
119
120 assert seen == {f'p{i}' for i in range(7)}
121
122
123async def test_create_if_absent(service_client):
124 response = await service_client.post(
125 '/v1/kv/create_if_absent',
126 json={'key': 'lwt', 'i32': 1},
127 )
128 assert response.status == 200
129 assert response.json() == {'applied': True}
130
131 response = await service_client.post(
132 '/v1/kv/create_if_absent',
133 json={'key': 'lwt', 'i32': 2},
134 )
135 assert response.status == 409
136 body = response.json()
137 assert body['applied'] is False
138 assert body['existing']['i32'] == 1
139
140
141async def test_compare_and_set(service_client):
142 response = await service_client.post(
143 '/v1/kv',
144 json={'key': 'cas', 'i32': 1},
145 )
146 assert response.status == 200
147
148 response = await service_client.post(
149 '/v1/kv/cas',
150 params={'key': 'cas'},
151 json={'expect': {'i32': 1}, 'set': {'i32': 99}},
152 )
153 assert response.status == 200
154 assert response.json() == {'applied': True}
155
156 response = await service_client.get('/v1/kv', params={'key': 'cas'})
157 assert response.json()['i32'] == 99
158
159 response = await service_client.post(
160 '/v1/kv/cas',
161 params={'key': 'cas'},
162 json={'expect': {'i32': 1}, 'set': {'i32': 0}},
163 )
164 assert response.status == 409
165 body = response.json()
166 assert body['applied'] is False
167 assert body['current']['i32'] == 99
168
169
170async def test_delete_if_exists(service_client):
171 response = await service_client.post(
172 '/v1/kv',
173 json={'key': 'd1'},
174 )
175 assert response.status == 200
176
177 response = await service_client.delete(
178 '/v1/kv/delete_if_exists',
179 params={'key': 'd1'},
180 )
181 assert response.status == 200
182 assert response.json() == {'applied': True}
183
184 response = await service_client.delete(
185 '/v1/kv/delete_if_exists',
186 params={'key': 'd1'},
187 )
188 assert response.status == 404
189 assert response.json() == {'applied': False}
190
191
192async def test_raw_query(service_client):
193 response = await service_client.post(
194 '/v1/kv',
195 json={'key': 'r1', 'i32': 10},
196 )
197 assert response.status == 200
198
199 response = await service_client.post(
200 '/v1/raw',
201 json={'query': 'SELECT key, i32 FROM examples.basic'},
202 )
203 assert response.status == 200
204 body = response.json()
205 assert body['count'] == 1
206 assert body['rows'][0]['key'] == 'r1'
207 assert body['rows'][0]['i32'] == 10
208
209
210async def test_raw_query_requires_query(service_client):
211 response = await service_client.post('/v1/raw', json={})
212 assert response.status == 400
213
214
215async def test_events_crud(service_client):
216 response = await service_client.post(
217 '/v1/events',
218 json={
219 'name': 'login',
220 'source_ip': '192.168.0.1',
221 'tags': ['auth', 'ok'],
222 'metadata': {'user': 'alice'},
223 'scores': [1, 2, 3],
224 },
225 )
226 assert response.status == 200
227 event_id = response.json()['id']
228
229 response = await service_client.get('/v1/events', params={'id': event_id})
230 assert response.status == 200
231 body = response.json()
232 assert body['id'] == event_id
233 assert body['name'] == 'login'
234 assert body['source_ip'] == '192.168.0.1'
235 assert sorted(body['tags']) == ['auth', 'ok']
236 assert body['metadata'] == {'user': 'alice'}
237 assert body['scores'] == [1, 2, 3]
238
239
240async def test_events_missing(service_client):
241 response = await service_client.get(
242 '/v1/events',
243 params={'id': '00000000-0000-0000-0000-000000000000'},
244 )
245 assert response.status == 404
246
247
248async def test_events_requires_name(service_client):
249 response = await service_client.post('/v1/events', json={})
250 assert response.status == 400
251
252
253async def test_events_list(service_client):
254 for name in ('a', 'b', 'c'):
255 response = await service_client.post('/v1/events', json={'name': name})
256 assert response.status == 200
257
258 response = await service_client.get('/v1/events/list')
259 assert response.status == 200
260 body = response.json()
261 assert body['count'] == 3
262 assert {item['name'] for item in body['items']} == {'a', 'b', 'c'}
263
264
265async def test_events_list_page_size(service_client):
266 names = {f'e{i}' for i in range(5)}
267 for name in names:
268 response = await service_client.post('/v1/events', json={'name': name})
269 assert response.status == 200
270
271 response = await service_client.get(
272 '/v1/events/list', params={'page_size': 2},
273 )
274 assert response.status == 200
275 body = response.json()
276 assert body['count'] == 5
277 assert {item['name'] for item in body['items']} == names
278
279
280async def test_kv_insert_with_ttl(service_client):
281 response = await service_client.post(
282 '/v1/kv',
283 json={'key': 'ephemeral', 'i32': 999, 'ttl': 60},
284 )
285 assert response.status == 200
286
287 response = await service_client.get('/v1/kv', params={'key': 'ephemeral'})
288 assert response.status == 200
289 assert response.json()['i32'] == 999
290
291
292async def test_kv_update_with_ttl(service_client):
293 response = await service_client.post(
294 '/v1/kv',
295 json={'key': 'ttl-upd', 'i32': 1},
296 )
297 assert response.status == 200
298
299 response = await service_client.patch(
300 '/v1/kv',
301 params={'key': 'ttl-upd'},
302 json={'i64': 100, 'ttl': 300},
303 )
304 assert response.status == 200
305
306 response = await service_client.get('/v1/kv', params={'key': 'ttl-upd'})
307
308 assert response.status == 200
309 assert response.json()['i64'] == 100
310
311
312async def test_event_with_ttl(service_client):
313 response = await service_client.post(
314 '/v1/events',
315 json={'name': 'temp-alert', 'ttl': 3600},
316 )
317 assert response.status == 200
318 event_id = response.json()['id']
319
320 response = await service_client.get('/v1/events', params={'id': event_id})
321 assert response.status == 200
322 assert response.json()['name'] == 'temp-alert'
323
324
325async def test_event_with_write_timestamp(service_client):
326 response = await service_client.post(
327 '/v1/events',
328 json={'name': 'backfill', 'write_timestamp': 1700000000000000},
329 )
330 assert response.status == 200
331 event_id = response.json()['id']
332
333 response = await service_client.get('/v1/events', params={'id': event_id})
334 assert response.status == 200
335 assert response.json()['name'] == 'backfill'
336
337
338async def test_raw_query_with_params(service_client):
339 response = await service_client.post(
340 '/v1/kv',
341 json={'key': 'param-test', 'i32': 42},
342 )
343 assert response.status == 200
344
345 response = await service_client.post(
346 '/v1/raw',
347 json={
348 'query': 'SELECT key, i32 FROM examples.basic WHERE key = ?',
349 'params': ['param-test'],
350 },
351 )
352 assert response.status == 200
353 body = response.json()
354 assert body['count'] == 1
355 assert body['rows'][0]['key'] == 'param-test'
356 assert body['rows'][0]['i32'] == 42
357
358
359async def test_raw_query_system_table(service_client):
360 response = await service_client.post(
361 '/v1/raw',
362 json={
363 'query': 'SELECT cluster_name, release_version FROM system.local',
364 },
365 )
366 assert response.status == 200
367 body = response.json()
368 assert body['count'] == 1
369 row = body['rows'][0]
370 assert 'cluster_name' in row
371 assert 'release_version' in row
372
373
374async def test_raw_ddl_void(service_client):
375 response = await service_client.post(
376 '/v1/raw',
377 json={
378 'query': (
379 'CREATE INDEX IF NOT EXISTS idx_events_name '
380 'ON examples.events (name)'
381 ),
382 'void': True,
383 },
384 )
385 assert response.status == 200
386 assert response.json() == {'status': 'ok'}
387
388
389async def test_raw_aggregation(service_client):
390 for name in ('x', 'y'):
391 response = await service_client.post('/v1/events', json={'name': name})
392 assert response.status == 200
393
394 response = await service_client.post(
395 '/v1/raw',
396 json={'query': 'SELECT COUNT(*) FROM examples.events'},
397 )
398 assert response.status == 200
399 body = response.json()
400 assert body['count'] == 1
401 row = body['rows'][0]
402 assert row['count'] == 2
403
404
405async def test_kv_all_basic_types(service_client):
406 payload = {
407 'key': 'alpha',
408 'bln': True,
409 'i32': 1,
410 'i64': 42,
411 'flt': 1.5,
412 'dbl': 2.5,
413 }
414 response = await service_client.post('/v1/kv', json=payload)
415 assert response.status == 200
416
417 response = await service_client.get('/v1/kv', params={'key': 'alpha'})
418 assert response.status == 200
419 body = response.json()
420
421 assert body['key'] == 'alpha'
422 assert body['bln'] is True
423 assert body['i32'] == 1
424 assert body['i64'] == 42
425 assert body['flt'] == 1.5
426 assert body['dbl'] == 2.5
427
428
429async def test_pagination_cursor_contract(service_client):
430 for i in range(5):
431 response = await service_client.post(
432 '/v1/kv',
433 json={'key': f'c{i}', 'i32': i},
434 )
435 assert response.status == 200
436
437 response = await service_client.get(
438 '/v1/kv/pages', params={'page_size': 2},
439 )
440 assert response.status == 200
441 first = response.json()
442 assert first['has_more'] is True
443 assert 'next_cursor' in first
444 assert isinstance(first['next_cursor'], str)
445 assert first['next_cursor']
446
447 cursor = first['next_cursor']
448 while True:
449 response = await service_client.get(
450 '/v1/kv/pages',
451 params={'page_size': 2, 'cursor': cursor},
452 )
453 assert response.status == 200
454 body = response.json()
455 if not body['has_more']:
456 assert 'next_cursor' not in body
457 break
458 cursor = body['next_cursor']
459
460
461async def test_event_response_shape(service_client):
462 response = await service_client.post('/v1/events', json={'name': 'shape'})
463 assert response.status == 200
464 body = response.json()
465
466 assert body['status'] == 'ok'
467
468 parsed = uuid.UUID(body['id'])
469 assert str(parsed) == body['id']
470
471 assert isinstance(body['created_at'], int)
472
473 assert body['created_at'] > 1577836800000
474
475
476async def test_raw_full_table_scan(service_client):
477 payload = [
478 {'key': 'scan-a', 'i32': 1},
479 {'key': 'scan-b', 'i32': 2},
480 {'key': 'scan-c', 'i32': 3},
481 ]
482 response = await service_client.post('/v1/kv/bulk', json=payload)
483 assert response.status == 200
484
485 response = await service_client.post(
486 '/v1/raw',
487 json={'query': 'SELECT * FROM examples.basic'},
488 )
489 assert response.status == 200
490 body = response.json()
491 assert body['count'] == 3
492 assert {row['key'] for row in body['rows']} == {
493 'scan-a', 'scan-b', 'scan-c',
494 }
495
496
497async def test_truncate(service_client):
498 for i in range(3):
499 response = await service_client.post(
500 '/v1/kv',
501 json={'key': f't{i}', 'i32': i},
502 )
503 assert response.status == 200
504
505 response = await service_client.get('/v1/kv/count')
506 assert response.json() == {'count': 3}
507
508 response = await service_client.post('/v1/kv/truncate')
509 assert response.status == 200
510 assert response.json() == {'status': 'ok'}
511
512 response = await service_client.get('/v1/kv/count')
513 assert response.json() == {'count': 0}