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

209 lines
9.8 KiB
Erlang
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
%%%-------------------------------------------------------------------
%%% @doc Тесты административного API для управления событиями.
%%% Покрывает эндпоинты:
%%% GET /v1/admin/events
%%% GET /v1/admin/events/:id
%%% PUT /v1/admin/events/:id
%%% DELETE /v1/admin/events/:id
%%% Проверяет фильтрацию, сортировку, пагинацию и их комбинации.
%%% @end
%%%-------------------------------------------------------------------
-module(admin_events_tests).
-include_lib("eunit/include/eunit.hrl").
-export([test/0]).
test() ->
ct:pal("=== Admin Events Tests ==="),
Token = api_test_runner:get_admin_token(),
UserToken = api_test_runner:get_user_token(),
%% Создаём тестовый календарь и два события
CalId = api_test_runner:create_calendar(UserToken, #{title => <<"EventsTestCal">>}),
Event1Id = api_test_runner:create_event(UserToken, CalId, #{
title => <<"Test Event Alpha">>,
start_time => api_test_runner:future_date(),
duration => 60
}),
Event2Id = api_test_runner:create_event(UserToken, CalId, #{
title => <<"Beta Event">>,
start_time => api_test_runner:future_date(),
duration => 60
}),
%% Выполняем тесты
test_list_events(Token, CalId, Event1Id, Event2Id),
test_get_event(Token, Event1Id),
test_update_event(Token, Event1Id),
test_delete_event(Token, Event2Id),
test_filter_events(Token, CalId),
test_search_events(Token, CalId),
test_event_pagination(Token, CalId),
%% Комбинации фильтров
test_filter_combined_status_calendar(Token, CalId),
test_filter_combined_title_status(Token, CalId),
%% Сортировка
test_sort_by_title(Token, CalId),
test_sort_by_start_time(Token, CalId),
%% Фильтр + сортировка
test_filter_status_sort_title(Token, CalId),
test_search_sort_created_at(Token, CalId),
%% Фильтр + сортировка + пагинация
test_filter_sort_pagination_combined(Token, CalId),
%% Проверка заголовка x-total-count
test_pagination_headers(Token, CalId),
test_delete_event(Token, Event1Id),
ct:pal("=== All admin events tests passed ==="),
ok.
%% @doc GET /v1/admin/events список событий (базовая проверка).
test_list_events(Token, _CalId, _Event1Id, _Event2Id) ->
ct:pal(" TEST: List all events"),
Events = api_test_runner:admin_get(<<"/v1/admin/events">>, Token),
?assert(is_list(Events)),
?assert(length(Events) >= 2),
ct:pal(" OK: ~p events found", [length(Events)]).
%% @doc GET /v1/admin/events/:id получение события по ID.
test_get_event(Token, EventId) ->
ct:pal(" TEST: Get event by ID"),
Path = <<"/v1/admin/events/", EventId/binary>>,
Event = api_test_runner:admin_get(Path, Token),
?assertEqual(EventId, maps:get(<<"id">>, Event)),
?assertEqual(<<"active">>, maps:get(<<"status">>, Event)),
ct:pal(" OK: ~s", [maps:get(<<"title">>, Event)]).
%% @doc PUT /v1/admin/events/:id обновление события.
test_update_event(Token, EventId) ->
ct:pal(" TEST: Update event"),
Path = <<"/v1/admin/events/", EventId/binary>>,
Updates = #{<<"title">> => <<"Updated by admin">>, <<"description">> => <<"Test update">>},
Updated = api_test_runner:admin_put(Path, Token, Updates),
?assertEqual(<<"Updated by admin">>, maps:get(<<"title">>, Updated)),
?assertEqual(<<"Test update">>, maps:get(<<"description">>, Updated)),
ct:pal(" OK").
%% @doc DELETE /v1/admin/events/:id удаление события.
test_delete_event(Token, EventId) ->
ct:pal(" TEST: Delete event"),
Path = <<"/v1/admin/events/", EventId/binary>>,
Deleted = api_test_runner:admin_delete(Path, Token),
?assertEqual(<<"deleted">>, maps:get(<<"status">>, Deleted)),
ct:pal(" OK").
%% @doc GET /v1/admin/events?status=active фильтрация по статусу.
test_filter_events(Token, CalId) ->
ct:pal(" TEST: Filter events by status=active"),
Path = <<"/v1/admin/events?calendar_id=", CalId/binary, "&status=active">>,
Events = api_test_runner:admin_get(Path, Token),
?assert(is_list(Events)),
[?assertEqual(<<"active">>, maps:get(<<"status">>, E)) || E <- Events],
ct:pal(" OK: ~p events", [length(Events)]).
%% @doc GET /v1/admin/events?q=... поиск по подстроке.
test_search_events(Token, CalId) ->
ct:pal(" TEST: Search events by title substring"),
Path = <<"/v1/admin/events?calendar_id=", CalId/binary, "&q=Updated">>,
Events = api_test_runner:admin_get(Path, Token),
?assert(is_list(Events)),
?assert(length(Events) >= 1),
[?assertNotEqual(nomatch, binary:match(maps:get(<<"title">>, E), <<"Updated">>)) || E <- Events],
ct:pal(" OK: ~p results", [length(Events)]).
%% @doc GET /v1/admin/events?limit=...&offset=... пагинация.
test_event_pagination(Token, CalId) ->
ct:pal(" TEST: Event pagination"),
Base = <<"/v1/admin/events?calendar_id=", CalId/binary, "&status=all&sort=title&order=asc">>,
Page1 = api_test_runner:admin_get(<<Base/binary, "&limit=1&offset=0">>, Token),
?assertEqual(1, length(Page1)),
Page2 = api_test_runner:admin_get(<<Base/binary, "&limit=1&offset=1">>, Token),
?assertEqual(1, length(Page2)),
Id1 = maps:get(<<"id">>, hd(Page1)),
Id2 = maps:get(<<"id">>, hd(Page2)),
?assertNotEqual(Id1, Id2),
ct:pal(" OK").
%% ── Комбинации фильтров ──
test_filter_combined_status_calendar(Token, CalId) ->
ct:pal(" TEST: Filter by status=active + calendar_id"),
Path = <<"/v1/admin/events?status=active&calendar_id=", CalId/binary>>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
[?assertEqual(<<"active">>, maps:get(<<"status">>, E)) || E <- Events],
[?assertEqual(CalId, maps:get(<<"calendar_id">>, E)) || E <- Events],
ct:pal(" OK: ~p events", [length(Events)]).
test_filter_combined_title_status(Token, CalId) ->
ct:pal(" TEST: Filter by title=Updated + status=active"),
Path = <<"/v1/admin/events?title=Updated%20by%20admin&status=active&calendar_id=", CalId/binary>>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
[?assertEqual(<<"Updated by admin">>, maps:get(<<"title">>, E)) || E <- Events],
[?assertEqual(<<"active">>, maps:get(<<"status">>, E)) || E <- Events],
ct:pal(" OK: ~p events", [length(Events)]).
%% ── Сортировка ──
test_sort_by_title(Token, CalId) ->
ct:pal(" TEST: Sort by title asc"),
Path = <<"/v1/admin/events?calendar_id=", CalId/binary, "&sort=title&order=asc">>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
Titles = [maps:get(<<"title">>, E) || E <- Events],
?assertEqual(lists:sort(Titles), Titles),
ct:pal(" OK: sorted by title asc").
test_sort_by_start_time(Token, CalId) ->
ct:pal(" TEST: Sort by start_time desc"),
Path = <<"/v1/admin/events?calendar_id=", CalId/binary, "&sort=start_time&order=desc">>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
Dates = [maps:get(<<"start_time">>, E) || E <- Events],
Sorted = lists:reverse(lists:sort(Dates)),
?assertEqual(Sorted, Dates),
ct:pal(" OK: sorted by start_time desc").
%% ── Фильтр + сортировка ──
test_filter_status_sort_title(Token, CalId) ->
ct:pal(" TEST: Filter status=active + sort by title desc"),
Path = <<"/v1/admin/events?status=active&calendar_id=", CalId/binary, "&sort=title&order=desc">>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
[?assertEqual(<<"active">>, maps:get(<<"status">>, E)) || E <- Events],
Titles = [maps:get(<<"title">>, E) || E <- Events],
?assertEqual(lists:reverse(lists:sort(Titles)), Titles),
ct:pal(" OK: ~p events", [length(Events)]).
test_search_sort_created_at(Token, CalId) ->
ct:pal(" TEST: Search q=Updated + sort by created_at asc"),
Path = <<"/v1/admin/events?q=Updated&calendar_id=", CalId/binary, "&sort=created_at&order=asc">>,
{ok, 200, _, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
[?assert(binary:match(maps:get(<<"title">>, E), <<"Updated">>) =/= nomatch) || E <- Events],
Dates = [maps:get(<<"created_at">>, E) || E <- Events],
?assertEqual(lists:sort(Dates), Dates),
ct:pal(" OK: ~p events", [length(Events)]).
%% ── Фильтр + сортировка + пагинация ──
test_filter_sort_pagination_combined(Token, CalId) ->
ct:pal(" TEST: status=active + sort=start_time desc + limit=1"),
Path = <<"/v1/admin/events?status=active&calendar_id=", CalId/binary, "&sort=start_time&order=desc&limit=1&offset=0">>,
{ok, 200, Headers, Body} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Events = jsx:decode(list_to_binary(Body), [return_maps]),
?assert(length(Events) =< 1),
[?assertEqual(<<"active">>, maps:get(<<"status">>, E)) || E <- Events],
Total = list_to_integer(proplists:get_value("x-total-count", Headers, "0")),
?assert(Total >= 1),
ct:pal(" OK: ~p events (total ~p)", [length(Events), Total]).
%% ── Заголовки пагинации ──
test_pagination_headers(Token, CalId) ->
ct:pal(" TEST: Pagination headers (x-total-count)"),
Path = <<"/v1/admin/events?calendar_id=", CalId/binary, "&limit=2&offset=0">>,
{ok, 200, Headers, _} = api_test_runner:admin_request(get, Path, Token, <<"">>),
Total = list_to_integer(proplists:get_value("x-total-count", Headers, "0")),
?assert(Total >= 1),
ct:pal(" OK: total count = ~p", [Total]).