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/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]). 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: execute_user(Body, User, Config) -> 499: Ep = ?config(schema_endpoint, Config), 500: Creds = make_creds(User), 501: execute(Ep, Body, Creds). 502: 503: check_contacts(ContactClients, User) -> 504: Expected = [escalus_utils:jid_to_lower(escalus_client:short_jid(Client)) 505: || Client <- ContactClients], 506: ExpectedNames = [escalus_client:username(Client) || Client <- ContactClients], 507: ActualContacts = get_roster(User), 508: Actual = [ jid:to_binary(JID) || #roster{jid = JID} <- ActualContacts], 509: ActualNames = [ Name || #roster{name = Name} <- ActualContacts], 510: ?assertEqual(lists:sort(Expected), lists:sort(Actual)), 511: ?assertEqual(lists:sort(ExpectedNames), lists:sort(ActualNames)), 512: [?assertEqual(?DEFAULT_GROUPS, Groups) || #roster{groups = Groups} <- ActualContacts]. 513: 514: check_if_created_succ(Path, Res) -> 515: check_if_created_succ(Path, Res, null). 516: 517: check_if_created_succ(Path, Res, ExpectedOkValue) -> 518: OkList = get_ok_value(Path, Res), 519: 520: OkList2 = case ExpectedOkValue of 521: null -> 522: [{Msg, true} || Msg <- OkList]; 523: _ when is_list(ExpectedOkValue) -> 524: lists:zip(OkList, ExpectedOkValue) 525: end, 526: [?assertNotEqual(nomatch, binary:match(Msg, <<"created successfully">>)) 527: || {Msg, ShouldHaveValue} <- OkList2, ShouldHaveValue]. 528: 529: get_roster(User) -> 530: {ok, Roster} = rpc(mim(), mod_roster_api, list_contacts, [user_to_jid(User)]), 531: Roster. 532: 533: get_roster(User, Contact) -> 534: rpc(mim(), mod_roster, get_roster_entry, 535: [domain_helper:host_type(), 536: user_to_jid(User), 537: jid:to_lower(user_to_jid(Contact)), 538: full]). 539: 540: user_to_bin(#client{jid = JID} = Client) -> escalus_client:short_jid(Client); 541: user_to_bin(Bin) when is_binary(Bin) -> Bin. 542: 543: user_to_jid(#client{jid = JID}) -> jid:to_bare(jid:from_binary(JID)); 544: user_to_jid(Bin) when is_binary(Bin) -> jid:from_binary(Bin). 545: 546: make_contact(Users) when is_list(Users) -> 547: [make_contact(U) || U <- Users]; 548: make_contact(U) -> 549: #{jid => user_to_bin(U), name => escalus_utils:get_username(U), groups => ?DEFAULT_GROUPS}. 550: 551: %% Request bodies 552: 553: admin_add_contact_body(User, Contact, Name, Groups) -> 554: Query = <<"mutation M1($user: JID!, $contact: JID!, $name: String, $groups: [String!]) 555: { roster { addContact(user: $user, contact: $contact, name: $name, groups: $groups) } }">>, 556: OpName = <<"M1">>, 557: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact), 558: name => Name, groups => Groups}, 559: #{query => Query, operationName => OpName, variables => Vars}. 560: 561: admin_add_contacts_body(User, Contacts) -> 562: Query = <<"mutation M1($user: JID!, $contacts: [ContactInput!]!) 563: { roster { addContacts(user: $user, contacts: $contacts) } }">>, 564: OpName = <<"M1">>, 565: Vars = #{user => user_to_bin(User), contacts => make_contact(Contacts)}, 566: #{query => Query, operationName => OpName, variables => Vars}. 567: 568: admin_delete_contact_body(User, Contact) -> 569: Query = <<"mutation M1($user: JID!, $contact: JID!) 570: { roster { deleteContact(user: $user, contact: $contact) } }">>, 571: OpName = <<"M1">>, 572: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact)}, 573: #{query => Query, operationName => OpName, variables => Vars}. 574: 575: admin_delete_contacts_body(User, Contacts) -> 576: Query = <<"mutation M1($user: JID!, $contacts: [JID!]!) 577: { roster { deleteContacts(user: $user, contacts: $contacts) } }">>, 578: OpName = <<"M1">>, 579: Vars = #{user => user_to_bin(User), contacts => [user_to_bin(C) || C <- Contacts]}, 580: #{query => Query, operationName => OpName, variables => Vars}. 581: 582: admin_subscription_body(User, Contact, Action) -> 583: Query = <<"mutation M1($user: JID!, $contact: JID!, $action: SubAction!) 584: { roster { subscription(user: $user, contact: $contact, action: $action) } }">>, 585: OpName = <<"M1">>, 586: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact), action => Action}, 587: #{query => Query, operationName => OpName, variables => Vars}. 588: 589: admin_mutual_subscription_body(User, Contact, Action) -> 590: Query = <<"mutation M1($userA: JID!, $userB: JID!, $action: MutualSubAction!) 591: { roster { setMutualSubscription(userA: $userA, userB: $userB, action: $action) } }">>, 592: OpName = <<"M1">>, 593: Vars = #{userA => user_to_bin(User), userB => user_to_bin(Contact), action => Action}, 594: #{query => Query, operationName => OpName, variables => Vars}. 595: 596: admin_subscribe_to_all_body(User, Contacts) -> 597: Query = <<"mutation M1($user: ContactInput!, $contacts: [ContactInput!]!) 598: { roster { subscribeToAll(user: $user, contacts: $contacts) } }">>, 599: OpName = <<"M1">>, 600: Vars = #{user => make_contact(User), contacts => make_contact(Contacts)}, 601: #{query => Query, operationName => OpName, variables => Vars}. 602: 603: admin_subscribe_all_to_all_body(Users) -> 604: Query = <<"mutation M1($contacts: [ContactInput!]!) 605: { roster { subscribeAllToAll(contacts: $contacts) } }">>, 606: OpName = <<"M1">>, 607: Vars = #{contacts => make_contact(Users)}, 608: #{query => Query, operationName => OpName, variables => Vars}. 609: 610: admin_list_contacts_body(User) -> 611: Query = <<"query Q1($user: JID!) 612: { roster { listContacts(user: $user) 613: { jid subscription ask name groups} } }">>, 614: OpName = <<"Q1">>, 615: Vars = #{user => user_to_bin(User)}, 616: #{query => Query, operationName => OpName, variables => Vars}. 617: 618: admin_get_contact_body(User, Contact) -> 619: Query = <<"query Q1($user: JID!, $contact: JID!) 620: { roster { getContact(user: $user, contact: $contact) 621: { jid subscription ask name groups} } }">>, 622: OpName = <<"Q1">>, 623: Vars = #{user => user_to_bin(User), contact => user_to_bin(Contact)}, 624: #{query => Query, operationName => OpName, variables => Vars}. 625: 626: user_add_contact_body(Contact, Name, Groups) -> 627: Query = <<"mutation M1($contact: JID!, $name: String, $groups: [String!]) 628: { roster { addContact(contact: $contact, name: $name, groups: $groups) } }">>, 629: OpName = <<"M1">>, 630: Vars = #{contact => user_to_bin(Contact), name => Name, groups => Groups}, 631: #{query => Query, operationName => OpName, variables => Vars}. 632: 633: user_add_contacts_body(Contacts) -> 634: Query = <<"mutation M1($contacts: [ContactInput!]!) 635: { roster { addContacts(contacts: $contacts) } }">>, 636: OpName = <<"M1">>, 637: Vars = #{contacts => make_contact(Contacts)}, 638: #{query => Query, operationName => OpName, variables => Vars}. 639: 640: user_delete_contact_body(Contact) -> 641: Query = <<"mutation M1($contact: JID!) 642: { roster { deleteContact(contact: $contact) } }">>, 643: OpName = <<"M1">>, 644: Vars = #{contact => user_to_bin(Contact)}, 645: #{query => Query, operationName => OpName, variables => Vars}. 646: 647: user_delete_contacts_body(Contacts) -> 648: Query = <<"mutation M1($contacts: [JID!]!) 649: { roster { deleteContacts(contacts: $contacts) } }">>, 650: OpName = <<"M1">>, 651: Vars = #{contacts => [user_to_bin(C) || C <- Contacts]}, 652: #{query => Query, operationName => OpName, variables => Vars}. 653: 654: user_subscription_body(Contact, Action) -> 655: Query = <<"mutation M1($contact: JID!, $action: SubAction!) 656: { roster { subscription(contact: $contact, action: $action) } }">>, 657: OpName = <<"M1">>, 658: Vars = #{contact => user_to_bin(Contact), action => Action}, 659: #{query => Query, operationName => OpName, variables => Vars}. 660: 661: user_list_contacts_body() -> 662: Query = <<"query Q1 { roster { listContacts 663: { jid subscription ask name groups} } }">>, 664: #{query => Query, operationName => <<"Q1">>, variables => #{}}. 665: 666: user_get_contact_body(Contact) -> 667: Query = <<"query Q1($contact: JID!) 668: { roster { getContact(contact: $contact) 669: { jid subscription ask name groups} } }">>, 670: OpName = <<"Q1">>, 671: Vars = #{contact => user_to_bin(Contact)}, 672: #{query => Query, operationName => OpName, variables => Vars}.