From 7d39c004a1fb8fc3aa7b04d75b2b04ccff85ff71 Mon Sep 17 00:00:00 2001 From: Aleksey Sabilin Date: Thu, 30 Jul 2026 22:29:52 +0300 Subject: [PATCH] fix(ct): adapt API tests to sole Default personal Default create_calendar to commercial; reuse existing personal on 409; assert verify title Default; cover personal_exists / default_calendar. Refs EventHub/EventHubBack#64 --- test/api/admins/admin_calendars_tests.erl | 17 ++++----- test/api/api_test_runner.erl | 37 +++++++++++++++++--- test/api/users/user_calendar_by_id_tests.erl | 26 ++++++++------ test/api/users/user_calendars_tests.erl | 17 ++++++--- test/api/users/user_verification_tests.erl | 8 ++--- 5 files changed, 68 insertions(+), 37 deletions(-) diff --git a/test/api/admins/admin_calendars_tests.erl b/test/api/admins/admin_calendars_tests.erl index c3c42e8..4444fba 100644 --- a/test/api/admins/admin_calendars_tests.erl +++ b/test/api/admins/admin_calendars_tests.erl @@ -67,21 +67,16 @@ setup() -> Email = api_test_runner:unique_email(<<"caladmin">>), Password = <<"testpass">>, UserToken = api_test_runner:register_and_login(Email, Password), - CalId1 = create_calendar(UserToken, <<"Personal Active">>, <<"Desc1">>), - CalId2 = create_calendar(UserToken, <<"Commercial">>, <<"Desc2">>), - CalId3 = create_calendar(UserToken, <<"Frozen">>, <<"Desc3">>), - update_calendar_admin(AdminToken, CalId2, #{<<"type">> => <<"commercial">>}), + %% Sole personal Default already exists after verify + CalId1 = api_test_runner:existing_personal_calendar_id(UserToken), + CalId2 = api_test_runner:create_calendar(UserToken, + #{title => <<"Commercial">>, description => <<"Desc2">>, type => <<"commercial">>}), + CalId3 = api_test_runner:create_calendar(UserToken, + #{title => <<"Frozen">>, description => <<"Desc3">>, type => <<"commercial">>}), update_calendar_admin(AdminToken, CalId3, #{<<"status">> => <<"frozen">>}), ct:pal(" Created calendars: ~p", [[CalId1, CalId2, CalId3]]), {AdminToken, UserToken, [CalId1, CalId2, CalId3]}. --spec create_calendar(binary(), binary(), binary()) -> binary(). -create_calendar(UserToken, Title, Description) -> - Body = jsx:encode(#{title => Title, description => Description}), - {ok, 201, _, Resp} = api_test_runner:client_request(post, <<"/v1/calendars">>, UserToken, Body), - #{<<"id">> := Id} = jsx:decode(list_to_binary(Resp), [return_maps]), - Id. - -spec update_calendar_admin(binary(), binary(), map()) -> ok. update_calendar_admin(AdminToken, CalId, Updates) -> {ok, 200, _, RespBody} = api_test_runner:admin_request(get, <<"/v1/admin/calendars/", CalId/binary>>, AdminToken, <<"">>), diff --git a/test/api/api_test_runner.erl b/test/api/api_test_runner.erl index 31bdf5c..a5b8d29 100644 --- a/test/api/api_test_runner.erl +++ b/test/api/api_test_runner.erl @@ -25,7 +25,9 @@ future_date/0, register_and_login/2, create_calendar/2, - create_event/3 + create_event/3, + ensure_commercial_subscription/1, + existing_personal_calendar_id/1 , get_admin_refresh_token/0 , admin_super_email/0 , admin_super_password/0]). @@ -409,14 +411,39 @@ register_and_login(Email, Password) -> -spec create_calendar(binary(), map()) -> binary(). create_calendar(Token, Params) -> - Type = maps:get(type, Params, maps:get(<<"type">>, Params, <<"personal">>)), + %% Default commercial: user already has sole personal Default after verify. + Type = maps:get(type, Params, maps:get(<<"type">>, Params, <<"commercial">>)), + Params1 = + case maps:is_key(type, Params) orelse maps:is_key(<<"type">>, Params) of + true -> Params; + false -> Params#{type => Type} + end, case Type of <<"commercial">> -> ensure_commercial_subscription(Token); commercial -> ensure_commercial_subscription(Token); - _ -> ok + <<"personal">> -> ok; + personal -> ok; + _ -> ensure_commercial_subscription(Token) end, - #{<<"id">> := CalId} = client_post(<<"/v1/calendars">>, Token, Params), - CalId. + Body = jsx:encode(Params1), + case client_request(post, <<"/v1/calendars">>, Token, Body) of + {ok, 201, _, RespBody} -> + #{<<"id">> := CalId} = jsx:decode(list_to_binary(RespBody), [return_maps]), + CalId; + {ok, 409, _, _} when Type =:= <<"personal">>; Type =:= personal -> + %% Sole Default personal already exists — reuse it. + existing_personal_calendar_id(Token); + Other -> + error({create_calendar_failed, Other}) + end. + +-spec existing_personal_calendar_id(binary()) -> binary(). +existing_personal_calendar_id(Token) -> + Cals = client_get(<<"/v1/calendars">>, Token), + case [Id || #{<<"id">> := Id, <<"type">> := <<"personal">>} <- Cals] of + [Id | _] -> Id; + [] -> error(no_personal_calendar) + end. -spec ensure_commercial_subscription(binary()) -> ok. ensure_commercial_subscription(Token) -> diff --git a/test/api/users/user_calendar_by_id_tests.erl b/test/api/users/user_calendar_by_id_tests.erl index bb9d296..86b820d 100644 --- a/test/api/users/user_calendar_by_id_tests.erl +++ b/test/api/users/user_calendar_by_id_tests.erl @@ -15,9 +15,8 @@ test() -> OtherToken = api_test_runner:register_and_login( api_test_runner:unique_email(<<"other">>), <<"pass">>), - % Создаём календарь для тестов - #{<<"id">> := CalId} = api_test_runner:client_post(<<"/v1/calendars">>, Token, - #{title => <<"TestCal">>, type => <<"personal">>}), + %% Studio calendar (sole personal Default cannot be deleted) + CalId = api_test_runner:create_calendar(Token, #{title => <<"TestCal">>}), test_get_calendar(Token, CalId), test_get_calendar_unauthorized(CalId), @@ -26,6 +25,7 @@ test() -> test_update_calendar_settings(Token, CalId), test_update_calendar_forbidden(OtherToken, CalId), test_delete_calendar(Token, CalId), + test_delete_default_personal_forbidden(Token), test_delete_calendar_forbidden(OtherToken, CalId), ct:pal("=== All user calendar by id tests passed ==="), @@ -104,19 +104,25 @@ test_update_calendar_forbidden(OtherToken, CalId) -> ct:pal(" OK: got 403"). test_delete_calendar(Token, CalId) -> - ct:pal(" TEST: Delete calendar (soft-delete)"), + ct:pal(" TEST: Delete studio calendar (soft-delete)"), Path = <<"/v1/calendars/", CalId/binary>>, Resp = api_test_runner:client_request(delete, Path, Token), ?assertMatch({ok, 200, _, _}, Resp), ct:pal(" OK: deleted"). -test_delete_calendar_forbidden(OtherToken, CalId) -> - % Первый раз мы уже удалили, но проверим на другом календаре +test_delete_default_personal_forbidden(Token) -> + ct:pal(" TEST: Delete sole personal calendar (403 default_calendar)"), + PersonalId = api_test_runner:existing_personal_calendar_id(Token), + Path = <<"/v1/calendars/", PersonalId/binary>>, + Resp = api_test_runner:client_request(delete, Path, Token), + ?assertMatch({ok, 403, _, _}, Resp), + ct:pal(" OK: got 403 default_calendar"). + +test_delete_calendar_forbidden(OtherToken, _DeletedCalId) -> ct:pal(" TEST: Delete calendar by non-owner (403)"), - % Создадим новый календарь владельцем Token, попробуем удалить OtherToken - #{<<"id">> := NewCalId} = api_test_runner:client_post(<<"/v1/calendars">>, api_test_runner:get_user_token(), - #{title => <<"ForbiddenDel">>, type => <<"personal">>}), + OwnerToken = api_test_runner:get_user_token(), + NewCalId = api_test_runner:create_calendar(OwnerToken, #{title => <<"ForbiddenDel">>}), Path = <<"/v1/calendars/", NewCalId/binary>>, Resp = api_test_runner:client_request(delete, Path, OtherToken), ?assertMatch({ok, 403, _, _}, Resp), - ct:pal(" OK: got 403"). \ No newline at end of file + ct:pal(" OK: got 403"). diff --git a/test/api/users/user_calendars_tests.erl b/test/api/users/user_calendars_tests.erl index 8bf3694..200448b 100644 --- a/test/api/users/user_calendars_tests.erl +++ b/test/api/users/user_calendars_tests.erl @@ -13,11 +13,10 @@ test() -> ct:pal("=== User Calendars Tests ==="), Token = api_test_runner:get_user_token(), - % Создаём один календарь для тестов - #{<<"id">> := CalId} = api_test_runner:client_post(<<"/v1/calendars">>, Token, - #{title => <<"TestCal">>, type => <<"personal">>}), + _CalId = api_test_runner:create_calendar(Token, #{title => <<"TestCal">>}), test_create_calendar(Token), + test_second_personal_rejected(Token), test_list_calendars(Token), test_list_calendars_unauthorized(), @@ -25,15 +24,23 @@ test() -> ok. test_create_calendar(Token) -> - ct:pal(" TEST: Create a new calendar"), + ct:pal(" TEST: Create a new studio calendar"), + api_test_runner:ensure_commercial_subscription(Token), Resp = api_test_runner:client_request(post, <<"/v1/calendars">>, Token, - jsx:encode(#{title => <<"NewCal">>, type => <<"personal">>})), + jsx:encode(#{title => <<"NewCal">>, type => <<"commercial">>})), {ok, 201, _, Body} = Resp, #{<<"id">> := Id, <<"title">> := Title} = jsx:decode(list_to_binary(Body), [return_maps]), ?assert(is_binary(Id)), ?assertEqual(<<"NewCal">>, Title), ct:pal(" OK: created calendar ~s", [Id]). +test_second_personal_rejected(Token) -> + ct:pal(" TEST: Second personal calendar rejected (409)"), + Resp = api_test_runner:client_request(post, <<"/v1/calendars">>, Token, + jsx:encode(#{title => <<"AnotherPersonal">>, type => <<"personal">>})), + ?assertMatch({ok, 409, _, _}, Resp), + ct:pal(" OK: got 409 personal_exists"). + test_list_calendars(Token) -> ct:pal(" TEST: List user calendars"), Calendars = api_test_runner:client_get(<<"/v1/calendars">>, Token), diff --git a/test/api/users/user_verification_tests.erl b/test/api/users/user_verification_tests.erl index 53b3a67..dab1950 100644 --- a/test/api/users/user_verification_tests.erl +++ b/test/api/users/user_verification_tests.erl @@ -47,17 +47,13 @@ test() -> #{<<"token">> := AuthToken} = jsx:decode(list_to_binary(LoginBody), [return_maps]), ?assert(is_binary(AuthToken)), - % 6. После активации — дефолтный приватный personal-календарь + % 6. После активации — единственный personal с title Default Calendars = api_test_runner:client_get(<<"/v1/calendars">>, AuthToken), ?assertEqual(1, length(Calendars)), [DefaultCal] = Calendars, ?assertEqual(<<"personal">>, maps:get(<<"type">>, DefaultCal)), ?assertEqual(<<>>, maps:get(<<"short_name">>, DefaultCal)), - ExpectedTitle = case string:split(Email, <<"@">>) of - [Local, _] when byte_size(Local) > 0 -> Local; - _ -> <<"Мой календарь">> - end, - ?assertEqual(ExpectedTitle, maps:get(<<"title">>, DefaultCal)), + ?assertEqual(<<"Default">>, maps:get(<<"title">>, DefaultCal)), % 7. Повторное использование того же токена – ошибка 404 {ok, 404, _, _} = api_test_runner:client_request(post, <<"/v1/verify">>, <<>>,