1: -module(graphql_roster_SUITE). 2: 3: -compile([export_all, nowarn_export_all]). 4: 5: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]). 6: -import(graphql_helper, [execute_user/3, execute_auth/2, get_listener_port/1, 7: get_listener_config/1, get_ok_value/2, get_err_msg/1, 8: get_err_msg/2, make_creds/1, user_to_jid/1, user_to_bin/1]). 9: 10: -include_lib("common_test/include/ct.hrl"). 11: -include_lib("eunit/include/eunit.hrl"). 12: -include_lib("exml/include/exml.hrl"). 13: -include_lib("escalus/include/escalus.hrl"). 14: -include_lib("../../include/mod_roster.hrl"). 15: 16: suite() -> 17: require_rpc_nodes([mim]) ++ escalus:suite(). 18: 19: all() -> 20: [{group, user_roster}, 21: {group, admin_roster}]. 22: 23: groups() -> 24: [{user_roster, [], user_roster_handler()}, 25: {admin_roster, [], admin_roster_handler()}]. 26: 27: user_roster_handler() -> 28: [user_add_and_delete_contact, 29: user_try_add_nonexistent_contact, 30: user_add_contacts, 31: user_try_delete_nonexistent_contact, 32: user_delete_contacts, 33: user_invite_accept_and_cancel_subscription, 34: user_decline_subscription_ask, 35: user_list_contacts, 36: user_get_contact, 37: user_get_nonexistent_contact 38: ]. 39: 40: admin_roster_handler() -> 41: [admin_add_and_delete_contact, 42: admin_try_add_nonexistent_contact, 43: admin_try_add_contact_to_nonexistent_user, 44: admin_try_add_contact_with_unknown_domain, 45: admin_add_contacts, 46: admin_try_delete_nonexistent_contact, 47: admin_try_delete_contact_with_unknown_domain, 48: admin_delete_contacts, 49: admin_invite_accept_and_cancel_subscription, 50: admin_decline_subscription_ask, 51: admin_try_subscribe_with_unknown_domain, 52: admin_set_mutual_subscription, 53: admin_set_mutual_subscription_try_connect_nonexistent_users, 54: admin_set_mutual_subscription_try_disconnect_nonexistent_users, 55: admin_subscribe_to_all, 56: admin_subscribe_to_all_with_wrong_user, 57: admin_subscribe_all_to_all, 58: admin_subscribe_all_to_all_with_wrong_user, 59: admin_list_contacts, 60: admin_list_contacts_wrong_user, 61: admin_get_contact, 62: admin_get_contact_wrong_user 63: ]. 64: 65: init_per_suite(Config) -> 66: Config2 = escalus:init_per_suite(Config), 67: dynamic_modules:save_modules(domain_helper:host_type(), Config2). 68: 69: end_per_suite(Config) -> 70: dynamic_modules:restore_modules(Config), 71: escalus:end_per_suite(Config). 72: 73: init_per_group(admin_roster, Config) -> 74: graphql_helper:init_admin_handler(Config); 75: init_per_group(user_roster, Config) -> 76: [{schema_endpoint, user} | Config]. 77: 78: end_per_group(admin_roster, _Config) -> 79: escalus_fresh:clean(); 80: end_per_group(user_roster, _Config) -> 81: escalus_fresh:clean(). 82: 83: init_per_testcase(CaseName, Config) -> 84: escalus:init_per_testcase(CaseName, Config). 85: 86: end_per_testcase(CaseName, Config) -> 87: escalus:end_per_testcase(CaseName, Config). 88: 89: -define(ADD_CONTACT_PATH, [data, roster, addContact]). 90: -define(ADD_CONTACTS_PATH, [data, roster, addContacts]). 91: -define(DELETE_CONTACT_PATH, [data, roster, deleteContact]). 92: -define(DELETE_CONTACTS_PATH, [data, roster, deleteContacts]). 93: -define(LIST_CONTACTS_PATH, [data, roster, listContacts]). 94: -define(GET_CONTACT_PATH, [data, roster, getContact]). 95: -define(SUBSCRIBE_ALL_TO_ALL_PATH, [data, roster, subscribeAllToAll]). 96: -define(SUBSCRIBE_TO_ALL_PATH, [data, roster, subscribeToAll]). 97: -define(MUTUAL_SUBSCRIPTION_PATH, [data, roster, setMutualSubscription]). 98: 99: -define(NONEXISTENT_DOMAIN_USER, <<"abc@abc">>). 100: -define(NONEXISTENT_USER, <<"abc@", (domain_helper:domain())/binary>>). 101: -define(NONEXISTENT_USER2, <<"abc2@", (domain_helper:domain())/binary>>). 102: -define(DEFAULT_GROUPS, [<<"Family">>]). 103: 104: %% Admin test cases 105: 106: admin_add_and_delete_contact(Config) -> 107: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 108: fun admin_add_and_delete_contact_story/3). 109: 110: admin_add_and_delete_contact_story(Config, Alice, Bob) -> 111: Res = admin_add_contact(Alice, Bob, Config), 112: ?assertNotEqual(nomatch, binary:match(get_ok_value(?ADD_CONTACT_PATH, Res), 113: <<"successfully">>)), 114: check_contacts([Bob], Alice), 115: 116: Res2 = execute_auth(admin_delete_contact_body(Alice, Bob), Config), 117: ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_CONTACT_PATH, Res2), 118: <<"successfully">>)), 119: check_contacts([], Alice). 120: 121: admin_try_add_nonexistent_contact(Config) -> 122: escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_try_add_nonexistent_contact/2). 123: 124: admin_try_add_nonexistent_contact(Config, Alice) -> 125: Contact = ?NONEXISTENT_DOMAIN_USER, 126: Res = admin_add_contact(Alice, Contact, Config), 127: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), Contact)), 128: check_contacts([], Alice). 129: 130: admin_try_add_contact_to_nonexistent_user(Config) -> 131: User = ?NONEXISTENT_USER, 132: Contact = ?NONEXISTENT_USER2, 133: Res = admin_add_contact(User, Contact, Config), 134: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), User)), 135: check_contacts([], User). 136: 137: admin_try_add_contact_with_unknown_domain(Config) -> 138: User = ?NONEXISTENT_DOMAIN_USER, 139: Contact = ?NONEXISTENT_USER2, 140: Res = admin_add_contact(User, Contact, Config), 141: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 142: 143: admin_try_delete_nonexistent_contact(Config) -> 144: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 145: fun admin_try_delete_nonexistent_contact_story/3). 146: 147: admin_try_delete_nonexistent_contact_story(Config, Alice, Bob) -> 148: Res = execute_auth(admin_delete_contact_body(Alice, Bob), Config), 149: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not exist">>)). 150: 151: admin_try_delete_contact_with_unknown_domain(Config) -> 152: User = ?NONEXISTENT_DOMAIN_USER, 153: Res = execute_auth(admin_delete_contact_body(User, User), Config), 154: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 155: 156: admin_add_contacts(Config) -> 157: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 158: fun admin_add_contacts_story/3). 159: 160: admin_add_contacts_story(Config, Alice, Bob) -> 161: Res = execute_auth(admin_add_contacts_body(Alice, [Bob, ?NONEXISTENT_DOMAIN_USER]), Config), 162: [R1, null] = get_ok_value(?ADD_CONTACTS_PATH, Res), 163: ?assertNotEqual(nomatch, binary:match(R1, <<"successfully">>)), 164: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). 165: 166: admin_delete_contacts(Config) -> 167: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 168: fun admin_delete_contacts_story/3). 169: 170: admin_delete_contacts_story(Config, Alice, Bob) -> 171: execute_auth(admin_add_contacts_body(Alice, [Bob]), Config), 172: Res = execute_auth(admin_delete_contacts_body(Alice, [Bob, ?NONEXISTENT_DOMAIN_USER]), Config), 173: [R1, null] = get_ok_value(?DELETE_CONTACTS_PATH, Res), 174: ?assertNotEqual(nomatch, binary:match(R1, <<"successfully">>)), 175: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). 176: 177: admin_invite_accept_and_cancel_subscription(Config) -> 178: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 179: fun admin_invite_accept_and_cancel_subscription_story/3). 180: 181: admin_invite_accept_and_cancel_subscription_story(Config, Alice, Bob) -> 182: % Add contacts 183: admin_add_contact(Alice, Bob, Config), 184: admin_add_contact(Bob, Alice, Config), 185: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), 186: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), 187: % Send invitation to subscribe 188: execute_auth(admin_subscription_body(Alice, Bob, <<"INVITE">>), Config), 189: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), 190: escalus:assert(is_presence_with_type, [<<"subscribe">>], escalus:wait_for_stanza(Bob)), 191: ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Alice, Bob)), 192: % Accept invitation 193: execute_auth(admin_subscription_body(Bob, Alice, <<"ACCEPT">>), Config), 194: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob)), 195: IsSub = fun(S) -> escalus_pred:is_presence_with_type(<<"subscribed">>, S) end, 196: escalus:assert_many([is_roster_set, IsSub, is_presence], 197: escalus:wait_for_stanzas(Alice, 3)), 198: ?assertMatch(#roster{ask = none, subscription = from}, get_roster(Bob, Alice)), 199: % Cancel subscription 200: execute_auth(admin_subscription_body(Alice, Bob, <<"CANCEL">>), Config), 201: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), 202: ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Alice, Bob)). 203: 204: admin_decline_subscription_ask(Config) -> 205: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 206: fun admin_decline_subscription_ask_story/3). 207: 208: admin_decline_subscription_ask_story(Config, Alice, Bob) -> 209: % Add contacts 210: execute_auth(admin_add_contact_body(Alice, Bob, null, null), Config), 211: execute_auth(admin_add_contact_body(Bob, Alice, null, null), Config), 212: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), 213: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), 214: % Send invitation to subscribe 215: execute_auth(admin_subscription_body(Bob, Alice, <<"INVITE">>), Config), 216: ?assertMatch(#roster{ask = in, subscription = none}, get_roster(Alice, Bob)), 217: ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Bob, Alice)), 218: % Decline the invitation 219: execute_auth(admin_subscription_body(Alice, Bob, <<"DECLINE">>), Config), 220: ?assertMatch(does_not_exist, get_roster(Alice, Bob)), 221: ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Bob, Alice)). 222: 223: admin_try_subscribe_with_unknown_domain(Config) -> 224: Bob = ?NONEXISTENT_DOMAIN_USER, 225: Alice = ?NONEXISTENT_USER, 226: Res = execute_auth(admin_subscription_body(Bob, Alice, <<"INVITE">>), Config), 227: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 228: 229: admin_set_mutual_subscription(Config) -> 230: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 231: fun admin_set_mutual_subscription_story/3). 232: 233: admin_set_mutual_subscription_story(Config, Alice, Bob) -> 234: Res = execute_auth(admin_mutual_subscription_body(Alice, Bob, <<"CONNECT">>), Config), 235: ?assertNotEqual(nomatch, binary:match(get_ok_value(?MUTUAL_SUBSCRIPTION_PATH, Res), 236: <<"successfully">>)), 237: ?assertMatch(#roster{ask = none, subscription = both}, get_roster(Alice, Bob)), 238: ?assertMatch(#roster{ask = none, subscription = both}, get_roster(Bob, Alice)), 239: 240: Res2 = execute_auth(admin_mutual_subscription_body(Alice, Bob, <<"DISCONNECT">>), Config), 241: ?assertNotEqual(nomatch, binary:match(get_ok_value(?MUTUAL_SUBSCRIPTION_PATH, Res2), 242: <<"successfully">>)), 243: ?assertMatch(does_not_exist, get_roster(Alice, Bob)), 244: ?assertMatch(does_not_exist, get_roster(Bob, Alice)). 245: 246: admin_set_mutual_subscription_try_connect_nonexistent_users(Config) -> 247: Alice = ?NONEXISTENT_DOMAIN_USER, 248: Bob = ?NONEXISTENT_USER, 249: Res = execute_auth(admin_mutual_subscription_body(Alice, Bob, <<"CONNECT">>), Config), 250: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 251: 252: admin_set_mutual_subscription_try_disconnect_nonexistent_users(Config) -> 253: Alice = ?NONEXISTENT_DOMAIN_USER, 254: Bob = ?NONEXISTENT_USER, 255: Res = execute_auth(admin_mutual_subscription_body(Alice, Bob, <<"DISCONNECT">>), Config), 256: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 257: 258: admin_subscribe_to_all(Config) -> 259: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}], 260: fun admin_subscribe_to_all_story/4). 261: 262: admin_subscribe_to_all_story(Config, Alice, Bob, Kate) -> 263: Res = execute_auth(admin_subscribe_to_all_body(Alice, [Bob, Kate]), Config), 264: check_if_created_succ(?SUBSCRIBE_TO_ALL_PATH, Res), 265: 266: check_contacts([Bob, Kate], Alice), 267: check_contacts([Alice], Bob), 268: check_contacts([Alice], Kate). 269: 270: admin_subscribe_to_all_with_wrong_user(Config) -> 271: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 272: fun admin_subscribe_to_all_with_wrong_user_story/3). 273: 274: admin_subscribe_to_all_with_wrong_user_story(Config, Alice, Bob) -> 275: Kate = ?NONEXISTENT_DOMAIN_USER, 276: Res = execute_auth(admin_subscribe_to_all_body(Alice, [Bob, Kate]), Config), 277: check_if_created_succ(?SUBSCRIBE_TO_ALL_PATH, Res, [true, false]), 278: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)), 279: 280: check_contacts([Bob], Alice), 281: check_contacts([Alice], Bob). 282: 283: admin_subscribe_all_to_all(Config) -> 284: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}, {kate, 1}], 285: fun admin_subscribe_all_to_all_story/4). 286: 287: admin_subscribe_all_to_all_story(Config, Alice, Bob, Kate) -> 288: Res = execute_auth(admin_subscribe_all_to_all_body([Alice, Bob, Kate]), Config), 289: check_if_created_succ(?SUBSCRIBE_ALL_TO_ALL_PATH, Res), 290: 291: check_contacts([Bob, Kate], Alice), 292: check_contacts([Alice, Kate], Bob), 293: check_contacts([Alice, Bob], Kate). 294: 295: admin_subscribe_all_to_all_with_wrong_user(Config) -> 296: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 297: fun admin_subscribe_all_to_all_with_wrong_user_story/3). 298: 299: admin_subscribe_all_to_all_with_wrong_user_story(Config, Alice, Bob) -> 300: Kate = ?NONEXISTENT_DOMAIN_USER, 301: Res = execute_auth(admin_subscribe_all_to_all_body([Alice, Bob, Kate]), Config), 302: check_if_created_succ(?SUBSCRIBE_ALL_TO_ALL_PATH, Res, [true, false, false]), 303: ?assertNotEqual(nomatch, binary:match(get_err_msg(1, Res), <<"does not exist">>)), 304: ?assertNotEqual(nomatch, binary:match(get_err_msg(2, Res), <<"does not exist">>)), 305: 306: check_contacts([Bob], Alice), 307: check_contacts([Alice], Bob). 308: 309: admin_list_contacts(Config) -> 310: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 311: fun admin_list_contacts_story/3). 312: 313: admin_list_contacts_story(Config, Alice, Bob) -> 314: BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), 315: BobName = escalus_client:username(Bob), 316: admin_add_contact(Alice, Bob, Config), 317: Res = execute_auth(admin_list_contacts_body(Alice), Config), 318: [#{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, 319: <<"name">> := BobName, <<"groups">> := ?DEFAULT_GROUPS}] = 320: get_ok_value([data, roster, listContacts], Res). 321: 322: admin_list_contacts_wrong_user(Config) -> 323: % User with a non-existent domain 324: Res = execute_auth(admin_list_contacts_body(?NONEXISTENT_DOMAIN_USER), Config), 325: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)), 326: % Non-existent user with existent domain 327: Res2 = execute_auth(admin_list_contacts_body(?NONEXISTENT_USER), Config), 328: ?assertEqual([], get_ok_value(?LIST_CONTACTS_PATH, Res2)). 329: 330: admin_get_contact(Config) -> 331: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 332: fun admin_get_contact_story/3). 333: 334: admin_get_contact_story(Config, Alice, Bob) -> 335: BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), 336: BobName = escalus_client:username(Bob), 337: admin_add_contact(Alice, Bob, Config), 338: Res = execute_auth(admin_get_contact_body(Alice, Bob), Config), 339: #{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, 340: <<"name">> := BobName, <<"groups">> := ?DEFAULT_GROUPS} = 341: get_ok_value([data, roster, getContact], Res). 342: 343: admin_get_contact_wrong_user(Config) -> 344: % User with a non-existent domain 345: Res = execute_auth(admin_get_contact_body(?NONEXISTENT_DOMAIN_USER, ?NONEXISTENT_USER), Config), 346: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)), 347: % Non-existent user with existent domain 348: Res2 = execute_auth(admin_get_contact_body(?NONEXISTENT_USER, ?NONEXISTENT_USER), Config), 349: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not exist">>)). 350: 351: %% User test cases 352: 353: user_add_and_delete_contact(Config) -> 354: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 355: fun user_add_and_delete_contact_story/3). 356: 357: user_add_and_delete_contact_story(Config, Alice, Bob) -> 358: % Add a new contact 359: Res = user_add_contact(Alice, Bob, Config), 360: ?assertNotEqual(nomatch, binary:match(get_ok_value(?ADD_CONTACT_PATH, Res), 361: <<"successfully">>)), 362: check_contacts([Bob], Alice), 363: % Delete a contact 364: Res2 = execute_user(user_delete_contact_body(Bob), Alice, Config), 365: ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_CONTACT_PATH, Res2), 366: <<"successfully">>)), 367: check_contacts([], Alice). 368: 369: user_try_add_nonexistent_contact(Config) -> 370: escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_try_add_nonexistent_contact/2). 371: 372: user_try_add_nonexistent_contact(Config, Alice) -> 373: Contact = ?NONEXISTENT_DOMAIN_USER, 374: Res = user_add_contact(Alice, Contact, Config), 375: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), Contact)), 376: check_contacts([], Alice). 377: 378: user_add_contacts(Config) -> 379: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 380: fun user_add_contacts_story/3). 381: 382: user_add_contacts_story(Config, Alice, Bob) -> 383: Res = execute_user(user_add_contacts_body([Bob, ?NONEXISTENT_DOMAIN_USER]), Alice, Config), 384: [R1, null] = get_ok_value(?ADD_CONTACTS_PATH, Res), 385: ?assertNotEqual(nomatch, binary:match(R1, <<"successfully">>)), 386: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). 387: 388: user_try_delete_nonexistent_contact(Config) -> 389: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 390: fun user_try_delete_nonexistent_contact_story/3). 391: 392: user_try_delete_nonexistent_contact_story(Config, Alice, Bob) -> 393: Res = execute_user(user_delete_contact_body(Bob), Alice, Config), 394: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not exist">>)). 395: 396: user_delete_contacts(Config) -> 397: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 398: fun user_delete_contacts_story/3). 399: 400: user_delete_contacts_story(Config, Alice, Bob) -> 401: user_add_contact(Alice, Bob, Config), 402: 403: Res = execute_user(user_delete_contacts_body([Bob, ?NONEXISTENT_DOMAIN_USER]), Alice, Config), 404: [R1, null] = get_ok_value(?DELETE_CONTACTS_PATH, Res), 405: ?assertNotEqual(nomatch, binary:match(R1, <<"successfully">>)), 406: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). 407: 408: user_invite_accept_and_cancel_subscription(Config) -> 409: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 410: fun user_invite_accept_and_cancel_subscription_story/3). 411: 412: user_invite_accept_and_cancel_subscription_story(Config, Alice, Bob) -> 413: % Add contacts 414: user_add_contact(Alice, Bob, Config), 415: user_add_contact(Bob, Alice, Config), 416: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), 417: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), 418: % Send invitation to subscribe 419: execute_user(user_subscription_body(Bob, <<"INVITE">>), Alice, Config), 420: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), 421: escalus:assert(is_presence_with_type, [<<"subscribe">>], escalus:wait_for_stanza(Bob)), 422: ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Alice, Bob)), 423: % Accept invitation 424: execute_user(user_subscription_body(Alice, <<"ACCEPT">>), Bob, Config), 425: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob)), 426: IsSub = fun(S) -> escalus_pred:is_presence_with_type(<<"subscribed">>, S) end, 427: escalus:assert_many([is_roster_set, IsSub, is_presence], 428: escalus:wait_for_stanzas(Alice, 3)), 429: ?assertMatch(#roster{ask = none, subscription = from}, get_roster(Bob, Alice)), 430: % Cancel subscription 431: execute_user(user_subscription_body(Bob, <<"CANCEL">>), Alice, Config), 432: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)), 433: ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Alice, Bob)). 434: 435: user_decline_subscription_ask(Config) -> 436: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 437: fun user_decline_subscription_ask_story/3). 438: 439: user_decline_subscription_ask_story(Config, Alice, Bob) -> 440: % Add contacts 441: user_add_contact(Alice, Bob, Config), 442: user_add_contact(Bob, Alice, Config), 443: escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob, 1)), 444: escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice, 1)), 445: % Send invitation to subscribe 446: execute_user(user_subscription_body(Alice, <<"INVITE">>), Bob, Config), 447: ?assertMatch(#roster{ask = in, subscription = none}, get_roster(Alice, Bob)), 448: ?assertMatch(#roster{ask = out, subscription = none}, get_roster(Bob, Alice)), 449: % Decline the invitation 450: execute_user(user_subscription_body(Bob, <<"DECLINE">>), Alice, Config), 451: ?assertMatch(does_not_exist, get_roster(Alice, Bob)), 452: ?assertMatch(#roster{ask = none, subscription = none}, get_roster(Bob, Alice)). 453: 454: user_list_contacts(Config) -> 455: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 456: fun user_list_contacts_story/3). 457: 458: user_list_contacts_story(Config, Alice, Bob) -> 459: BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), 460: Name = <<"Bobek">>, 461: execute_user(user_add_contact_body(Bob, Name, ?DEFAULT_GROUPS), Alice, Config), 462: Res = execute_user(user_list_contacts_body(), Alice, Config), 463: [#{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, 464: <<"name">> := Name, <<"groups">> := ?DEFAULT_GROUPS}] = 465: get_ok_value(?LIST_CONTACTS_PATH, Res). 466: 467: user_get_contact(Config) -> 468: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 469: fun user_get_contact_story/3). 470: 471: user_get_contact_story(Config, Alice, Bob) -> 472: BobBin = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)), 473: Name = <<"Bobek">>, 474: execute_user(user_add_contact_body(Bob, Name, ?DEFAULT_GROUPS), Alice, Config), 475: Res = execute_user(user_get_contact_body(Bob), Alice, Config), 476: #{<<"subscription">> := <<"NONE">>, <<"ask">> := <<"NONE">>, <<"jid">> := BobBin, 477: <<"name">> := Name, <<"groups">> := ?DEFAULT_GROUPS} = 478: get_ok_value(?GET_CONTACT_PATH, Res). 479: 480: user_get_nonexistent_contact(Config) -> 481: escalus:fresh_story_with_config(Config, [{alice, 1}], 482: fun user_get_nonexistent_contact_story/2). 483: 484: user_get_nonexistent_contact_story(Config, Alice) -> 485: Res = execute_user(user_get_contact_body(?NONEXISTENT_DOMAIN_USER), Alice, Config), 486: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not exist">>)). 487: 488: % Helpers 489: 490: admin_add_contact(User, Contact, Config) -> 491: Name = escalus_utils:get_username(Contact), 492: execute_auth(admin_add_contact_body(User, Contact, Name, ?DEFAULT_GROUPS), Config). 493: 494: user_add_contact(User, Contact, Config) -> 495: Name = escalus_utils:get_username(Contact), 496: execute_user(user_add_contact_body(Contact, Name, ?DEFAULT_GROUPS), User, Config). 497: 498: check_contacts(ContactClients, User) -> 499: Expected = [escalus_utils:jid_to_lower(escalus_client:short_jid(Client)) 500: || Client <- ContactClients], 501: ExpectedNames = [escalus_client:username(Client) || Client <- ContactClients], 502: ActualContacts = get_roster(User), 503: Actual = [ jid:to_binary(JID) || #roster{jid = JID} <- ActualContacts], 504: ActualNames = [ Name || #roster{name = Name} <- ActualContacts], 505: ?assertEqual(lists:sort(Expected), lists:sort(Actual)), 506: ?assertEqual(lists:sort(ExpectedNames), lists:sort(ActualNames)), 507: [?assertEqual(?DEFAULT_GROUPS, Groups) || #roster{groups = Groups} <- ActualContacts]. 508: 509: check_if_created_succ(Path, Res) -> 510: check_if_created_succ(Path, Res, null). 511: 512: check_if_created_succ(Path, Res, ExpectedOkValue) -> 513: OkList = get_ok_value(Path, Res), 514: 515: OkList2 = case ExpectedOkValue of 516: null -> 517: [{Msg, true} || Msg <- OkList]; 518: _ when is_list(ExpectedOkValue) -> 519: lists:zip(OkList, ExpectedOkValue) 520: end, 521: [?assertNotEqual(nomatch, binary:match(Msg, <<"created successfully">>)) 522: || {Msg, ShouldHaveValue} <- OkList2, ShouldHaveValue]. 523: 524: get_roster(User) -> 525: {ok, Roster} = rpc(mim(), mod_roster_api, list_contacts, [user_to_jid(User)]), 526: Roster. 527: 528: get_roster(User, Contact) -> 529: rpc(mim(), mod_roster, get_roster_entry, 530: [domain_helper:host_type(), 531: user_to_jid(User), 532: jid:to_lower(user_to_jid(Contact)), 533: full]). 534: 535: make_contact(Users) when is_list(Users) -> 536: [make_contact(U) || U <- Users]; 537: make_contact(U) -> 538: #{jid => user_to_bin(U), name => escalus_utils:get_username(U), groups => ?DEFAULT_GROUPS}. 539: 540: %% Request bodies 541: 542: admin_add_contact_body(User, Contact, Name, Groups) -> 543: Query = <<"mutation M1($user: JID!, $contact: JID!, $name: String, $groups: [String!]) 544: { roster { addContact(user: $user, contact: $contact, name: $name, groups: $groups) } }">>, 545: OpName = <<"M1">>, 546: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact), 547: name => Name, groups => Groups}, 548: #{query => Query, operationName => OpName, variables => Vars}. 549: 550: admin_add_contacts_body(User, Contacts) -> 551: Query = <<"mutation M1($user: JID!, $contacts: [ContactInput!]!) 552: { roster { addContacts(user: $user, contacts: $contacts) } }">>, 553: OpName = <<"M1">>, 554: Vars = #{user => user_to_bin(User), contacts => make_contact(Contacts)}, 555: #{query => Query, operationName => OpName, variables => Vars}. 556: 557: admin_delete_contact_body(User, Contact) -> 558: Query = <<"mutation M1($user: JID!, $contact: JID!) 559: { roster { deleteContact(user: $user, contact: $contact) } }">>, 560: OpName = <<"M1">>, 561: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact)}, 562: #{query => Query, operationName => OpName, variables => Vars}. 563: 564: admin_delete_contacts_body(User, Contacts) -> 565: Query = <<"mutation M1($user: JID!, $contacts: [JID!]!) 566: { roster { deleteContacts(user: $user, contacts: $contacts) } }">>, 567: OpName = <<"M1">>, 568: Vars = #{user => user_to_bin(User), contacts => [user_to_bin(C) || C <- Contacts]}, 569: #{query => Query, operationName => OpName, variables => Vars}. 570: 571: admin_subscription_body(User, Contact, Action) -> 572: Query = <<"mutation M1($user: JID!, $contact: JID!, $action: SubAction!) 573: { roster { subscription(user: $user, contact: $contact, action: $action) } }">>, 574: OpName = <<"M1">>, 575: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact), action => Action}, 576: #{query => Query, operationName => OpName, variables => Vars}. 577: 578: admin_mutual_subscription_body(User, Contact, Action) -> 579: Query = <<"mutation M1($userA: JID!, $userB: JID!, $action: MutualSubAction!) 580: { roster { setMutualSubscription(userA: $userA, userB: $userB, action: $action) } }">>, 581: OpName = <<"M1">>, 582: Vars = #{userA => user_to_bin(User), userB => user_to_bin(Contact), action => Action}, 583: #{query => Query, operationName => OpName, variables => Vars}. 584: 585: admin_subscribe_to_all_body(User, Contacts) -> 586: Query = <<"mutation M1($user: ContactInput!, $contacts: [ContactInput!]!) 587: { roster { subscribeToAll(user: $user, contacts: $contacts) } }">>, 588: OpName = <<"M1">>, 589: Vars = #{user => make_contact(User), contacts => make_contact(Contacts)}, 590: #{query => Query, operationName => OpName, variables => Vars}. 591: 592: admin_subscribe_all_to_all_body(Users) -> 593: Query = <<"mutation M1($contacts: [ContactInput!]!) 594: { roster { subscribeAllToAll(contacts: $contacts) } }">>, 595: OpName = <<"M1">>, 596: Vars = #{contacts => make_contact(Users)}, 597: #{query => Query, operationName => OpName, variables => Vars}. 598: 599: admin_list_contacts_body(User) -> 600: Query = <<"query Q1($user: JID!) 601: { roster { listContacts(user: $user) 602: { jid subscription ask name groups} } }">>, 603: OpName = <<"Q1">>, 604: Vars = #{user => user_to_bin(User)}, 605: #{query => Query, operationName => OpName, variables => Vars}. 606: 607: admin_get_contact_body(User, Contact) -> 608: Query = <<"query Q1($user: JID!, $contact: JID!) 609: { roster { getContact(user: $user, contact: $contact) 610: { jid subscription ask name groups} } }">>, 611: OpName = <<"Q1">>, 612: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact)}, 613: #{query => Query, operationName => OpName, variables => Vars}. 614: 615: user_add_contact_body(Contact, Name, Groups) -> 616: Query = <<"mutation M1($contact: JID!, $name: String, $groups: [String!]) 617: { roster { addContact(contact: $contact, name: $name, groups: $groups) } }">>, 618: OpName = <<"M1">>, 619: Vars = #{contact => user_to_bin(Contact), name => Name, groups => Groups}, 620: #{query => Query, operationName => OpName, variables => Vars}. 621: 622: user_add_contacts_body(Contacts) -> 623: Query = <<"mutation M1($contacts: [ContactInput!]!) 624: { roster { addContacts(contacts: $contacts) } }">>, 625: OpName = <<"M1">>, 626: Vars = #{contacts => make_contact(Contacts)}, 627: #{query => Query, operationName => OpName, variables => Vars}. 628: 629: user_delete_contact_body(Contact) -> 630: Query = <<"mutation M1($contact: JID!) 631: { roster { deleteContact(contact: $contact) } }">>, 632: OpName = <<"M1">>, 633: Vars = #{contact => user_to_bin(Contact)}, 634: #{query => Query, operationName => OpName, variables => Vars}. 635: 636: user_delete_contacts_body(Contacts) -> 637: Query = <<"mutation M1($contacts: [JID!]!) 638: { roster { deleteContacts(contacts: $contacts) } }">>, 639: OpName = <<"M1">>, 640: Vars = #{contacts => [user_to_bin(C) || C <- Contacts]}, 641: #{query => Query, operationName => OpName, variables => Vars}. 642: 643: user_subscription_body(Contact, Action) -> 644: Query = <<"mutation M1($contact: JID!, $action: SubAction!) 645: { roster { subscription(contact: $contact, action: $action) } }">>, 646: OpName = <<"M1">>, 647: Vars = #{contact => user_to_bin(Contact), action => Action}, 648: #{query => Query, operationName => OpName, variables => Vars}. 649: 650: user_list_contacts_body() -> 651: Query = <<"query Q1 { roster { listContacts 652: { jid subscription ask name groups} } }">>, 653: #{query => Query, operationName => <<"Q1">>, variables => #{}}. 654: 655: user_get_contact_body(Contact) -> 656: Query = <<"query Q1($contact: JID!) 657: { roster { getContact(contact: $contact) 658: { jid subscription ask name groups} } }">>, 659: OpName = <<"Q1">>, 660: Vars = #{contact => user_to_bin(Contact)}, 661: #{query => Query, operationName => OpName, variables => Vars}.