249 lines
10 KiB
Erlang
249 lines
10 KiB
Erlang
-module(logic_search_tests).
|
||
-include_lib("eunit/include/eunit.hrl").
|
||
-include("records.hrl").
|
||
|
||
setup() ->
|
||
mnesia:start(),
|
||
mnesia:create_table(user, [
|
||
{attributes, record_info(fields, user)},
|
||
{ram_copies, [node()]}
|
||
]),
|
||
mnesia:create_table(calendar, [
|
||
{attributes, record_info(fields, calendar)},
|
||
{ram_copies, [node()]}
|
||
]),
|
||
mnesia:create_table(event, [
|
||
{attributes, record_info(fields, event)},
|
||
{ram_copies, [node()]}
|
||
]),
|
||
ok.
|
||
|
||
cleanup(_) ->
|
||
mnesia:delete_table(event),
|
||
mnesia:delete_table(calendar),
|
||
mnesia:delete_table(user),
|
||
mnesia:stop(),
|
||
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}
|
||
]}.
|
||
|
||
%% Вспомогательные функции
|
||
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.
|
||
|
||
%% Тесты
|
||
test_search_events_by_text() ->
|
||
OwnerId = create_test_user(user),
|
||
CalendarId = create_test_calendar(OwnerId, personal, []),
|
||
|
||
StartTime = {{2026, 6, 1}, {10, 0, 0}},
|
||
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 = #{},
|
||
{ok, Total, Results} = logic_search:search(<<"event">>, <<"Python">>, OwnerId, Params),
|
||
?assertEqual(1, Total),
|
||
?assertEqual(1, length(Results)),
|
||
|
||
{ok, Total2, _Results2} = 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 = {{2026, 6, 1}, {10, 0, 0}},
|
||
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),
|
||
|
||
% Поиск по одному тегу
|
||
Params = #{tags => <<"python">>},
|
||
{ok, Total, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
|
||
?assertEqual(2, Total), % Event 1 и Event 3
|
||
|
||
% Поиск по тегу, который есть только у одного события
|
||
Params2 = #{tags => <<"workshop">>},
|
||
{ok, Total2, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
|
||
?assertEqual(1, Total2), % Только Event 1
|
||
|
||
% Поиск по тегу, которого нет
|
||
Params3 = #{tags => <<"nonexistent">>},
|
||
{ok, Total3, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params3),
|
||
?assertEqual(0, Total3).
|
||
|
||
test_search_events_by_date() ->
|
||
OwnerId = create_test_user(user),
|
||
CalendarId = create_test_calendar(OwnerId, personal, []),
|
||
|
||
create_test_event(CalendarId, <<"June Event">>, <<"">>, {{2026, 6, 15}, {10, 0, 0}}, [], undefined),
|
||
create_test_event(CalendarId, <<"July Event">>, <<"">>, {{2026, 7, 15}, {10, 0, 0}}, [], undefined),
|
||
create_test_event(CalendarId, <<"August Event">>, <<"">>, {{2026, 8, 15}, {10, 0, 0}}, [], undefined),
|
||
|
||
Params = #{from => {{2026, 6, 1}, {0, 0, 0}}, to => {{2026, 6, 30}, {23, 59, 59}}},
|
||
{ok, Total, _} = 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 = {{2026, 6, 1}, {10, 0, 0}},
|
||
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),
|
||
|
||
Params = #{lat => 55.7558, lon => 37.6173, radius => 10},
|
||
{ok, Total, _Results} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
|
||
?assertEqual(1, Total),
|
||
|
||
Params2 = #{lat => 59.9343, lon => 30.3351, radius => 10},
|
||
{ok, Total2, _} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
|
||
?assertEqual(1, Total2).
|
||
|
||
test_combined_search() ->
|
||
OwnerId = create_test_user(user),
|
||
CalendarId = create_test_calendar(OwnerId, personal, []),
|
||
|
||
StartTime = {{2026, 6, 15}, {10, 0, 0}},
|
||
create_test_event(CalendarId, <<"Python Workshop">>, <<"Learn Python">>, StartTime, [<<"python">>, <<"workshop">>], undefined),
|
||
create_test_event(CalendarId, <<"Python Advanced">>, <<"Advanced Python">>, {{2026, 7, 15}, {10, 0, 0}}, [<<"python">>, <<"advanced">>], undefined),
|
||
|
||
Params = #{from => {{2026, 6, 1}, {0, 0, 0}}, to => {{2026, 6, 30}, {23, 59, 59}}, tags => <<"python">>},
|
||
{ok, Total, _} = 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">>]),
|
||
|
||
Params = #{tags => <<"tech">>},
|
||
{ok, Total, _} = logic_search:search(<<"calendar">>, undefined, OwnerId, Params),
|
||
?assertEqual(1, Total),
|
||
|
||
{ok, Total2, _} = logic_search:search(<<"calendar">>, <<"Calendar">>, OwnerId, #{}),
|
||
?assertEqual(2, Total2).
|
||
|
||
test_search_all() ->
|
||
OwnerId = create_test_user(user),
|
||
CalendarId = create_test_calendar(OwnerId, personal, []),
|
||
StartTime = {{2026, 6, 1}, {10, 0, 0}},
|
||
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 = {{2026, 6, 1}, {10, 0, 0}},
|
||
|
||
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]),
|
||
|
||
Params = #{limit => 2, offset => 0},
|
||
{ok, Total, Results} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
|
||
?assertEqual(5, Total),
|
||
?assertEqual(2, length(Results)),
|
||
|
||
Params2 = #{limit => 2, offset => 2},
|
||
{ok, _, Results2} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
|
||
?assertEqual(2, length(Results2)),
|
||
|
||
Params3 = #{limit => 2, offset => 4},
|
||
{ok, _, Results3} = logic_search:search(<<"event">>, undefined, OwnerId, Params3),
|
||
?assertEqual(1, length(Results3)).
|
||
|
||
test_sorting() ->
|
||
OwnerId = create_test_user(user),
|
||
CalendarId = create_test_calendar(OwnerId, personal, []),
|
||
|
||
create_test_event(CalendarId, <<"Early">>, <<"">>, {{2026, 6, 1}, {10, 0, 0}}, [], undefined),
|
||
create_test_event(CalendarId, <<"Late">>, <<"">>, {{2026, 6, 30}, {10, 0, 0}}, [], undefined),
|
||
|
||
Params = #{sort => <<"start_time">>, order => <<"asc">>},
|
||
{ok, _, [First | _]} = logic_search:search(<<"event">>, undefined, OwnerId, Params),
|
||
?assertMatch(#{title := <<"Early">>}, First),
|
||
|
||
Params2 = #{sort => <<"start_time">>, order => <<"desc">>},
|
||
{ok, _, [First2 | _]} = logic_search:search(<<"event">>, undefined, OwnerId, Params2),
|
||
?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 = {{2026, 6, 1}, {10, 0, 0}},
|
||
create_test_event(PersonalId, <<"Personal Event">>, <<"">>, StartTime, [], undefined),
|
||
create_test_event(CommercialId, <<"Public Event">>, <<"">>, StartTime, [], undefined),
|
||
|
||
% Другой пользователь видит только коммерческие события
|
||
{ok, Total, Results} = 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 = {{2026, 6, 1}, {10, 0, 0}},
|
||
create_test_event(CalendarId, <<"Test">>, <<"">>, StartTime, [], undefined),
|
||
|
||
{ok, Total, Results} = logic_search:search(<<"event">>, <<"nonexistent">>, OwnerId, #{}),
|
||
?assertEqual(0, Total),
|
||
?assertEqual([], Results). |