209 lines
9.8 KiB
Erlang
209 lines
9.8 KiB
Erlang
%%%-------------------------------------------------------------------
|
||
%%% @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]). |