Files
EventHubBack/test/api/admins/admin_reports_tests.erl
T

239 lines
10 KiB
Erlang

%%%-------------------------------------------------------------------
%%% @doc Тесты административного API для управления жалобами.
%%%
%%% Покрывает эндпоинты:
%%% GET /v1/admin/reports
%%% GET /v1/admin/reports/:id
%%% PUT /v1/admin/reports/:id
%%%
%%% Проверяет:
%%% - получение списка жалоб
%%% - получение жалобы по ID
%%% - обновление статуса жалобы (review, dismiss)
%%% - фильтрацию по статусу и типу цели
%%% - комбинации фильтров (status + target_type)
%%% - сортировку по created_at и status
%%% - комбинации фильтрации с сортировкой
%%% - пагинацию (limit/offset, x-total-count)
%%% - комбинации фильтрации, сортировки и пагинации
%%% @end
%%%-------------------------------------------------------------------
-module(admin_reports_tests).
-include_lib("eunit/include/eunit.hrl").
-export([test/0]).
%%%===================================================================
%%% Главная тестовая функция
%%%===================================================================
-spec test() -> ok.
test() ->
ct:pal("=== Admin Reports Tests ==="),
Token = api_test_runner:get_admin_token(),
UserToken = api_test_runner:get_user_token(),
CalId = api_test_runner:create_calendar(UserToken, #{title => <<"ReportsTestCal">>}),
EventId = api_test_runner:create_event(UserToken, CalId, #{
title => <<"Event for reporting">>,
start_time => api_test_runner:future_date(),
duration => 60
}),
#{<<"id">> := Report1Id} = api_test_runner:client_post(<<"/v1/reports">>, UserToken, #{
<<"target_type">> => <<"event">>,
<<"target_id">> => EventId,
<<"reason">> => <<"Inappropriate content">>
}),
#{<<"id">> := Report2Id} = api_test_runner:client_post(<<"/v1/reports">>, UserToken, #{
<<"target_type">> => <<"event">>,
<<"target_id">> => EventId,
<<"reason">> => <<"Spam">>
}),
test_list_reports(Token, Report1Id),
test_get_report(Token, Report1Id),
test_review_report(Token, Report1Id),
test_dismiss_report(Token, Report2Id),
test_filter_reports(Token),
test_filter_combined_status_target(Token),
test_sort_by_created_at_desc(Token),
test_sort_by_created_at_asc(Token),
test_sort_by_status_asc(Token),
test_filter_status_sort_created_at(Token),
test_filter_target_sort_status(Token),
test_report_pagination(Token),
test_pagination_headers(Token),
test_filter_status_with_pagination(Token),
test_filter_sort_pagination_combined(Token),
ct:pal("=== All admin reports tests passed ==="),
ok.
%%%===================================================================
%%% Тестовые функции
%%%===================================================================
-spec test_list_reports(binary(), binary()) -> ok.
test_list_reports(Token, ReportId) ->
ct:pal(" TEST: List all reports"),
Reports = api_test_runner:admin_get(<<"/v1/admin/reports">>, Token),
?assert(is_list(Reports)),
?assert(length(Reports) >= 2),
?assert(lists:any(fun(R) -> maps:get(<<"id">>, R) =:= ReportId end, Reports)),
ct:pal(" OK: ~p reports", [length(Reports)]).
-spec test_get_report(binary(), binary()) -> ok.
test_get_report(Token, ReportId) ->
ct:pal(" TEST: Get report by ID"),
Path = <<"/v1/admin/reports/", ReportId/binary>>,
Report = api_test_runner:admin_get(Path, Token),
?assertEqual(ReportId, maps:get(<<"id">>, Report)),
?assertEqual(<<"pending">>, maps:get(<<"status">>, Report)),
ct:pal(" OK").
-spec test_review_report(binary(), binary()) -> ok.
test_review_report(Token, ReportId) ->
ct:pal(" TEST: Review report (set status to reviewed)"),
Path = <<"/v1/admin/reports/", ReportId/binary>>,
Updated = api_test_runner:admin_put(Path, Token, #{<<"status">> => <<"reviewed">>}),
?assertEqual(<<"reviewed">>, maps:get(<<"status">>, Updated)),
ct:pal(" OK").
-spec test_dismiss_report(binary(), binary()) -> ok.
test_dismiss_report(Token, ReportId) ->
ct:pal(" TEST: Dismiss report (set status to dismissed)"),
Path = <<"/v1/admin/reports/", ReportId/binary>>,
Updated = api_test_runner:admin_put(Path, Token, #{<<"status">> => <<"dismissed">>}),
?assertEqual(<<"dismissed">>, maps:get(<<"status">>, Updated)),
ct:pal(" OK").
-spec test_filter_reports(binary()) -> ok.
test_filter_reports(Token) ->
ct:pal(" TEST: Filter reports by status=reviewed"),
Reports = api_test_runner:admin_get(<<"/v1/admin/reports?status=reviewed">>, Token),
?assert(is_list(Reports)),
[?assertEqual(<<"reviewed">>, maps:get(<<"status">>, R)) || R <- Reports],
ct:pal(" OK: ~p reviewed reports", [length(Reports)]),
ct:pal(" TEST: Filter reports by target_type=event"),
Reports2 = api_test_runner:admin_get(<<"/v1/admin/reports?target_type=event">>, Token),
?assert(is_list(Reports2)),
[?assertEqual(<<"event">>, maps:get(<<"target_type">>, R)) || R <- Reports2],
ct:pal(" OK: ~p reports for events", [length(Reports2)]).
-spec test_filter_combined_status_target(binary()) -> ok.
test_filter_combined_status_target(Token) ->
ct:pal(" TEST: Combined filter (status=dismissed & target_type=event)"),
Reports = api_test_runner:admin_get(
<<"/v1/admin/reports?status=dismissed&target_type=event">>, Token),
?assert(is_list(Reports)),
[?assertEqual(<<"dismissed">>, maps:get(<<"status">>, R)) || R <- Reports],
[?assertEqual(<<"event">>, maps:get(<<"target_type">>, R)) || R <- Reports],
ct:pal(" OK: ~p reports match both criteria", [length(Reports)]).
-spec test_sort_by_created_at_desc(binary()) -> ok.
test_sort_by_created_at_desc(Token) ->
ct:pal(" TEST: Sort by created_at desc"),
{ok, 200, _, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?sort=created_at&order=desc">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
Dates = [maps:get(<<"created_at">>, R) || R <- Reports],
Sorted = lists:reverse(lists:sort(Dates)),
?assertEqual(Sorted, Dates),
ct:pal(" OK: sorted by created_at desc").
-spec test_sort_by_created_at_asc(binary()) -> ok.
test_sort_by_created_at_asc(Token) ->
ct:pal(" TEST: Sort by created_at asc"),
{ok, 200, _, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?sort=created_at&order=asc">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
Dates = [maps:get(<<"created_at">>, R) || R <- Reports],
?assertEqual(lists:sort(Dates), Dates),
ct:pal(" OK: sorted by created_at asc").
-spec test_sort_by_status_asc(binary()) -> ok.
test_sort_by_status_asc(Token) ->
ct:pal(" TEST: Sort by status asc"),
{ok, 200, _, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?sort=status&order=asc">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
Statuses = [maps:get(<<"status">>, R) || R <- Reports],
?assertEqual(lists:sort(Statuses), Statuses),
ct:pal(" OK: sorted by status asc").
-spec test_filter_status_sort_created_at(binary()) -> ok.
test_filter_status_sort_created_at(Token) ->
ct:pal(" TEST: Filter status=reviewed + sort by created_at asc"),
{ok, 200, _, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?status=reviewed&sort=created_at&order=asc">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
[?assertEqual(<<"reviewed">>, maps:get(<<"status">>, R)) || R <- Reports],
Dates = [maps:get(<<"created_at">>, R) || R <- Reports],
?assertEqual(lists:sort(Dates), Dates),
ct:pal(" OK: ~p reports sorted", [length(Reports)]).
-spec test_filter_target_sort_status(binary()) -> ok.
test_filter_target_sort_status(Token) ->
ct:pal(" TEST: Filter target_type=event + sort by status desc"),
{ok, 200, _, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?target_type=event&sort=status&order=desc">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
[?assertEqual(<<"event">>, maps:get(<<"target_type">>, R)) || R <- Reports],
Statuses = [maps:get(<<"status">>, R) || R <- Reports],
?assertEqual(lists:reverse(lists:sort(Statuses)), Statuses),
ct:pal(" OK: ~p reports sorted", [length(Reports)]).
-spec test_report_pagination(binary()) -> ok.
test_report_pagination(Token) ->
ct:pal(" TEST: Report pagination"),
Page1 = api_test_runner:admin_get(<<"/v1/admin/reports?limit=1&offset=0">>, Token),
?assert(length(Page1) >= 1),
Page2 = api_test_runner:admin_get(<<"/v1/admin/reports?limit=1&offset=1">>, Token),
?assert(length(Page2) >= 0),
case {Page1, Page2} of
{[First|_], [Second|_]} ->
Id1 = maps:get(<<"id">>, First),
Id2 = maps:get(<<"id">>, Second),
?assertNotEqual(Id1, Id2);
_ -> ok
end,
ct:pal(" OK").
-spec test_pagination_headers(binary()) -> ok.
test_pagination_headers(Token) ->
ct:pal(" TEST: Pagination headers (x-total-count)"),
{ok, 200, Headers, _} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?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]).
-spec test_filter_status_with_pagination(binary()) -> ok.
test_filter_status_with_pagination(Token) ->
ct:pal(" TEST: Filter status=dismissed + pagination (limit=1)"),
{ok, 200, Headers, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?status=dismissed&limit=1&offset=0">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
?assert(length(Reports) =< 1),
[?assertEqual(<<"dismissed">>, maps:get(<<"status">>, R)) || R <- Reports],
Total = list_to_integer(
proplists:get_value("x-total-count", Headers, "0")),
?assert(Total >= 1),
ct:pal(" OK: total count = ~p", [Total]).
-spec test_filter_sort_pagination_combined(binary()) -> ok.
test_filter_sort_pagination_combined(Token) ->
ct:pal(" TEST: Filter target_type=event + sort by created_at desc + pagination (limit=1)"),
{ok, 200, Headers, Body} = api_test_runner:admin_request(get,
<<"/v1/admin/reports?target_type=event&sort=created_at&order=desc&limit=1&offset=0">>, Token, <<"">>),
Reports = jsx:decode(list_to_binary(Body), [return_maps]),
?assert(length(Reports) =< 1),
[?assertEqual(<<"event">>, maps:get(<<"target_type">>, R)) || R <- Reports],
Total = list_to_integer(
proplists:get_value("x-total-count", Headers, "0")),
?assert(Total >= 1),
ct:pal(" OK: total count = ~p", [Total]).