Files
EventHubBack/test/unit/logic_search_tests.erl
T
aleksey 6d52bc3a8e
CI / test (push) Successful in 22m57s
CI / deploy-ift (push) Successful in 3m22s
CI / e2e-ift (push) Successful in 1m12s
CI / deploy-stage (push) Successful in 4m21s
CI / e2e-stage (push) Successful in 1m27s
feat: discovery tops for empty GET /v1/search. Refs EventHub/EventHubBack#50
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 12:17:36 +03:00

275 lines
11 KiB
Erlang

-module(logic_search_tests).
-include_lib("eunit/include/eunit.hrl").
-include("records.hrl").
-define(TABLES, [user, calendar, event]).
setup() ->
eh_test_support:start_mnesia(),
eh_test_support:ensure_tables(?TABLES),
ok.
cleanup(_) ->
eh_test_support:delete_tables(?TABLES),
eh_test_support:stop_mnesia(),
ok.
logic_search_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"Search events by text", fun test_search_events_by_text/0},
{"Search events by tags", fun test_search_events_by_tags/0},
{"Search events by date range", fun test_search_events_by_date/0},
{"Search events by location", fun test_search_events_by_location/0},
{"Combined search", fun test_combined_search/0},
{"Search calendars", fun test_search_calendars/0},
{"Search all", fun test_search_all/0},
{"Pagination", fun test_pagination/0},
{"Sorting", fun test_sorting/0},
{"Access control in search", fun test_access_control/0},
{"Empty search results", fun test_empty_search/0},
{"Discovery tops without filters", fun test_discovery_returns_tops/0},
{"Query switches to filtered search", fun test_discovery_with_q_uses_filter/0}
]}.
%% Вспомогательные функции
create_test_user(Role) ->
UserId = base64:encode(crypto:strong_rand_bytes(16), #{mode => urlsafe, padding => false}),
User = #user{
id = UserId,
email = <<UserId/binary, "@test.com">>,
password_hash = <<"hash">>,
role = Role,
status = active,
created_at = calendar:universal_time(),
updated_at = calendar:universal_time()
},
mnesia:dirty_write(User),
UserId.
create_test_calendar(OwnerId, Type, Tags) ->
{ok, Calendar} = core_calendar:create(OwnerId, <<"Test Calendar">>, <<"Description">>, manual),
core_calendar:update(Calendar#calendar.id, [{type, Type}, {tags, Tags}]),
{ok, Updated} = core_calendar:get_by_id(Calendar#calendar.id),
Updated#calendar.id.
create_test_event(CalendarId, Title, Description, StartTime, Tags, Location) ->
{ok, Event} = core_event:create(CalendarId, Title, StartTime, 60),
Updates = [{description, Description}, {tags, Tags}],
Updates2 = case Location of
undefined -> Updates;
_ -> [{location, Location} | Updates]
end,
core_event:update(Event#event.id, Updates2),
{ok, Updated} = core_event:get_by_id(Event#event.id),
Updated#event.id.
add_days(DateTime, Days) ->
Sec = calendar:datetime_to_gregorian_seconds(DateTime) + Days * 86400,
calendar:gregorian_seconds_to_datetime(Sec).
events_from({ok, Total, #{<<"events">> := Events}}) ->
{Total, Events}.
calendars_from({ok, Total, #{<<"calendars">> := Calendars}}) ->
{Total, Calendars}.
%% Тесты
test_search_events_by_text() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Python Workshop">>, <<"Learn Python">>, StartTime, [], undefined),
create_test_event(CalendarId, <<"JavaScript Conference">>, <<"JS for everyone">>, StartTime, [], undefined),
create_test_event(CalendarId, <<"Yoga Class">>, <<"Morning yoga">>, StartTime, [], undefined),
Params = #{},
{Total, Results} = events_from(logic_search:search(<<"event">>, <<"Python">>, OwnerId, Params)),
?assertEqual(1, Total),
?assertEqual(1, length(Results)),
{Total2, _} = events_from(logic_search:search(<<"event">>, <<"conference">>, OwnerId, Params)),
?assertEqual(1, Total2).
test_search_events_by_tags() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Event 1">>, <<"">>, StartTime, [<<"python">>, <<"workshop">>], undefined),
create_test_event(CalendarId, <<"Event 2">>, <<"">>, StartTime, [<<"javascript">>, <<"conference">>], undefined),
create_test_event(CalendarId, <<"Event 3">>, <<"">>, StartTime, [<<"python">>, <<"advanced">>], undefined),
{Total, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{tags => <<"python">>})),
?assertEqual(2, Total),
{Total2, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{tags => <<"workshop">>})),
?assertEqual(1, Total2),
{Total3, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{tags => <<"nonexistent">>})),
?assertEqual(0, Total3).
test_search_events_by_date() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
Base = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Near Event">>, <<"">>, Base, [], undefined),
create_test_event(CalendarId, <<"Mid Event">>, <<"">>, add_days(Base, 30), [], undefined),
create_test_event(CalendarId, <<"Far Event">>, <<"">>, add_days(Base, 60), [], undefined),
Params = #{from => add_days(Base, -1), to => add_days(Base, 7)},
{Total, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, Params)),
?assertEqual(1, Total).
test_search_events_by_location() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
MoscowLoc = #location{address = <<"Moscow">>, lat = 55.7558, lon = 37.6173},
SpbLoc = #location{address = <<"SPb">>, lat = 59.9343, lon = 30.3351},
create_test_event(CalendarId, <<"Moscow Event">>, <<"">>, StartTime, [], MoscowLoc),
create_test_event(CalendarId, <<"SPb Event">>, <<"">>, StartTime, [], SpbLoc),
{Total, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId,
#{lat => 55.7558, lon => 37.6173, radius => 10})),
?assertEqual(1, Total),
{Total2, _} = events_from(logic_search:search(<<"event">>, undefined, OwnerId,
#{lat => 59.9343, lon => 30.3351, radius => 10})),
?assertEqual(1, Total2).
test_combined_search() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
Base = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Python Workshop">>, <<"Learn Python">>, Base,
[<<"python">>, <<"workshop">>], undefined),
create_test_event(CalendarId, <<"Python Advanced">>, <<"Advanced Python">>, add_days(Base, 30),
[<<"python">>, <<"advanced">>], undefined),
Params = #{from => add_days(Base, -1), to => add_days(Base, 7), tags => <<"python">>},
{Total, _} = events_from(logic_search:search(<<"event">>, <<"Workshop">>, OwnerId, Params)),
?assertEqual(1, Total).
test_search_calendars() ->
OwnerId = create_test_user(user),
create_test_calendar(OwnerId, personal, [<<"tech">>, <<"programming">>]),
create_test_calendar(OwnerId, commercial, [<<"yoga">>, <<"wellness">>]),
{Total, _} = calendars_from(logic_search:search(<<"calendar">>, undefined, OwnerId, #{tags => <<"tech">>})),
?assertEqual(1, Total),
{Total2, _} = calendars_from(logic_search:search(<<"calendar">>, <<"Calendar">>, OwnerId, #{})),
?assertEqual(2, Total2).
test_search_all() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Test Event">>, <<"">>, StartTime, [], undefined),
{ok, Total, Results} = logic_search:search(undefined, <<"Test">>, OwnerId, #{}),
?assert(Total >= 2),
?assert(maps:is_key(<<"events">>, Results)),
?assert(maps:is_key(<<"calendars">>, Results)).
test_pagination() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
lists:foreach(fun(I) ->
Title = iolist_to_binary(["Event ", integer_to_binary(I)]),
create_test_event(CalendarId, Title, <<"">>, StartTime, [], undefined)
end, [1, 2, 3, 4, 5]),
{Total, Results} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{limit => 2, offset => 0})),
?assertEqual(5, Total),
?assertEqual(2, length(Results)),
{_, Results2} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{limit => 2, offset => 2})),
?assertEqual(2, length(Results2)),
{_, Results3} = events_from(logic_search:search(<<"event">>, undefined, OwnerId, #{limit => 2, offset => 4})),
?assertEqual(1, length(Results3)).
test_sorting() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
Base = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Early">>, <<"">>, Base, [], undefined),
create_test_event(CalendarId, <<"Late">>, <<"">>, add_days(Base, 29), [], undefined),
{_, [First | _]} = events_from(logic_search:search(<<"event">>, undefined, OwnerId,
#{sort => <<"start_time">>, order => <<"asc">>})),
?assertMatch(#{title := <<"Early">>}, First),
{_, [First2 | _]} = events_from(logic_search:search(<<"event">>, undefined, OwnerId,
#{sort => <<"start_time">>, order => <<"desc">>})),
?assertMatch(#{title := <<"Late">>}, First2).
test_access_control() ->
OwnerId = create_test_user(user),
OtherId = create_test_user(user),
PersonalId = create_test_calendar(OwnerId, personal, []),
CommercialId = create_test_calendar(OwnerId, commercial, []),
StartTime = eh_test_support:future_start(),
create_test_event(PersonalId, <<"Personal Event">>, <<"">>, StartTime, [], undefined),
create_test_event(CommercialId, <<"Public Event">>, <<"">>, StartTime, [], undefined),
{Total, Results} = events_from(logic_search:search(<<"event">>, undefined, OtherId, #{})),
?assertEqual(1, Total),
[Event] = Results,
?assertMatch(#{title := <<"Public Event">>}, Event).
test_empty_search() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
create_test_event(CalendarId, <<"Test">>, <<"">>, StartTime, [], undefined),
{Total, Results} = events_from(logic_search:search(<<"event">>, <<"nonexistent">>, OwnerId, #{})),
?assertEqual(0, Total),
?assertEqual([], Results).
test_discovery_returns_tops() ->
OwnerId = create_test_user(user),
ViewerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, commercial, []),
StartTime = eh_test_support:future_start(),
LowId = create_test_event(CalendarId, <<"Low Rated">>, <<"">>, StartTime, [], undefined),
HighId = create_test_event(CalendarId, <<"High Rated">>, <<"">>, StartTime, [], undefined),
{ok, _} = core_event:update(LowId, [{rating_avg, 1.0}, {rating_count, 1}]),
{ok, _} = core_event:update(HighId, [{rating_avg, 5.0}, {rating_count, 10}]),
stats_tops:init_tables(),
stats_tops:rebuild(),
{Total, [First | _]} = events_from(logic_search:search(<<"event">>, undefined, ViewerId, #{})),
?assertEqual(2, Total),
?assertMatch(#{title := <<"High Rated">>}, First).
test_discovery_with_q_uses_filter() ->
OwnerId = create_test_user(user),
CalendarId = create_test_calendar(OwnerId, personal, []),
StartTime = eh_test_support:future_start(),
LowId = create_test_event(CalendarId, <<"Alpha">>, <<"">>, StartTime, [], undefined),
HighId = create_test_event(CalendarId, <<"Beta">>, <<"">>, StartTime, [], undefined),
{ok, _} = core_event:update(LowId, [{rating_avg, 1.0}]),
{ok, _} = core_event:update(HighId, [{rating_avg, 5.0}]),
stats_tops:init_tables(),
stats_tops:rebuild(),
{Total, Results} = events_from(logic_search:search(<<"event">>, <<"Alpha">>, OwnerId, #{})),
?assertEqual(1, Total),
?assertMatch([#{title := <<"Alpha">>}], Results).