test: unique ticket messages per run to avoid IFT dedupe collisions

This commit is contained in:
2026-07-20 11:27:27 +03:00
parent 7c1fe1940d
commit e94c94d1a6
3 changed files with 30 additions and 17 deletions
+4 -2
View File
@@ -34,10 +34,12 @@ test() ->
UserToken = api_test_runner:get_user_token(), UserToken = api_test_runner:get_user_token(),
% Создаём два тикета для разных проверок % Создаём два тикета для разных проверок
Ticket1 = api_test_runner:client_post(<<"/v1/tickets">>, UserToken, 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, #{<<"id">> := Ticket1Id} = Ticket1,
Ticket2 = api_test_runner:client_post(<<"/v1/tickets">>, UserToken, 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">> := Ticket2Id} = Ticket2,
% Получаем ID текущего администратора для теста фильтрации по исполнителю % Получаем ID текущего администратора для теста фильтрации по исполнителю
+8
View File
@@ -21,6 +21,7 @@
get_support_token/0, get_support_token/0,
get_user_token/0, get_user_token/0,
unique_email/1, unique_email/1,
unique_ticket_message/1,
future_date/0, future_date/0,
register_and_login/2, register_and_login/2,
create_calendar/2, create_calendar/2,
@@ -335,6 +336,13 @@ unique_email(Prefix) ->
Unique = integer_to_binary(erlang:system_time()), Unique = integer_to_binary(erlang:system_time()),
<<Prefix/binary, "_", Unique/binary, "@test.local">>. <<Prefix/binary, "_", Unique/binary, "@test.local">>.
%% Уникальное сообщение тикета на прогон (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])),
<<Prefix/binary, " ", Unique/binary>>.
-spec future_date() -> calendar:datetime(). -spec future_date() -> calendar:datetime().
future_date() -> future_date() ->
Seconds = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) + 86400, Seconds = calendar:datetime_to_gregorian_seconds(calendar:universal_time()) + 86400,
+17 -14
View File
@@ -31,18 +31,21 @@ test() ->
StrangerEmail = api_test_runner:unique_email(<<"stranger">>), StrangerEmail = api_test_runner:unique_email(<<"stranger">>),
StrangerToken = api_test_runner:register_and_login(StrangerEmail, <<"pass">>), 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, #{<<"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(Token, api_test_runner:unique_ticket_message(<<"Test bug">>)),
test_create_ticket_dedupe(Token), test_create_ticket_dedupe(Token, DedupeMsg),
test_create_ticket_manual(Token), test_create_ticket_manual(Token),
test_create_ticket_missing_fields(Token), test_create_ticket_missing_fields(Token),
test_create_ticket_unauthorized(), test_create_ticket_unauthorized(),
test_list_tickets(Token, TicketId), test_list_tickets(Token, TicketId),
test_list_tickets_unauthorized(), test_list_tickets_unauthorized(),
test_get_ticket(Token, TicketId), test_get_ticket(Token, TicketId, PrimaryMsg),
test_get_ticket_forbidden(StrangerToken, TicketId), test_get_ticket_forbidden(StrangerToken, TicketId),
test_get_ticket_not_found(Token), test_get_ticket_not_found(Token),
test_get_ticket_unauthorized(TicketId), test_get_ticket_unauthorized(TicketId),
@@ -54,12 +57,12 @@ test() ->
%%%=================================================================== %%%===================================================================
%% @doc Успешное создание тикета: 201 Created. %% @doc Успешное создание тикета: 201 Created.
-spec test_create_ticket(binary()) -> ok. -spec test_create_ticket(binary(), binary()) -> ok.
test_create_ticket(Token) -> test_create_ticket(Token, ErrorMessage) ->
ct:pal(" TEST: Create a ticket"), ct:pal(" TEST: Create a ticket"),
Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token, Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token,
jsx:encode(#{ jsx:encode(#{
error_message => <<"Test bug">>, error_message => ErrorMessage,
stacktrace => <<"trace">>, stacktrace => <<"trace">>,
source => <<"frontend">>, source => <<"frontend">>,
context => #{route => <<"/test">>, build => <<"dev">>} context => #{route => <<"/test">>, build => <<"dev">>}
@@ -75,11 +78,11 @@ test_create_ticket(Token) ->
ct:pal(" OK: ticket ~s created", [Id]). ct:pal(" OK: ticket ~s created", [Id]).
%% @doc Повторный POST с тем же сообщением увеличивает count. %% @doc Повторный POST с тем же сообщением увеличивает count.
-spec test_create_ticket_dedupe(binary()) -> ok. -spec test_create_ticket_dedupe(binary(), binary()) -> ok.
test_create_ticket_dedupe(Token) -> test_create_ticket_dedupe(Token, ErrorMessage) ->
ct:pal(" TEST: Dedupe ticket by hash"), ct:pal(" TEST: Dedupe ticket by hash"),
Payload = jsx:encode(#{ Payload = jsx:encode(#{
error_message => <<"Dedupe me">>, error_message => ErrorMessage,
stacktrace => <<"same stack">>, stacktrace => <<"same stack">>,
source => <<"frontend">> source => <<"frontend">>
}), }),
@@ -97,7 +100,7 @@ test_create_ticket_manual(Token) ->
ct:pal(" TEST: Create manual ticket"), ct:pal(" TEST: Create manual ticket"),
Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token, Resp = api_test_runner:client_request(post, <<"/v1/tickets">>, Token,
jsx:encode(#{ jsx:encode(#{
error_message => <<"Button does nothing">>, error_message => api_test_runner:unique_ticket_message(<<"Button does nothing">>),
source => <<"manual">>, source => <<"manual">>,
context => #{steps => <<"1. Open calendar\n2. Click share">>} context => #{steps => <<"1. Open calendar\n2. Click share">>}
})), })),
@@ -146,13 +149,13 @@ test_list_tickets_unauthorized() ->
ct:pal(" OK: got 401"). ct:pal(" OK: got 401").
%% @doc GET /v1/tickets/:id получение своего тикета. %% @doc GET /v1/tickets/:id получение своего тикета.
-spec test_get_ticket(binary(), binary()) -> ok. -spec test_get_ticket(binary(), binary(), binary()) -> ok.
test_get_ticket(Token, TicketId) -> test_get_ticket(Token, TicketId, ExpectedMessage) ->
ct:pal(" TEST: Get my ticket by ID"), ct:pal(" TEST: Get my ticket by ID"),
Path = <<"/v1/tickets/", TicketId/binary>>, Path = <<"/v1/tickets/", TicketId/binary>>,
Ticket = api_test_runner:client_get(Path, Token), Ticket = api_test_runner:client_get(Path, Token),
?assertEqual(TicketId, maps:get(<<"id">>, Ticket)), ?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"). ct:pal(" OK: got my ticket").
%% @doc GET /v1/tickets/:id попытка доступа к чужому тикету (403). %% @doc GET /v1/tickets/:id попытка доступа к чужому тикету (403).