Пагинация, фильтры и сортировки Часть 1 #20

This commit is contained in:
2026-05-09 13:38:54 +03:00
parent ecf68ee300
commit a34e36b966
5 changed files with 316 additions and 40 deletions

View File

@@ -43,25 +43,25 @@ test() ->
{ok, {{_, 200, _}, _, StatsResp1}} = httpc:request(get, {AdminURL ++ "/v1/admin/stats", [{"Authorization", "Bearer " ++ binary_to_list(SuperadminToken)}]}, [], []),
Stats1 = jsx:decode(list_to_binary(StatsResp1), [return_maps]),
ct:pal(" OK (Stats 1: ~p)~n", [Stats1]),
map_size(Stats1) > 0,
true = map_size(Stats1) > 0,
ct:pal(" Admin stats (admin)... "),
{ok, {{_, 200, _}, _, StatsResp2}} = httpc:request(get, {AdminURL ++ "/v1/admin/stats", [{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]}, [], []),
Stats2 = jsx:decode(list_to_binary(StatsResp2), [return_maps]),
ct:pal(" OK (Stats 1: ~p)~n", [Stats2]),
map_size(Stats2) > 0,
true = map_size(Stats2) > 0,
ct:pal(" Admin stats (moderator)... "),
{ok, {{_, 200, _}, _, StatsResp3}} = httpc:request(get, {AdminURL ++ "/v1/admin/stats", [{"Authorization", "Bearer " ++ binary_to_list(ModeratorToken)}]}, [], []),
Stats3 = jsx:decode(list_to_binary(StatsResp3), [return_maps]),
ct:pal(" OK (Stats 1: ~p)~n", [Stats3]),
map_size(Stats3) > 0,
true = map_size(Stats3) > 0,
ct:pal(" Admin stats (support)... "),
{ok, {{_, 200, _}, _, StatsResp4}} = httpc:request(get, {AdminURL ++ "/v1/admin/stats", [{"Authorization", "Bearer " ++ binary_to_list(SupportToken)}]}, [], []),
Stats4 = jsx:decode(list_to_binary(StatsResp4), [return_maps]),
ct:pal(" OK (Stats 1: ~p)~n", [Stats4]),
map_size(Stats4) > 0,
true = map_size(Stats4) > 0,
%% TEST 4: List users
ct:pal(" TEST 4: List users... "),
@@ -356,5 +356,158 @@ test() ->
[], []),
ct:pal("OK~n"),
%% ========================================================
%% Extended Admin Events Search & Filter Tests
%% ========================================================
%% ── Подготовка изолированных данных ──
ct:pal(" Preparing isolated search test data... "),
UserToken = api_test_runner:get_user_token(),
SearchCalId = api_test_runner:create_calendar(UserToken, #{title => <<"SearchTestCal">>}),
SearchCalIdStr = binary_to_list(SearchCalId),
AlphaId = api_test_runner:create_event(UserToken, SearchCalId, #{
title => <<"Test Event Alpha">>,
start_time => api_SUITE:future_date(),
duration => 60
}),
BetaId = api_test_runner:create_event(UserToken, SearchCalId, #{
title => <<"Beta Event">>,
start_time => api_SUITE:future_date(),
duration => 60
}),
_AlphaConfId = api_test_runner:create_event(UserToken, SearchCalId, #{
title => <<"Alpha Conference">>,
start_time => api_SUITE:future_date(),
duration => 60
}),
% Отменяем BetaId через административный эндпоинт (PUT /v1/admin/events/:id)
ct:pal(" Cancelling Beta Event (admin)... "),
{ok, {{_, 200, _}, _, _}} =
httpc:request(put, {AdminURL ++ "/v1/admin/events/" ++ binary_to_list(BetaId),
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}],
"application/json", jsx:encode(#{<<"status">> => <<"cancelled">>})}, [], []),
ct:pal("OK~n"),
%% ── TEST 34: Filter by status=active ──
ct:pal(" TEST 34: Filter events by status=active... "),
{ok, {{_, 200, _}, _, Body34}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=active",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events34 = jsx:decode(list_to_binary(Body34), [return_maps]),
ct:pal("DEBUG: events34 count = ~p", [length(Events34)]),
ct:pal("DEBUG: events34 = ~p", [Events34]),
true = (length(Events34) >= 2),
Ids34 = [maps:get(<<"id">>, E) || E <- Events34],
ct:pal("OK (count: ~p, ids: ~p)~n", [length(Events34), Ids34]),
%% ── TEST 35: Filter by status=cancelled ──
ct:pal(" TEST 35: Filter events by status=cancelled... "),
{ok, {{_, 200, _}, _, Body35}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=cancelled",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events35 = jsx:decode(list_to_binary(Body35), [return_maps]),
ct:pal("DEBUG: Events35 count = ~p", [length(Events35)]),
ct:pal("DEBUG: Events35 = ~p", [Events35]),
true = (length(Events35) >= 1),
ct:pal("OK (count: ~p)~n", [length(Events35)]),
%% ── TEST 36: Filter by status=all ──
ct:pal(" TEST 36: Filter events by status=all... "),
{ok, {{_, 200, _}, _, Body36}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=all",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events36 = jsx:decode(list_to_binary(Body36), [return_maps]),
ct:pal("DEBUG: Events36 count = ~p", [length(Events36)]),
ct:pal("DEBUG: Events36 = ~p", [Events36]),
true = (length(Events36) >= 3),
ct:pal("OK (count: ~p)~n", [length(Events36)]),
%% ── TEST 37: Filter by calendar_id ──
ct:pal(" TEST 37: Filter by calendar_id... "),
{ok, {{_, 200, _}, _, Body37}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr,
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events37 = jsx:decode(list_to_binary(Body37), [return_maps]),
ct:pal("DEBUG: Events37 count = ~p", [length(Events37)]),
ct:pal("DEBUG: Events37 = ~p", [Events37]),
true = (length(Events37) >= 3),
ct:pal("OK (count: ~p)~n", [length(Events37)]),
%% ── TEST 38: Exact title match ──
ct:pal(" TEST 38: Exact title match... "),
{ok, {{_, 200, _}, _, Body38}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&title=Test%20Event%20Alpha",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events38 = jsx:decode(list_to_binary(Body38), [return_maps]),
ct:pal("DEBUG: Events38 count = ~p", [length(Events38)]),
ct:pal("DEBUG: Events38 = ~p", [Events38]),
1 = length(Events38),
#{<<"id">> := AlphaId} = hd(Events38),
ct:pal("OK~n"),
%% ── TEST 39: Substring search (q) ──
ct:pal(" TEST 39: Substring search (q=Alpha)... "),
{ok, {{_, 200, _}, _, Body39}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&q=Alpha",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events39 = jsx:decode(list_to_binary(Body39), [return_maps]),
ct:pal("DEBUG: Events39 count = ~p", [length(Events39)]),
ct:pal("DEBUG: Events39 = ~p", [Events39]),
true = (length(Events39) >= 2),
Titles39 = [maps:get(<<"title">>, E) || E <- Events39],
ct:pal("OK (count: ~p, titles: ~p)~n", [length(Events39), Titles39]),
%% ── TEST 40: Combined filters (calendar_id + status) ──
ct:pal(" TEST 40: Combined filters (calendar+status)... "),
{ok, {{_, 200, _}, _, Body40}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=active",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events40 = jsx:decode(list_to_binary(Body40), [return_maps]),
ct:pal("DEBUG: Events40 count = ~p", [length(Events40)]),
ct:pal("DEBUG: Events40 = ~p", [Events40]),
true = (length(Events40) >= 2),
ct:pal("OK (count: ~p)~n", [length(Events40)]),
%% ── TEST 41: Pagination (limit & offset) ──
ct:pal(" TEST 41: Pagination... "),
{ok, {{_, 200, _}, Headers41a, Body41a}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=all&limit=2&offset=0&sort=title&order=asc",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events41a = jsx:decode(list_to_binary(Body41a), [return_maps]),
ct:pal("DEBUG: Events41a count = ~p", [length(Events41a)]),
ct:pal("DEBUG: Events41a = ~p", [Events41a]),
2 = length(Events41a),
{"content-range", ContentRange41a} = lists:keyfind("content-range", 1, Headers41a),
ct:pal("page1: ~s; ", [ContentRange41a]),
{ok, {{_, 200, _}, Headers41b, Body41b}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=all&limit=2&offset=2&sort=title&order=asc",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events41b = jsx:decode(list_to_binary(Body41b), [return_maps]),
ct:pal("DEBUG: Events41b count = ~p", [length(Events41b)]),
ct:pal("DEBUG: Events41b = ~p", [Events41b]),
1 = length(Events41b),
{"content-range", ContentRange41b} = lists:keyfind("content-range", 1, Headers41b),
ct:pal("page2: ~s~n", [ContentRange41b]),
%% ── TEST 42: Sorting (order=asc) ──
ct:pal(" TEST 42: Sorting by title ascending... "),
{ok, {{_, 200, _}, _, Body42}} =
httpc:request(get, {AdminURL ++ "/v1/admin/events?calendar_id=" ++ SearchCalIdStr ++ "&status=all&sort=title&order=asc",
[{"Authorization", "Bearer " ++ binary_to_list(AdminToken)}]},
[], []),
Events42 = jsx:decode(list_to_binary(Body42), [return_maps]),
SortedTitles = [maps:get(<<"title">>, E) || E <- Events42],
SortedTitles = lists:sort(SortedTitles),
ct:pal("OK (titles: ~p)~n", [SortedTitles]),
ct:pal("~n✅ Admin API tests passed!~n"),
{?MODULE, ok}.