Рефакторинг админских обработчиков - пагинация, сортировка, фильтрация. Финал
This commit is contained in:
@@ -7,14 +7,20 @@
|
||||
%%% Проверяет:
|
||||
%%% - получение списка записей аудита
|
||||
%%% - фильтрацию по admin_id
|
||||
%%% - пагинацию
|
||||
%%% - фильтрацию по action
|
||||
%%% - комбинацию фильтров (admin_id + action)
|
||||
%%% - пагинацию (limit/offset, x-total-count)
|
||||
%%% - сортировку по timestamp, action, admin_id
|
||||
%%% - комбинации сортировки с фильтрацией и пагинацией
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-module(admin_audit_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-export([test/0]).
|
||||
|
||||
%%%===================================================================
|
||||
%%% Главная тестовая функция
|
||||
%%%===================================================================
|
||||
-spec test() -> ok.
|
||||
test() ->
|
||||
ct:pal("=== Admin Audit Tests ==="),
|
||||
@@ -23,10 +29,9 @@ test() ->
|
||||
AdminToken = api_test_runner:get_admin_token(),
|
||||
SuperToken = api_test_runner:get_superadmin_token(),
|
||||
|
||||
% Создаём тестовую запись аудита
|
||||
% Создаём тестовые записи аудита
|
||||
Me = api_test_runner:admin_get(<<"/v1/admin/me">>, AdminToken),
|
||||
AdminId = maps:get(<<"id">>, Me),
|
||||
|
||||
Path = <<"/v1/admin/user/", UserId/binary>>,
|
||||
Body = #{<<"action">> => <<"block">>, <<"reason">> => <<"Test">>},
|
||||
api_test_runner:admin_put(Path, AdminToken, Body),
|
||||
@@ -34,30 +39,85 @@ test() ->
|
||||
Body2 = #{<<"action">> => <<"unblock">>, <<"reason">> => <<"Test">>},
|
||||
api_test_runner:admin_put(Path, AdminToken, Body2),
|
||||
|
||||
% ── Основные тесты ──
|
||||
test_list_audit(SuperToken),
|
||||
test_filter_audit(SuperToken, AdminId),
|
||||
test_audit_pagination(SuperToken),
|
||||
test_list_admin_forbidden(AdminToken),
|
||||
|
||||
% ── Фильтрация ──
|
||||
test_filter_audit_by_admin_id(SuperToken, AdminId),
|
||||
test_filter_audit_by_action(SuperToken),
|
||||
|
||||
% ── Комбинация фильтров ──
|
||||
test_filter_audit_combined(SuperToken, AdminId),
|
||||
|
||||
% ── Пагинация ──
|
||||
test_audit_pagination(SuperToken),
|
||||
test_audit_pagination_headers(SuperToken),
|
||||
|
||||
% ── Сортировка ──
|
||||
test_sort_by_timestamp_desc(SuperToken),
|
||||
test_sort_by_action_asc(SuperToken),
|
||||
test_sort_by_admin_id_asc(SuperToken),
|
||||
|
||||
% ── Комбинации сортировки с фильтрацией и пагинацией ──
|
||||
test_sort_combined_with_filter(SuperToken, AdminId),
|
||||
test_sort_combined_with_filter_and_pagination(SuperToken, AdminId),
|
||||
|
||||
ct:pal("=== All admin audit tests passed ==="),
|
||||
ok.
|
||||
|
||||
%%%===================================================================
|
||||
%%% Тестовые функции
|
||||
%%%===================================================================
|
||||
|
||||
%% @doc GET /v1/admin/audit – список всех записей аудита.
|
||||
test_list_audit(Token) ->
|
||||
ct:pal(" TEST: List all audit records"),
|
||||
ct:pal(" TEST: List all audit records"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit">>, Token),
|
||||
?assert(is_list(Records)),
|
||||
?assert(length(Records) >= 1),
|
||||
ct:pal(" OK: ~p records", [length(Records)]).
|
||||
ct:pal(" OK: ~p records", [length(Records)]).
|
||||
|
||||
test_filter_audit(Token, AdminId) ->
|
||||
ct:pal(" TEST: Filter audit by admin_id"),
|
||||
%% @doc GET /v1/admin/audit – запрет для обычного админа.
|
||||
test_list_admin_forbidden(Token) ->
|
||||
ct:pal(" TEST: List audit as non-superadmin (403)"),
|
||||
Resp = api_test_runner:admin_request(get, <<"/v1/admin/audit">>, Token),
|
||||
?assertMatch({ok, 403, _, _}, Resp),
|
||||
ct:pal(" OK: got 403").
|
||||
|
||||
%% ── Фильтрация ──
|
||||
|
||||
%% @doc Фильтрация по admin_id.
|
||||
test_filter_audit_by_admin_id(Token, AdminId) ->
|
||||
ct:pal(" TEST: Filter audit by admin_id"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit?admin_id=", AdminId/binary>>, Token),
|
||||
?assert(is_list(Records)),
|
||||
[?assertEqual(AdminId, maps:get(<<"admin_id">>, R)) || R <- Records],
|
||||
ct:pal(" OK: ~p records", [length(Records)]).
|
||||
ct:pal(" OK: ~p records", [length(Records)]).
|
||||
|
||||
%% @doc Фильтрация по action.
|
||||
test_filter_audit_by_action(Token) ->
|
||||
ct:pal(" TEST: Filter audit by action"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit?action=block_user">>, Token),
|
||||
?assert(is_list(Records)),
|
||||
[?assertEqual(<<"block_user">>, maps:get(<<"action">>, R)) || R <- Records],
|
||||
ct:pal(" OK: ~p records with action=block_user", [length(Records)]).
|
||||
|
||||
%% @doc Комбинация фильтров: admin_id + action.
|
||||
test_filter_audit_combined(Token, AdminId) ->
|
||||
ct:pal(" TEST: Combined filter (admin_id + action)"),
|
||||
Records = api_test_runner:admin_get(
|
||||
<<"/v1/admin/audit?admin_id=", AdminId/binary, "&action=unblock_user">>, Token),
|
||||
?assert(is_list(Records)),
|
||||
[?assertEqual(AdminId, maps:get(<<"admin_id">>, R)) || R <- Records],
|
||||
[?assertEqual(<<"unblock_user">>, maps:get(<<"action">>, R)) || R <- Records],
|
||||
ct:pal(" OK: ~p records match both criteria", [length(Records)]).
|
||||
|
||||
%% ── Пагинация ──
|
||||
|
||||
%% @doc Пагинация: limit=1, offset=0.
|
||||
test_audit_pagination(Token) ->
|
||||
ct:pal(" TEST: Audit pagination"),
|
||||
ct:pal(" TEST: Audit pagination"),
|
||||
Page1 = api_test_runner:admin_get(<<"/v1/admin/audit?limit=1&offset=0">>, Token),
|
||||
?assert(length(Page1) >= 1),
|
||||
Page2 = api_test_runner:admin_get(<<"/v1/admin/audit?limit=1&offset=1">>, Token),
|
||||
@@ -69,11 +129,66 @@ test_audit_pagination(Token) ->
|
||||
?assertNotEqual(Id1, Id2);
|
||||
_ -> ok
|
||||
end,
|
||||
ct:pal(" OK").
|
||||
ct:pal(" OK").
|
||||
|
||||
-spec test_list_admin_forbidden(binary()) -> ok.
|
||||
test_list_admin_forbidden(Token) ->
|
||||
ct:pal(" TEST: List audit as non-superadmin (403)"),
|
||||
Resp = api_test_runner:admin_request(get, <<"/v1/admin/audit">>, Token),
|
||||
?assertMatch({ok, 403, _, _}, Resp),
|
||||
ct:pal(" OK: got 403").
|
||||
%% @doc Проверка заголовков пагинации (x-total-count).
|
||||
test_audit_pagination_headers(Token) ->
|
||||
ct:pal(" TEST: Audit pagination headers (x-total-count)"),
|
||||
{ok, 200, Headers, _} = api_test_runner:admin_request(get,
|
||||
<<"/v1/admin/audit?limit=2&offset=0">>, Token),
|
||||
Total = list_to_integer(
|
||||
proplists:get_value("x-total-count", Headers, "0")),
|
||||
?assert(Total >= 1),
|
||||
ct:pal(" OK: total count = ~p", [Total]).
|
||||
|
||||
%% ── Сортировка ──
|
||||
|
||||
%% @doc Сортировка по timestamp по убыванию.
|
||||
test_sort_by_timestamp_desc(Token) ->
|
||||
ct:pal(" TEST: Sort audit by timestamp desc"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit?sort=timestamp&order=desc">>, Token),
|
||||
Timestamps = [maps:get(<<"timestamp">>, R) || R <- Records],
|
||||
?assertEqual(lists:reverse(lists:sort(Timestamps)), Timestamps),
|
||||
ct:pal(" OK: sorted by timestamp desc").
|
||||
|
||||
%% @doc Сортировка по action по возрастанию.
|
||||
test_sort_by_action_asc(Token) ->
|
||||
ct:pal(" TEST: Sort audit by action asc"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit?sort=action&order=asc">>, Token),
|
||||
Actions = [maps:get(<<"action">>, R) || R <- Records],
|
||||
?assertEqual(lists:sort(Actions), Actions),
|
||||
ct:pal(" OK: sorted by action asc").
|
||||
|
||||
%% @doc Сортировка по admin_id по возрастанию.
|
||||
test_sort_by_admin_id_asc(Token) ->
|
||||
ct:pal(" TEST: Sort audit by admin_id asc"),
|
||||
Records = api_test_runner:admin_get(<<"/v1/admin/audit?sort=admin_id&order=asc">>, Token),
|
||||
AdminIds = [maps:get(<<"admin_id">>, R) || R <- Records],
|
||||
?assertEqual(lists:sort(AdminIds), AdminIds),
|
||||
ct:pal(" OK: sorted by admin_id asc").
|
||||
|
||||
%% ── Комбинации сортировки с фильтрацией и пагинацией ──
|
||||
|
||||
%% @doc Сортировка + фильтр: admin_id + action, сортировка по timestamp asc.
|
||||
test_sort_combined_with_filter(Token, AdminId) ->
|
||||
ct:pal(" TEST: Sort audit (timestamp asc) filtered by admin_id + action"),
|
||||
Records = api_test_runner:admin_get(
|
||||
<<"/v1/admin/audit?admin_id=", AdminId/binary, "&action=unblock_user&sort=timestamp&order=asc">>, Token),
|
||||
[?assertEqual(AdminId, maps:get(<<"admin_id">>, R)) || R <- Records],
|
||||
[?assertEqual(<<"unblock_user">>, maps:get(<<"action">>, R)) || R <- Records],
|
||||
Timestamps = [maps:get(<<"timestamp">>, R) || R <- Records],
|
||||
?assertEqual(lists:sort(Timestamps), Timestamps),
|
||||
ct:pal(" OK: ~p records sorted", [length(Records)]).
|
||||
|
||||
%% @doc Сортировка + фильтр + пагинация: action=block, сортировка по timestamp desc, limit=1.
|
||||
test_sort_combined_with_filter_and_pagination(Token, _AdminId) ->
|
||||
ct:pal(" TEST: Filter + sort + pagination (action=block_user, sort=timestamp desc, limit=1)"),
|
||||
{ok, 200, Headers, Body} = api_test_runner:admin_request(get,
|
||||
<<"/v1/admin/audit?action=block_user&sort=timestamp&order=desc&limit=1&offset=0">>, Token),
|
||||
Records = jsx:decode(list_to_binary(Body), [return_maps]),
|
||||
?assert(length(Records) =< 1),
|
||||
[?assertEqual(<<"block_user">>, maps:get(<<"action">>, R)) || R <- Records],
|
||||
Total = list_to_integer(
|
||||
proplists:get_value("x-total-count", Headers, "0")),
|
||||
?assert(Total >= 1),
|
||||
ct:pal(" OK: got ~p records (total ~p)", [length(Records), Total]).
|
||||
Reference in New Issue
Block a user