diff --git a/big_tests/tests/graphql_roster_SUITE.erl b/big_tests/tests/graphql_roster_SUITE.erl index 69977422b5..1085bb7d7f 100644 --- a/big_tests/tests/graphql_roster_SUITE.erl +++ b/big_tests/tests/graphql_roster_SUITE.erl @@ -25,10 +25,17 @@ groups() -> {admin_roster, [], admin_roster_handler()}]. user_roster_handler() -> - [user_add_contact, - user_remove_contact, - user_subscription, - user_list_contacts]. + [user_add_and_delete_contact, + user_try_add_nonexistent_contact, + user_add_contacts, + user_try_add_contacts_with_nonexistent_user, + user_try_delete_nonexistent_contact, + user_invite_accept_and_cancel_subscription, + user_decline_subscription_ask, + user_list_contacts, + user_get_contact, + user_get_nonexistent_contact + ]. admin_roster_handler() -> [admin_add_and_delete_contact, @@ -292,7 +299,7 @@ admin_list_contacts_wrong_user(Config) -> admin_get_contact(Config) -> escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], - fun admin_list_contacts_story/3). + fun admin_get_contact_story/3). admin_get_contact_story(Config, Alice, Bob) -> BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), @@ -311,20 +318,147 @@ admin_get_contact_wrong_user(Config) -> Res2 = execute_auth(admin_get_contact_body(?NONEXISTENT_USER, ?NONEXISTENT_USER), Config), ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not exist">>)). -user_add_contact(Config) -> - ok. +user_add_and_delete_contact(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_add_and_delete_contact_story/3). -user_remove_contact(Config) -> - ok. +user_add_and_delete_contact_story(Config, Alice, Bob) -> + % Add a new contact + Res = execute_user(user_add_contact_body(Bob, null, null), Alice, Config), + ?assertNotEqual(nomatch, binary:match(get_ok_value(?ADD_CONTACT_PATH, Res), + <<"successfully">>)), + ?assertMatch(#roster{}, get_roster(Alice, Bob)), + % Delete a contact + Res2 = execute_user(user_delete_contact_body(Bob), Alice, Config), + ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_CONTACT_PATH, Res2), + <<"successfully">>)), + ?assertMatch(does_not_exist, get_roster(Alice, Bob)). + +user_try_add_nonexistent_contact(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_try_add_nonexistent_contact/2). -user_subscription(Connfig) -> - ok. +user_try_add_nonexistent_contact(Config, Alice) -> + Contact = ?NONEXISTENT_DOMAIN_USER, + Res = execute_user(user_add_contact_body(Contact, null, null), Alice, Config), + ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), Contact)), + ?assertMatch(does_not_exist, get_roster(Alice, Contact)). + +user_add_contacts(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}], + fun user_add_contacts_story/4). + +user_add_contacts_story(Config, Alice, Bob, Kate) -> + Res = execute_user(user_add_contacts_body([Bob, Kate]), Alice, Config), + [?assertNotEqual(nomatch, binary:match(R, <<"successfully">>)) + || R <- get_ok_value(?ADD_CONTACTS_PATH, Res)]. + +user_try_add_contacts_with_nonexistent_user(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_try_add_contacts_with_nonexistent_user_story/3). + +user_try_add_contacts_with_nonexistent_user_story(Config, Alice, Bob) -> + Res = execute_user(user_add_contacts_body([Bob, ?NONEXISTENT_DOMAIN_USER]), Alice, Config), + [R1, null] = get_ok_value(?ADD_CONTACTS_PATH, Res), + ?assertNotEqual(nomatch, binary:match(R1, <<"successfully">>)), + ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). + +user_try_delete_nonexistent_contact(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_try_delete_nonexistent_contact_story/3). + +user_try_delete_nonexistent_contact_story(Config, Alice, Bob) -> + Res = execute_user(user_delete_contact_body(Bob), Alice, Config), + ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not exist">>)). + +user_invite_accept_and_cancel_subscription(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_invite_accept_and_cancel_subscription_story/3). + +user_invite_accept_and_cancel_subscription_story(Config, Alice, Bob) -> + % Add contacts + execute_user(user_add_contact_body(Bob, <<"Bobek">>, null), Alice, Config), + execute_user(user_add_contact_body(Alice, <<"Ali">>, null), Bob, Config), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), + % Send invitation to subscribe + execute_user(user_subscription_body(Bob, <<"INVITE">>), Alice, Config), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), + escalus:assert(is_presence_with_type, [<<"subscribe">>], + escalus:wait_for_stanza(Bob)), + ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Alice, Bob)), + % Accept invitation + execute_user(user_subscription_body(Alice, <<"ACCEPT">>), Bob, Config), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob)), + IsSub = fun(S) -> escalus_pred:is_presence_with_type(<<"subscribed">>, S) end, + escalus:assert_many([is_roster_set, IsSub, is_presence], + escalus:wait_for_stanzas(Alice, 3)), + ?assertMatch(#roster{ask = none, subscription = from}, get_roster(Bob, Alice)), + % Cancel subscription + execute_user(user_subscription_body(Bob, <<"CANCEL">>), Alice, Config), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), + ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Alice, Bob)). + +user_decline_subscription_ask(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_decline_subscription_ask_story/3). + +user_decline_subscription_ask_story(Config, Alice, Bob) -> + % Add contacts + execute_user(user_add_contact_body(Bob, null, null), Alice, Config), + execute_user(user_add_contact_body(Alice, null, null), Bob, Config), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), + escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), + % Send invitation to subscribe + execute_user(user_subscription_body(Alice, <<"INVITE">>), Bob, Config), + ?assertMatch(#roster{ask = in, subscription = none}, get_roster(Alice, Bob)), + ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Bob, Alice)), + % Decline the invitation + execute_user(user_subscription_body(Bob, <<"DECLINE">>), Alice, Config), + ?assertMatch(does_not_exist, get_roster(Alice, Bob)), + ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Bob, Alice)). user_list_contacts(Config) -> - ok. + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_list_contacts_story/3). + +user_list_contacts_story(Config, Alice, Bob) -> + BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), + Name = <<"Bobek">>, + execute_user(user_add_contact_body(Bob, Name, ?DEFAULT_GROUPS), Alice, Config), + Res = execute_user(user_list_contacts_body(), Alice, Config), + [#{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, + <<"name">> := Name, <<"groups">> := ?DEFAULT_GROUPS}] = + get_ok_value(?LIST_CONTACTS_PATH, Res). + +user_get_contact(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], + fun user_get_contact_story/3). + +user_get_contact_story(Config, Alice, Bob) -> + BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), + Name = <<"Bobek">>, + execute_user(user_add_contact_body(Bob, Name, ?DEFAULT_GROUPS), Alice, Config), + Res = execute_user(user_get_contact_body(Bob), Alice, Config), + #{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, + <<"name">> := Name, <<"groups">> := ?DEFAULT_GROUPS} = + get_ok_value(?GET_CONTACT_PATH, Res). + +user_get_nonexistent_contact(Config) -> + escalus:fresh_story_with_config(Config, [{alice, 1}], + fun user_get_nonexistent_contact_story/2). + +user_get_nonexistent_contact_story(Config, Alice) -> + Res = execute_user(user_get_contact_body(?NONEXISTENT_DOMAIN_USER), Alice, Config), + ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). + % Helpers +execute_user(Body, User, Config) -> + Ep = ?config(schema_endpoint, Config), + Creds = make_creds(User), + execute(Ep, Body, Creds). + check_contacts(ContactClients, User, Config) -> Res = execute_auth(admin_list_contacts_body(User), Config), Expected = [escalus_utils:jid_to_lower(escalus_client:short_jid(Client)) @@ -437,3 +571,44 @@ admin_get_contact_body(User, Contact) -> OpName = <<"Q1">>, Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact)}, #{query => Query, operationName => OpName, variables => Vars}. + +user_add_contact_body(Contact, Name, Groups) -> + Query = <<"mutation M1($contact: JID!, $name: String, $groups: [String!]) + { roster { addContact(contact: $contact, name: $name, groups: $groups) } }">>, + OpName = <<"M1">>, + Vars = #{contact => user_to_bin(Contact), name => Name, groups => Groups}, + #{query => Query, operationName => OpName, variables => Vars}. + +user_add_contacts_body(Contacts) -> + Query = <<"mutation M1($contacts: [ContactInput!]!) + { roster { addContacts(contacts: $contacts) } }">>, + OpName = <<"M1">>, + Vars = #{contacts => make_contact(Contacts)}, + #{query => Query, operationName => OpName, variables => Vars}. + +user_delete_contact_body(Contact) -> + Query = <<"mutation M1($contact: JID!) + { roster { deleteContact(contact: $contact) } }">>, + OpName = <<"M1">>, + Vars = #{contact => user_to_bin(Contact)}, + #{query => Query, operationName => OpName, variables => Vars}. + +user_subscription_body(Contact, Action) -> + Query = <<"mutation M1($contact: JID!, $action: SubAction!) + { roster { subscription(contact: $contact, action: $action) } }">>, + OpName = <<"M1">>, + Vars = #{contact => user_to_bin(Contact), action => Action}, + #{query => Query, operationName => OpName, variables => Vars}. + +user_list_contacts_body() -> + Query = <<"query Q1 { roster { listContacts + { jid subscription ask name groups} } }">>, + #{query => Query, operationName => <<"Q1">>, variables => #{}}. + +user_get_contact_body(Contact) -> + Query = <<"query Q1($contact: JID!) + { roster { getContact(contact: $contact) + { jid subscription ask name groups} } }">>, + OpName = <<"Q1">>, + Vars = #{contact => user_to_bin(Contact)}, + #{query => Query, operationName => OpName, variables => Vars}. diff --git a/src/admin_extra/service_admin_extra_roster.erl b/src/admin_extra/service_admin_extra_roster.erl index f786ca16c4..0593e65d0a 100644 --- a/src/admin_extra/service_admin_extra_roster.erl +++ b/src/admin_extra/service_admin_extra_roster.erl @@ -242,7 +242,7 @@ delete_rosteritem(LocalUser, LocalServer, User, Server) -> unsubscribe(LocalJID, RemoteJID) -> ItemEl = build_roster_item(RemoteJID, remove), QueryEl = #xmlel{ name = <<"query">>, - attrs = [{<<"xmlns">>, <<"jabber:iq:roster">>}], + attrs = [{<<"xmlns">>, ?NS_ROSTER}], children = [ItemEl]}, {ok, HostType} = mongoose_domain_api:get_domain_host_type(LocalJID#jid.lserver), mod_roster:set_items(HostType, LocalJID, QueryEl).