import os from typing import Any, Callable, Dict, List, Tuple import pytest import requests_mock from src.config import config from src.constants import Model from src.clients.atlas_auth_api import AtlasAuthClientConfig from src.clients.atlas_data_api import AtlasDataClientConfig from src.clients.user_data_api import UserDataClientConfig from src.index import handler def get_user_id(index: int, with_prefix: bool = False) -> str: result = f"userid{index:04d}" if with_prefix: result = f"auth0|{result}" return result def get_user_active(index: int) -> bool: return bool(index % 20) def get_user_id_inactive(accounts_count: int, users_count: int, *args) -> List[str]: return [ get_user_id(i) for i in range(accounts_count) if (not get_user_active(i) or i > users_count) and i not in args ] def wrap_response(data: list) -> list: return [{"json": item} for item in data] def get_response(func: Callable, count: int) -> List[dict]: return wrap_response([{"items": func(index)} for index in range(count)]) def get_inactive_accounts_response(index: int) -> dict: id_list = list(range(100 * index, 100 * (index + 1))) if index < 2 else [] return {"accounts": id_list, "devices": id_list[:-1], "settings": id_list[:-2], "favorites": id_list[:-3]} def get_events_response(index: int) -> dict: return {"events": list(range(100 * index, 100 * (index + 1))) if index < 3 else []} def get_messages_response(index: int) -> dict: id_list = ( list(range(config.DELETE_MESSAGES_LIMIT * index, config.DELETE_MESSAGES_LIMIT * (index + 1))) if index < 5 else [] ) return {"messages": id_list, "push_messages": id_list[:-2], "feed_messages": id_list[:-4]} def generate_accounts_response(request, context) -> dict: user_id_list = request.qs["user_id"] id_list = [int(user_id[6:]) for user_id in user_id_list] return {"items": {"accounts": id_list, "devices": id_list[:-2]}} def agg_history(history_list) -> Dict[tuple, tuple]: result = {} for item in history_list: endpoint_key = (item.method, item.path) current_params = item.json() if item.method == "POST" else item.qs full_params = result.get(endpoint_key, {}) for key, value in current_params.items(): if isinstance(value, list): if len(value) == 1: full_params[key] = value[0] else: full_params[key] = list(sorted(full_params.get(key, []) + value)) else: full_params[key] = value result[endpoint_key] = full_params return result @pytest.mark.parametrize( "model,include,call_count,expected_result", ( ( Model.ACCOUNTS, "devices", 42, { ("POST", "/oauth/token"): { "audience": "atlasum|api_read", "grant_type": "client_credentials", "client_id": os.environ["ATLASAPI_CLIENT_ID"], "client_secret": os.environ["ATLASAPI_CLIENT_SECRET"], }, ("GET", "/private/accounts/"): {"is_active": "true", "include": "user_id"}, ("GET", "/private/accounts/"): { "is_active": "false", "include": "user_id", "user_id": get_user_id_inactive(2951, 2600) }, ("GET", "/api/v2/users/status_lookup"): {"id": [get_user_id(i, True) for i in range(2951)]}, ("DELETE", "/private/accounts/"): { "user_id": get_user_id_inactive(2951, 2600, 0, 20, 40), "include": "devices" }, }, ), ( Model.INACTIVE_ACCOUNTS, "messages,push_messages", 3, { ("DELETE", "/private/accounts/inactive/"): { "days": str(config.STORED_PERIOD), "include": "messages,push_messages", "limit": str(config.DELETE_INACTIVE_ACCOUNTS_LIMIT), }, }, ), ( Model.EVENTS, "abc", 4, { ("DELETE", "/private/events/"): { "days": str(config.STORED_PERIOD), "limit": str(config.DELETE_EVENTS_LIMIT) }, }, ), ( Model.MESSAGES, "push_messages,feed_messages", 6, { ("DELETE", "/private/messages/"): { "days": str(config.STORED_PERIOD), "type": "push_messages,feed_messages", "limit": str(config.DELETE_MESSAGES_LIMIT), }, }, ), ) ) @requests_mock.Mocker(kw="requests_mocker") def test_handler( model: str, include: str, call_count: int, expected_result: Dict[Tuple[str, str], Dict[str, Any]], **kwargs, ): requests_mocker = kwargs["requests_mocker"] accounts_count, users_count = 2951, 2600 config.MODEL_PATH = model config.DEACTIVATE_ACCOUNTS_INCLUDE = include config.DELETE_INACTIVE_ACCOUNTS_INCLUDE = include config.DELETE_MESSAGES_TYPES = include if model == Model.ACCOUNTS: atlas_auth_config = AtlasAuthClientConfig() requests_mocker.register_uri( "POST", f"{atlas_auth_config._schema}://{atlas_auth_config._host}/oauth/token", json={"access_token": "test_token"}, ) atlas_data_config = AtlasDataClientConfig() requests_mocker.register_uri( "GET", f"{atlas_data_config._schema}://{atlas_data_config._host}/api/v2/users/status_lookup", wrap_response( [ ( [ {"id": get_user_id(i, with_prefix=True), "is_active": get_user_active(i)} for i in range(count, min(count + config.ATLAS_CHECK_LIMIT, users_count)) ] if count < users_count else [] ) for count in range(0, accounts_count, config.ATLAS_CHECK_LIMIT) ] ) ) user_data_config = UserDataClientConfig() requests_mocker.register_uri( "GET", f"{user_data_config._schema}://{user_data_config._host}/private/accounts/?is_active=true", json={"items": [get_user_id(i) for i in range(accounts_count)]}, ) requests_mocker.register_uri( "GET", f"{user_data_config._schema}://{user_data_config._host}/private/accounts/?is_active=false", json={"items": [get_user_id(0), get_user_id(20), get_user_id(40)]}, ) requests_mocker.register_uri( "DELETE", f"{user_data_config._schema}://{user_data_config._host}/private/accounts/", json=generate_accounts_response, ) elif model == Model.INACTIVE_ACCOUNTS: user_data_config = UserDataClientConfig() requests_mocker.register_uri( "DELETE", f"{user_data_config._schema}://{user_data_config._host}/private/accounts/inactive/", get_response(get_inactive_accounts_response, 4), ) elif model == Model.EVENTS: user_data_config = UserDataClientConfig() requests_mocker.register_uri( "DELETE", f"{user_data_config._schema}://{user_data_config._host}/private/events/", get_response(get_events_response, 5), ) elif model == Model.MESSAGES: user_data_config = UserDataClientConfig() requests_mocker.register_uri( "DELETE", f"{user_data_config._schema}://{user_data_config._host}/private/messages/", get_response(get_messages_response, 7), ) handler() history = requests_mocker.request_history assert len(history) == call_count assert agg_history(history) == expected_result