From e94c94d1a6c0deab4ac9678573fe3c74ae0b477d Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Mon, 20 Jul 2026 11:27:27 +0300 Subject: [PATCH] test: unique ticket messages per run to avoid IFT dedupe collisions --- test/api/admins/admin_tickets_tests.erl | 6 +++-- test/api/api_test_runner.erl | 8 ++++++ test/api/users/user_tickets_tests.erl | 33 ++++++++++++++----------- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/test/api/admins/admin_tickets_tests.erl b/test/api/admins/admin_tickets_tests.erl index 670a3c5..0022818 100644 --- a/test/api/admins/admin_tickets_tests.erl +++ b/test/api/admins/admin_tickets_tests.erl @@ -34,10 +34,12 @@ test() -> UserToken = api_test_runner:get_user_token(), % Создаём два тикета для разных проверок Ticket1 = api_test_runner:client_post(<<"/v1/tickets">>, UserToken, - #{<<"error_message">> => <<"Test bug">>, <<"stacktrace">> => <<"trace">>}), + #{<<"error_message">> => api_test_runner:unique_ticket_message(<<"Test bug">>), + <<"stacktrace">> => <<"trace">>}), #{<<"id">> := Ticket1Id} = Ticket1, Ticket2 = api_test_runner:client_post(<<"/v1/tickets">>, UserToken, - #{<<"error_message">> => <<"Another bug">>, <<"stacktrace">> => <<"trace2">>}), + #{<<"error_message">> => api_test_runner:unique_ticket_message(<<"Another bug">>), + <<"stacktrace">> => <<"trace2">>}), #{<<"id">> := Ticket2Id} = Ticket2, % Получаем ID текущего администратора для теста фильтрации по исполнителю diff --git a/test/api/api_test_runner.erl b/test/api/api_test_runner.erl index 02bf116..db10d22 100644 --- a/test/api/api_test_runner.erl +++ b/test/api/api_test_runner.erl @@ -21,6 +21,7 @@ get_support_token/0, get_user_token/0, unique_email/1, + unique_ticket_message/1, future_date/0, register_and_login/2, create_calendar/2, @@ -335,6 +336,13 @@ unique_email(Prefix) -> Unique = integer_to_binary(erlang:system_time()), <>. +%% Уникальное сообщение тикета на прогон (IFT: иначе дедуп по error_hash +%% возвращает чужой reporter_id и list/get своих тикетов падает). +-spec unique_ticket_message(binary()) -> binary(). +unique_ticket_message(Prefix) -> + Unique = integer_to_binary(erlang:unique_integer([positive, monotonic])), + <>. + -spec future_date() -> calendar:datetime(). future_date() -> Seconds = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) + 86400, diff --git a/test/api/users/user_tickets_tests.erl b/test/api/users/user_tickets_tests.erl index d5900d4..e5f7c2f 100644 --- a/test/api/users/user_tickets_tests.erl +++ b/test/api/users/user_tickets_tests.erl @@ -31,18 +31,21 @@ test() -> StrangerEmail = api_test_runner:unique_email(<<"stranger">>), StrangerToken = api_test_runner:register_and_login(StrangerEmail, <<"pass">>), + PrimaryMsg = api_test_runner:unique_ticket_message(<<"Something broke">>), + DedupeMsg = api_test_runner:unique_ticket_message(<<"Dedupe me">>), + % Создаём тикет #{<<"id">> := TicketId} = api_test_runner:client_post(<<"/v1/tickets">>, Token, - #{error_message => <<"Something broke">>, stacktrace => <<"line 42">>}), + #{error_message => PrimaryMsg, stacktrace => <<"line 42">>}), - test_create_ticket(Token), - test_create_ticket_dedupe(Token), + test_create_ticket(Token, api_test_runner:unique_ticket_message(<<"Test bug">>)), + test_create_ticket_dedupe(Token, DedupeMsg), test_create_ticket_manual(Token), test_create_ticket_missing_fields(Token), test_create_ticket_unauthorized(), test_list_tickets(Token, TicketId), test_list_tickets_unauthorized(), - test_get_ticket(Token, TicketId), + test_get_ticket(Token, TicketId, PrimaryMsg), test_get_ticket_forbidden(StrangerToken, TicketId), test_get_ticket_not_found(Token), test_get_ticket_unauthorized(TicketId), @@ -54,12 +57,12 @@ test() -> %%%=================================================================== %% @doc Успешное создание тикета: 201 Created. --spec test_create_ticket(binary()) -> ok. -test_create_ticket(Token) -> +-spec test_create_ticket(binary(), binary()) -> ok. +test_create_ticket(Token, ErrorMessage) -> ct:pal(" TEST: Create a ticket"), Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token, jsx:encode(#{ - error_message => <<"Test bug">>, + error_message => ErrorMessage, stacktrace => <<"trace">>, source => <<"frontend">>, context => #{route => <<"/test">>, build => <<"dev">>} @@ -75,11 +78,11 @@ test_create_ticket(Token) -> ct:pal(" OK: ticket ~s created", [Id]). %% @doc Повторный POST с тем же сообщением увеличивает count. --spec test_create_ticket_dedupe(binary()) -> ok. -test_create_ticket_dedupe(Token) -> +-spec test_create_ticket_dedupe(binary(), binary()) -> ok. +test_create_ticket_dedupe(Token, ErrorMessage) -> ct:pal(" TEST: Dedupe ticket by hash"), Payload = jsx:encode(#{ - error_message => <<"Dedupe me">>, + error_message => ErrorMessage, stacktrace => <<"same stack">>, source => <<"frontend">> }), @@ -97,7 +100,7 @@ test_create_ticket_manual(Token) -> ct:pal(" TEST: Create manual ticket"), Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token, jsx:encode(#{ - error_message => <<"Button does nothing">>, + error_message => api_test_runner:unique_ticket_message(<<"Button does nothing">>), source => <<"manual">>, context => #{steps => <<"1. Open calendar\n2. Click share">>} })), @@ -146,13 +149,13 @@ test_list_tickets_unauthorized() -> ct:pal(" OK: got 401"). %% @doc GET /v1/tickets/:id – получение своего тикета. --spec test_get_ticket(binary(), binary()) -> ok. -test_get_ticket(Token, TicketId) -> +-spec test_get_ticket(binary(), binary(), binary()) -> ok. +test_get_ticket(Token, TicketId, ExpectedMessage) -> ct:pal(" TEST: Get my ticket by ID"), Path = <<"/v1/tickets/", TicketId/binary>>, Ticket = api_test_runner:client_get(Path, Token), ?assertEqual(TicketId, maps:get(<<"id">>, Ticket)), - ?assertEqual(<<"Something broke">>, maps:get(<<"error_message">>, Ticket)), + ?assertEqual(ExpectedMessage, maps:get(<<"error_message">>, Ticket)), ct:pal(" OK: got my ticket"). %% @doc GET /v1/tickets/:id – попытка доступа к чужому тикету (403). @@ -179,4 +182,4 @@ test_get_ticket_unauthorized(TicketId) -> Path = <<"/v1/tickets/", TicketId/binary>>, Resp = api_test_runner:client_request(get, Path, <<>>), ?assertMatch({ok, 401, _, _}, Resp), - ct:pal(" OK: got 401"). \ No newline at end of file + ct:pal(" OK: got 401").