"""Tests for core.pagination module.""" import pytest from sqlalchemy import literal, union from sqlalchemy.orm import Query from typing import Any, Callable from src.cache import redis_client from src.legacy.core.pagination import paginate from src.legacy.redis_db import keys from src.legacy.redis_db.decorators import decode_str def get_kwargs(offset: int, limit: int, include_count: bool = True) -> dict: return {"limit": limit, "offset": offset, "include_count": include_count, "kwarg1": "ab", "kwarg2": 100} def get_data(offset: int = 0, items_count: int = 50, fields_count: int = 2) -> list: return [{f"field{j}": f"val{j}-{i:2}" for j in range(fields_count)} for i in range(offset, items_count)] def get_response(offset: int, limit: int, count: int = 50, response_count: int or None = -1): if response_count is not None and response_count < 0: response_count = count return { "count": response_count, "items": get_data(offset, min(offset + limit, count)) if offset < count else [], "next": f"/?limit={limit}&offset={offset + limit}" if (offset + limit) < count else None, "previous": ( f"/?limit={limit}&offset={offset - limit}" if offset > limit else ("/?" if offset == limit else None) ), } def get_query(db_session) -> Query: queries = [] for item in get_data(): columns = [] for name, value in item.items(): columns.append(literal(value).label(name)) queries.append(db_session.query(*columns)) query = union(*queries).alias() return db_session.query(query).order_by(*query.c) def row_to_dict(data: list, *args, **kwargs) -> list: return [item._asdict() for item in data] def get_extra_data(): return {"extra": 1} def check_extra_data(data: list, extra_data: Any, *args, **kwargs) -> list: assert extra_data == get_extra_data() return data def get_response_kwargs() -> dict: return {"ex1": 1, "ex2": "test"} def get_cache_key() -> str: return "test_key/{kwarg1},{kwarg2}" @pytest.mark.parametrize( "is_query,cache_key_template,full_data,extra_data,response_kwargs,update_page,f_args,f_kwargs,expected_result", ( (False, None, False, False, False, None, (), get_kwargs(0, 10), ValueError), (True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(20, 10), get_response(20, 10)), (True, None, False, False, False, None, (), get_kwargs(50, 10), get_response(50, 10)), (False, get_cache_key(), True, False, False, None, (), get_kwargs(20, 10), get_response(20, 10)), (False, None, True, False, False, None, (), get_kwargs(10, 10), get_response(10, 10)), (False, get_cache_key(), True, False, False, None, (), get_kwargs(0, 10), get_response(0, 10)), (False, None, True, True, False, check_extra_data, (), get_kwargs(10, 10), get_response(10, 10)), ( True, get_cache_key(), True, False, True, row_to_dict, ("a", 1), get_kwargs(10, 10), {**get_response(10, 10), **get_response_kwargs()}, ), (False, get_cache_key(), True, False, False, None, (), get_kwargs(0, 10, False), get_response(0, 10)), ( True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(20, 10, False), get_response(20, 10, response_count=None), ), ( True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(0, 10, False), get_response(0, 10, response_count=None), ), ( True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(10, 10, False), get_response(10, 10, response_count=None), ), ( True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(40, 10, False), get_response(40, 10, response_count=None), ), ( True, get_cache_key(), False, False, False, row_to_dict, (), get_kwargs(50, 10, False), get_response(50, 10, response_count=None), ), ), ) def test_paginate( app_fixture, db_session, is_query: bool, cache_key_template: str, full_data: bool, extra_data: bool, response_kwargs: bool, update_page: Callable, f_args: tuple, f_kwargs: dict, expected_result: dict or type, ): """Test paginate decorator.""" redis_client.flushall() include_count = f_kwargs["include_count"] func_result = get_query(db_session) if is_query else get_data() resp_dict = None if extra_data: resp_dict = get_extra_data() elif response_kwargs: resp_dict = get_response_kwargs() def func(*args, **kwargs) -> Query or list or tuple: assert args == f_args assert kwargs == f_kwargs return [func_result, resp_dict] if resp_dict is not None else func_result decorated_func = paginate( cache_key_template=cache_key_template, full_data=full_data, extra_data=extra_data, response_kwargs=response_kwargs, update_page=update_page, )(func) if isinstance(expected_result, type): with pytest.raises(expected_result): decorated_func(*f_args, **f_kwargs) else: result = decorated_func(*f_args, **f_kwargs) assert result == expected_result if cache_key_template and (include_count or full_data): redis_data = redis_client.get(keys.get_key(cache_key_template, *f_args, **f_kwargs)) redis_data = decode_str(redis_data) if full_data: full_result = func_result.all() if is_query else func_result assert redis_data == full_result if resp_dict is None else [func_result, resp_dict] else: assert redis_data == get_query(db_session).count()