-module(admin_handler_tickets_tests). -include_lib("eunit/include/eunit.hrl"). -include("records.hrl"). setup() -> ok = meck:new(cowboy_req, [non_strict]), ok = meck:new(handler_auth, [non_strict]), ok = meck:new(core_user, [non_strict]), ok = meck:new(core_ticket, [non_strict]), ok = meck:expect(cowboy_req, reply, fun(Code, Headers, Body, Req) -> put(test_reply, {Code, Headers, Body, Req}) end), ok. cleanup(_) -> meck:unload(core_ticket), meck:unload(core_user), meck:unload(handler_auth), meck:unload(cowboy_req). admin_tickets_test_() -> {setup, fun setup/0, fun cleanup/1, [ {"GET /admin/tickets – success", fun test_list/0}, {"GET /admin/tickets – forbidden", fun test_list_forbidden/0}, {"POST /admin/tickets – success", fun test_create/0}, {"POST /admin/tickets – missing error_message", fun test_create_missing/0}, {"GET /admin/tickets/:id – success", fun test_get/0}, {"GET /admin/tickets/:id – not found", fun test_get_not_found/0}, {"PUT /admin/tickets/:id – success", fun test_update/0}, {"PUT /admin/tickets/:id – not found", fun test_update_not_found/0}, {"DELETE /admin/tickets/:id – success", fun test_delete/0}, {"DELETE /admin/tickets/:id – not found", fun test_delete_not_found/0}, {"PATCH /admin/tickets – method not allowed", fun test_wrong_method/0} ]}. %% GET – список тикетов (успех) test_list() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> undefined end), % для маршрута без id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), Ticket = #ticket{ id = <<"t1">>, error_hash = <<"hash1">>, error_message = <<"Error message">>, stacktrace = <<"stack">>, context = <<"ctx">>, count = 1, first_seen = {{2026,4,28},{12,0,0}}, last_seen = {{2026,4,28},{12,0,0}}, status = open, assigned_to = undefined, resolution_note = undefined }, ok = meck:expect(core_ticket, list_all, fun() -> [Ticket] end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(200, Status), [#{<<"id">> := <<"t1">>, <<"error_message">> := <<"Error message">>}] = jsx:decode(RespBody, [return_maps]). %% GET – запрещён test_list_forbidden() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> undefined end), % для маршрута без id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {error, 403, <<"Admin access required">>, Req} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, _, _} = erase(test_reply), ?assertEqual(403, Status). %% POST – создание тикета test_create() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"POST">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> undefined end), % для маршрута без id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), BodyMap = #{<<"error_message">> => <<"Bug">>, <<"stacktrace">> => <<"trace">>}, ok = meck:expect(cowboy_req, read_body, fun(Req) -> {ok, jsx:encode(BodyMap), Req} end), Created = #ticket{id = <<"t_new">>, error_message = <<"Bug">>, status = open}, ok = meck:expect(core_ticket, create_ticket, fun(_) -> {ok, Created} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(201, Status), #{<<"error_message">> := <<"Bug">>} = jsx:decode(RespBody, [return_maps]). %% POST – отсутствует поле error_message test_create_missing() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"POST">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> undefined end), % для маршрута без id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(cowboy_req, read_body, fun(Req) -> {ok, jsx:encode(#{<<"title">> => <<"No msg">>}), Req} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, _, _} = erase(test_reply), ?assertEqual(400, Status). %% GET – один тикет по ID test_get() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t1">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), Ticket = #ticket{id = <<"t1">>, error_message = <<"Test">>, status = open}, ok = meck:expect(core_ticket, get_by_id, fun(<<"t1">>) -> {ok, Ticket} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(200, Status), #{<<"id">> := <<"t1">>} = jsx:decode(RespBody, [return_maps]). %% GET – тикет не найден test_get_not_found() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"GET">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t99">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(core_ticket, get_by_id, fun(_) -> {error, not_found} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, _, _} = erase(test_reply), ?assertEqual(404, Status). %% PUT – обновление тикета test_update() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"PUT">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t1">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(cowboy_req, read_body, fun(Req) -> {ok, jsx:encode(#{<<"status">> => <<"closed">>}), Req} end), Updated = #ticket{id = <<"t1">>, status = closed}, ok = meck:expect(core_ticket, update_ticket, fun(<<"t1">>, _) -> {ok, Updated} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(200, Status), #{<<"status">> := <<"closed">>} = jsx:decode(RespBody, [return_maps]). %% PUT – тикет не найден test_update_not_found() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"PUT">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t99">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(cowboy_req, read_body, fun(Req) -> {ok, jsx:encode(#{<<"status">> => <<"closed">>}), Req} end), ok = meck:expect(core_ticket, update_ticket, fun(_, _) -> {error, not_found} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, _, _} = erase(test_reply), ?assertEqual(404, Status). %% DELETE – удаление тикета test_delete() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"DELETE">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t1">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(core_ticket, delete_ticket, fun(<<"t1">>) -> {ok, deleted} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(200, Status), #{<<"status">> := <<"deleted">>} = jsx:decode(RespBody, [return_maps]). %% DELETE – тикет не найден test_delete_not_found() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"DELETE">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> <<"t99">> end), % для маршрута с id ok = meck:expect(handler_auth, authenticate, fun(Req) -> {ok, <<"adm1">>, Req} end), AdminUser = #user{id = <<"adm1">>, role = admin}, ok = meck:expect(core_user, get_by_id, fun(<<"adm1">>) -> {ok, AdminUser} end), ok = meck:expect(core_ticket, delete_ticket, fun(_) -> {error, not_found} end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, _, _} = erase(test_reply), ?assertEqual(404, Status). %% Неправильный метод test_wrong_method() -> ok = meck:expect(cowboy_req, method, fun(_) -> <<"PATCH">> end), ok = meck:expect(cowboy_req, binding, fun(id, _) -> undefined end), % для маршрута без id ok = meck:expect(cowboy_req, reply, fun(Code, Headers, Body, Req) -> put(test_reply, {Code, Headers, Body, Req}) end), {ok, _, _} = admin_handler_tickets:init(req, []), {Status, _, RespBody, _} = erase(test_reply), ?assertEqual(405, Status), #{<<"error">> := <<"Method not allowed">>} = jsx:decode(RespBody, [return_maps]).