-module(core_ticket_tests). -include_lib("eunit/include/eunit.hrl"). -include("records.hrl"). %% ---------------------------------------------------------------- %% Фикстуры %% ---------------------------------------------------------------- setup() -> catch mnesia:stop(), case mnesia:start() of {atomic, ok} -> ok; ok -> ok end, {atomic, ok} = mnesia:create_table(ticket, [ {attributes, record_info(fields, ticket)}, {ram_copies, [node()]} ]), ok. cleanup(_) -> mnesia:delete_table(ticket), mnesia:stop(). %% ---------------------------------------------------------------- %% Тесты %% ---------------------------------------------------------------- core_ticket_test_() -> {foreach, fun setup/0, fun cleanup/1, [ {"Create ticket and retrieve it", fun test_create_and_get/0}, {"Update ticket status", fun test_update_status/0}, {"Delete ticket and verify removal", fun test_delete_ticket/0}, {"List all tickets returns created ones", fun test_list_all/0}, {"List tickets by user filters correctly", fun test_list_by_user/0}, {"Get ticket stats reflects real counts", fun test_stats/0}, {"Update ticket with unknown id fails", fun test_update_not_found/0}, {"Delete ticket with unknown id fails", fun test_delete_not_found/0}, {"Get ticket with unknown id fails", fun test_get_not_found/0} ]}. %% ── Вспомогательная функция для создания тикета ───────── make_ticket(ErrorMsg) -> Data = #{ <<"error_message">> => list_to_binary(ErrorMsg), <<"stacktrace">> => <<"trace">>, <<"reporter_id">> => <<"user123">>, <<"status">> => <<"open">> }, {ok, Ticket} = core_ticket:create_ticket(Data), Ticket. %% ── Тесты ───────────────────────────────────────────────── test_create_and_get() -> Ticket = make_ticket("Bug1"), ?assert(is_binary(Ticket#ticket.id)), {ok, Retrieved} = core_ticket:get_by_id(Ticket#ticket.id), ?assertEqual(Ticket#ticket.id, Retrieved#ticket.id). test_update_status() -> Ticket = make_ticket("Bug2"), {ok, Updated} = core_ticket:update_ticket(Ticket#ticket.id, #{<<"status">> => <<"closed">>}), ?assertEqual(closed, Updated#ticket.status), {ok, Stored} = core_ticket:get_by_id(Ticket#ticket.id), ?assertEqual(closed, Stored#ticket.status). test_delete_ticket() -> Ticket = make_ticket("Bug3"), Id = Ticket#ticket.id, {ok, deleted} = core_ticket:delete_ticket(Id), % Проверяем, что тикет больше не читается ?assertMatch({error, not_found}, core_ticket:get_by_id(Id)). test_list_all() -> T1 = make_ticket("E1"), T2 = make_ticket("E2"), All = core_ticket:list_all(), ?assert(length(All) >= 2), Ids = [T#ticket.id || T <- All], ?assert(lists:member(T1#ticket.id, Ids)), ?assert(lists:member(T2#ticket.id, Ids)). test_list_by_user() -> % Создаём тикет от пользователя test_user Data = #{ <<"error_message">> => <<"from_test_user">>, <<"stacktrace">> => <<"trace">>, <<"reporter_id">> => <<"test_user">>, <<"status">> => <<"open">> }, {ok, T1} = core_ticket:create_ticket(Data), % Ещё один тикет от другого пользователя DataOther = #{ <<"error_message">> => <<"other">>, <<"stacktrace">> => <<"trace">>, <<"reporter_id">> => <<"other_user">>, <<"status">> => <<"open">> }, {ok, _T2} = core_ticket:create_ticket(DataOther), % list_by_user("test_user") должен вернуть ровно один тикет (T1) UserTickets = core_ticket:list_by_user(<<"test_user">>), ?assertEqual(1, length(UserTickets)), ?assertEqual(T1#ticket.id, (hd(UserTickets))#ticket.id). test_stats() -> Data1 = #{ <<"error_message">> => <<"stat1">>, <<"stacktrace">> => <<"trace">>, <<"reporter_id">> => <<"reporter123">>, <<"status">> => <<"open">> }, Data2 = #{ <<"error_message">> => <<"stat2">>, <<"stacktrace">> => <<"trace">>, <<"reporter_id">> => <<"reporter456">>, <<"status">> => <<"open">> }, {ok, _} = core_ticket:create_ticket(Data1), {ok, _} = core_ticket:create_ticket(Data2), Stats = core_ticket:stats(), ?assert(is_map(Stats)), ?assert(maps:is_key(open, Stats)), ?assert(maps:is_key(total, Stats)), % Проверяем, что общее количество тикетов не меньше 2 Total = maps:get(total, Stats), ?assert(Total >= 2). test_update_not_found() -> {error, not_found} = core_ticket:update_ticket(<<"nonexistent">>, #{<<"status">> => <<"closed">>}). test_delete_not_found() -> {error, not_found} = core_ticket:delete_ticket(<<"nonexistent">>). test_get_not_found() -> {error, not_found} = core_ticket:get_by_id(<<"nonexistent">>).