1: -module(graphql_muc_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_ok_value/2, get_err_msg/1, 7: user_to_bin/1, user_to_full_bin/1]). 8: 9: -include_lib("common_test/include/ct.hrl"). 10: -include_lib("escalus/include/escalus_xmlns.hrl"). 11: -include_lib("eunit/include/eunit.hrl"). 12: -include_lib("exml/include/exml.hrl"). 13: 14: suite() -> 15: require_rpc_nodes([mim]) ++ escalus:suite(). 16: 17: all() -> 18: [{group, user_muc}, 19: {group, admin_muc}]. 20: 21: groups() -> 22: [{user_muc, [parallel], user_muc_handler()}, 23: {admin_muc, [parallel], admin_muc_handler()}]. 24: 25: user_muc_handler() -> 26: [user_create_and_delete_room, 27: user_try_delete_nonexistent_room, 28: user_try_delete_room_by_not_owner, 29: user_try_create_instant_room_with_nonexistent_domain, 30: user_list_rooms, 31: user_list_room_users, 32: user_list_room_users_without_anonymous_mode, 33: user_try_list_room_users_without_permission, 34: user_try_list_nonexistent_room_users, 35: user_change_room_config, 36: user_try_change_nonexistent_room_config, 37: user_get_room_config, 38: user_try_get_nonexistent_room_config, 39: user_invite_user, 40: user_kick_user, 41: user_send_message_to_room, 42: user_send_message_to_room_with_specified_res, 43: user_without_session_send_message_to_room, 44: user_get_room_messages, 45: user_try_get_nonexistent_room_messages, 46: user_try_get_room_messages_without_permission]. 47: 48: admin_muc_handler() -> 49: [admin_create_and_delete_room, 50: admin_try_create_instant_room_with_nonexistent_domain, 51: admin_try_create_instant_room_with_nonexistent_user, 52: admin_try_delete_nonexistent_room, 53: admin_try_delete_room_with_nonexistent_domain, 54: admin_list_rooms, 55: admin_list_room_users, 56: admin_try_list_users_from_nonexistent_room, 57: admin_change_room_config, 58: admin_try_change_nonexistent_room_config, 59: admin_get_room_config, 60: admin_try_get_nonexistent_room_config, 61: admin_invite_user, 62: admin_try_invite_user_to_nonexistent_room, 63: admin_kick_user, 64: admin_send_message_to_room, 65: admin_get_room_messages, 66: admin_try_get_nonexistent_room_messages]. 67: 68: init_per_suite(Config) -> 69: HostType = domain_helper:host_type(), 70: Config2 = escalus:init_per_suite(Config), 71: Config3 = dynamic_modules:save_modules(HostType, Config2), 72: Config4 = rest_helper:maybe_enable_mam(mam_helper:backend(), HostType, Config3), 73: dynamic_modules:restart(HostType, mod_disco, 74: config_parser_helper:default_mod_config(mod_disco)), 75: muc_helper:load_muc(), 76: mongoose_helper:ensure_muc_clean(), 77: Config4. 78: 79: end_per_suite(Config) -> 80: escalus_fresh:clean(), 81: mongoose_helper:ensure_muc_clean(), 82: muc_helper:unload_muc(), 83: dynamic_modules:restore_modules(Config), 84: escalus:end_per_suite(Config). 85: 86: init_per_group(admin_muc, Config) -> 87: graphql_helper:init_admin_handler(Config); 88: init_per_group(user_muc, Config) -> 89: [{schema_endpoint, user} | Config]. 90: 91: end_per_group(_GN, Config) -> 92: Config. 93: 94: init_per_testcase(TC, Config) -> 95: rest_helper:maybe_skip_mam_test_cases(TC, [user_get_room_messages, 96: admin_get_room_messages], Config). 97: 98: end_per_testcase(TC, Config) -> 99: escalus:end_per_testcase(TC, Config). 100: 101: -define(CREATE_INSTANT_ROOM_PATH, [data, muc, createInstantRoom]). 102: -define(LIST_ROOMS_PATH, [data, muc, listRooms]). 103: -define(INVITE_USER_PATH, [data, muc, inviteUser]). 104: -define(KICK_USER_PATH, [data, muc, kickUser]). 105: -define(DELETE_ROOM_PATH, [data, muc, deleteRoom]). 106: -define(SEND_MESSAGE_PATH, [data, muc, sendMessageToRoom]). 107: -define(GET_MESSAGES_PATH, [data, muc, getRoomMessages]). 108: -define(LIST_ROOM_USERS_PATH, [data, muc, listRoomUsers]). 109: -define(CHANGE_ROOM_CONFIG_PATH, [data, muc, changeRoomConfiguration]). 110: -define(GET_ROOM_CONFIG_PATH, [data, muc, getRoomConfig]). 111: 112: -define(NONEXISTENT_ROOM, <<"room@room">>). 113: -define(NONEXISTENT_ROOM2, <<"room@", (muc_helper:muc_host())/binary>>). 114: 115: admin_list_rooms(Config) -> 116: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun admin_list_rooms_story/3). 117: 118: admin_list_rooms_story(Config, Alice, Bob) -> 119: AliceJID = jid:from_binary(escalus_client:short_jid(Alice)), 120: BobJID = jid:from_binary(escalus_client:short_jid(Bob)), 121: AliceRoom = rand_name(), 122: BobRoom = rand_name(), 123: muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []), 124: muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, [{public_list, false}]), 125: Res = execute_auth(admin_list_rooms_body(muc_helper:muc_host(), Alice, null, null), Config), 126: #{<<"rooms">> := Rooms } = get_ok_value(?LIST_ROOMS_PATH, Res), 127: ?assert(contain_room(AliceRoom, Rooms)), 128: ?assert(contain_room(BobRoom, Rooms)). 129: 130: admin_create_and_delete_room(Config) -> 131: escalus:fresh_story_with_config(Config, [{alice, 1}], fun admin_create_and_delete_room_story/2). 132: 133: admin_create_and_delete_room_story(Config, Alice) -> 134: Name = <<"first-alice-room">>, 135: MUCServer = muc_helper:muc_host(), 136: RoomJID = jid:make_bare(Name, MUCServer), 137: % Create instant room 138: Res = execute_auth(admin_create_instant_room_body(MUCServer, Name, Alice, <<"Ali">>), Config), 139: ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0}, 140: get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)), 141: Res2 = execute_auth(admin_list_rooms_body(MUCServer, Alice, null, null), Config), 142: ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))), 143: % Delete room 144: Res3 = execute_auth(delete_room_body(RoomJID, null), Config), 145: ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3), 146: <<"successfully">>)), 147: Res4 = execute_auth(admin_list_rooms_body(MUCServer, Alice, null, null), Config), 148: ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))). 149: 150: admin_try_create_instant_room_with_nonexistent_domain(Config) -> 151: escalus:fresh_story_with_config(Config, [{alice, 1}], 152: fun admin_try_create_instant_room_with_nonexistent_domain_story/2). 153: 154: admin_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) -> 155: Res = execute_auth(admin_create_instant_room_body(<<"unknown">>, rand_name(), Alice, <<"Ali">>), 156: Config), 157: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 158: 159: admin_try_create_instant_room_with_nonexistent_user(Config) -> 160: Name = rand_name(), 161: MUCServer = muc_helper:muc_host(), 162: JID = <<(rand_name())/binary, "@localhost">>, 163: Res = execute_auth(admin_create_instant_room_body(MUCServer, Name, JID, <<"Ali">>), Config), 164: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 165: 166: admin_try_delete_nonexistent_room(Config) -> 167: RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()), 168: Res = execute_auth(delete_room_body(RoomJID, null), Config), 169: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)). 170: 171: admin_try_delete_room_with_nonexistent_domain(Config) -> 172: RoomJID = jid:make_bare(<<"unknown">>, <<"unknown">>), 173: Res = execute_auth(delete_room_body(RoomJID, null), Config), 174: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)). 175: 176: admin_invite_user(Config) -> 177: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_invite_user_story/3). 178: 179: admin_invite_user_story(Config, Alice, Bob) -> 180: RoomJIDBin = ?config(room_jid, Config), 181: RoomJID = jid:from_binary(RoomJIDBin), 182: Res = execute_auth(admin_invite_user_body(RoomJID, Alice, Bob, null), Config), 183: ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res), 184: <<"successfully">>)), 185: Stanza = escalus:wait_for_stanza(Bob), 186: escalus:assert(is_message, Stanza), 187: ?assertEqual(RoomJIDBin, 188: exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])). 189: 190: admin_try_invite_user_to_nonexistent_room(Config) -> 191: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], 192: fun admin_try_invite_user_to_nonexistent_room_story/3). 193: 194: admin_try_invite_user_to_nonexistent_room_story(Config, Alice, Bob) -> 195: Res = execute_auth(admin_invite_user_body(?NONEXISTENT_ROOM, Alice, Bob, null), Config), 196: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 197: 198: admin_kick_user(Config) -> 199: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun admin_kick_user_story/3). 200: 201: admin_kick_user_story(Config, Alice, Bob) -> 202: RoomJIDBin = ?config(room_jid, Config), 203: RoomJID = jid:from_binary(RoomJIDBin), 204: BobNick = <<"Bobek">>, 205: Reason = <<"You are too laud">>, 206: enter_room(RoomJID, Alice, <<"ali">>), 207: enter_room(RoomJID, Bob, BobNick), 208: Res = execute_auth(kick_user_body(RoomJID, BobNick, Reason), Config), 209: ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res), 210: <<"successfully">>)), 211: escalus:wait_for_stanzas(Bob, 2), 212: KickStanza = escalus:wait_for_stanza(Bob), 213: escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza), 214: ?assertEqual(Reason, 215: exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>}, 216: {element, <<"reason">>}, cdata])). 217: 218: admin_send_message_to_room(Config) -> 219: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 220: fun admin_send_message_to_room_story/3). 221: 222: admin_send_message_to_room_story(Config, _Alice, Bob) -> 223: RoomJID = jid:from_binary(?config(room_jid, Config)), 224: Message = <<"Hello All!">>, 225: BobNick = <<"Bobek">>, 226: enter_room(RoomJID, Bob, BobNick), 227: escalus:wait_for_stanza(Bob), 228: % Send message 229: Res = execute_auth(admin_send_message_to_room_body(RoomJID, Bob, Message), Config), 230: ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res), 231: <<"successfully">>)), 232: assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message, 233: escalus:wait_for_stanza(Bob)). 234: 235: admin_get_room_config(Config) -> 236: muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_get_room_config_story/2). 237: 238: admin_get_room_config_story(Config, _Alice) -> 239: RoomJID = jid:from_binary(?config(room_jid, Config)), 240: Res = execute_auth(get_room_config_body(RoomJID), Config), 241: assert_default_room_config(Res). 242: 243: admin_try_get_nonexistent_room_config(Config) -> 244: Res = execute_auth(get_room_config_body(?NONEXISTENT_ROOM), Config), 245: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 246: 247: admin_change_room_config(Config) -> 248: muc_helper:story_with_room(Config, [], [{alice, 1}], fun admin_change_room_config_story/2). 249: 250: admin_change_room_config_story(Config, _Alice) -> 251: RoomJID = jid:from_binary(?config(room_jid, Config)), 252: Title = <<"aloes">>, 253: Description = <<"The chat about aloes">>, 254: Public = false, 255: RoomConfig = #{title => Title, description => Description, public => Public}, 256: Res = execute_auth(change_room_config_body(RoomJID, RoomConfig), Config), 257: ?assertMatch(#{<<"title">> := Title, 258: <<"description">> := Description, 259: <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)). 260: 261: admin_try_change_nonexistent_room_config(Config) -> 262: RoomConfig = #{title => <<"NewTitle">>}, 263: Res = execute_auth(change_room_config_body(?NONEXISTENT_ROOM, RoomConfig), Config), 264: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 265: 266: admin_list_room_users(Config) -> 267: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 268: fun admin_list_room_users_story/3). 269: 270: admin_list_room_users_story(Config, Alice, Bob) -> 271: RoomJID = jid:from_binary(?config(room_jid, Config)), 272: BobNick = <<"Bobek">>, 273: AliceNick = <<"Ali">>, 274: enter_room(RoomJID, Bob, BobNick), 275: enter_room(RoomJID, Alice, AliceNick), 276: Res = execute_auth(list_room_users_body(RoomJID), Config), 277: ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>}, 278: {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}], 279: assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)). 280: 281: admin_try_list_users_from_nonexistent_room(Config) -> 282: Res = execute_auth(list_room_users_body(?NONEXISTENT_ROOM), Config), 283: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 284: 285: admin_get_room_messages(Config) -> 286: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 287: fun admin_get_room_messages_story/3). 288: 289: admin_get_room_messages_story(Config, Alice, Bob) -> 290: RoomJID = jid:from_binary(?config(room_jid, Config)), 291: enter_room(RoomJID, Bob, <<"Bobek">>), 292: enter_room(RoomJID, Alice, <<"Ali">>), 293: escalus:wait_for_stanzas(Bob, 2), 294: execute_auth(admin_send_message_to_room_body(RoomJID, Bob, <<"Hi!">>), Config), 295: escalus:wait_for_stanzas(Bob, 1), 296: mam_helper:maybe_wait_for_archive(Config), 297: Res = execute_auth(get_room_messages_body(RoomJID, 50, null), Config), 298: #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} = 299: get_ok_value(?GET_MESSAGES_PATH, Res), 300: ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)). 301: 302: admin_try_get_nonexistent_room_messages(Config) -> 303: Res = execute_auth(get_room_messages_body(?NONEXISTENT_ROOM, null, null), Config), 304: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 305: 306: %% User test cases 307: 308: user_list_rooms(Config) -> 309: escalus:fresh_story_with_config(Config, [{alice, 1}, {bob, 1}], fun user_list_rooms_story/3). 310: 311: user_list_rooms_story(Config, Alice, Bob) -> 312: AliceJID = jid:from_binary(escalus_client:short_jid(Alice)), 313: BobJID = jid:from_binary(escalus_client:short_jid(Bob)), 314: AliceRoom = rand_name(), 315: BobRoom = rand_name(), 316: muc_helper:create_instant_room(AliceRoom, AliceJID, <<"Ali">>, []), 317: muc_helper:create_instant_room(BobRoom, BobJID, <<"Bob">>, []), 318: 319: Res = execute_user(user_list_rooms_body(muc_helper:muc_host(), null, null), Alice, Config), 320: #{<<"rooms">> := Rooms } = get_ok_value(?LIST_ROOMS_PATH, Res), 321: ?assert(contain_room(AliceRoom, Rooms)), 322: ?assert(contain_room(BobRoom, Rooms)). 323: 324: user_create_and_delete_room(Config) -> 325: escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_create_and_delete_room_story/2). 326: 327: user_create_and_delete_room_story(Config, Alice) -> 328: Name = rand_name(), 329: MUCServer = muc_helper:muc_host(), 330: RoomJID = jid:make_bare(Name, MUCServer), 331: % Create instant room 332: Res = execute_user(user_create_instant_room_body(MUCServer, Name, <<"Ali">>), Alice, Config), 333: ?assertMatch(#{<<"title">> := Name, <<"private">> := false, <<"usersNumber">> := 0}, 334: get_ok_value(?CREATE_INSTANT_ROOM_PATH, Res)), 335: Res2 = execute_user(user_list_rooms_body(MUCServer, null, null), Alice, Config), 336: ?assert(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res2))), 337: % Delete room 338: Res3 = execute_user(delete_room_body(RoomJID, null), Alice, Config), 339: ?assertNotEqual(nomatch, binary:match(get_ok_value(?DELETE_ROOM_PATH, Res3), 340: <<"successfully">>)), 341: Res4 = execute_user(user_list_rooms_body(MUCServer, null, null), Alice, Config), 342: ?assertNot(contain_room(Name, get_ok_value(?LIST_ROOMS_PATH, Res4))). 343: 344: user_try_create_instant_room_with_nonexistent_domain(Config) -> 345: escalus:fresh_story_with_config(Config, [{alice, 1}], 346: fun user_try_create_instant_room_with_nonexistent_domain_story/2). 347: 348: user_try_create_instant_room_with_nonexistent_domain_story(Config, Alice) -> 349: Res = execute_user(user_create_instant_room_body(<<"unknown">>, rand_name(), <<"Ali">>), 350: Alice, Config), 351: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 352: 353: user_try_delete_nonexistent_room(Config) -> 354: escalus:fresh_story_with_config(Config, [{alice, 1}], 355: fun user_try_delete_nonexistent_room_story/2). 356: 357: user_try_delete_nonexistent_room_story(Config, Alice) -> 358: RoomJID = jid:make_bare(<<"unknown">>, muc_helper:muc_host()), 359: Res = execute_user(delete_room_body(RoomJID, null), Alice, Config), 360: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"non-existent">>)). 361: 362: user_try_delete_room_by_not_owner(Config) -> 363: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 364: fun user_try_delete_room_by_not_owner_story/3). 365: 366: user_try_delete_room_by_not_owner_story(Config, _Alice, Bob) -> 367: RoomJID = jid:from_binary(?config(room_jid, Config)), 368: Res = execute_user(delete_room_body(RoomJID, null), Bob, Config), 369: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)). 370: 371: user_invite_user(Config) -> 372: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_invite_user_story/3). 373: 374: user_invite_user_story(Config, Alice, Bob) -> 375: RoomJIDBin = ?config(room_jid, Config), 376: RoomJID = jid:from_binary(RoomJIDBin), 377: Res = execute_user(user_invite_user_body(RoomJID, Bob, null), Alice, Config), 378: ?assertNotEqual(nomatch, binary:match(get_ok_value(?INVITE_USER_PATH, Res), 379: <<"successfully">>)), 380: Stanza = escalus:wait_for_stanza(Bob), 381: escalus:assert(is_message, Stanza), 382: ?assertEqual(RoomJIDBin, 383: exml_query:path(Stanza, [{element, <<"x">>}, {attr, <<"jid">>}])). 384: 385: user_kick_user(Config) -> 386: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], fun user_kick_user_story/3). 387: 388: user_kick_user_story(Config, Alice, Bob) -> 389: RoomJIDBin = ?config(room_jid, Config), 390: RoomJID = jid:from_binary(RoomJIDBin), 391: BobNick = <<"Bobek">>, 392: Reason = <<"You are too loud">>, 393: enter_room(RoomJID, Alice, <<"ali">>), 394: enter_room(RoomJID, Bob, BobNick), 395: Res = execute_user(kick_user_body(RoomJID, BobNick, Reason), Alice, Config), 396: ?assertNotEqual(nomatch, binary:match(get_ok_value(?KICK_USER_PATH, Res), 397: <<"successfully">>)), 398: escalus:wait_for_stanzas(Bob, 2), 399: KickStanza = escalus:wait_for_stanza(Bob), 400: escalus:assert(is_presence_with_type, [<<"unavailable">>], KickStanza), 401: ?assertEqual(Reason, 402: exml_query:path(KickStanza, [{element, <<"x">>}, {element, <<"item">>}, 403: {element, <<"reason">>}, cdata])). 404: 405: user_send_message_to_room(Config) -> 406: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 407: fun user_send_message_to_room_story/3). 408: 409: user_send_message_to_room_story(Config, _Alice, Bob) -> 410: RoomJID = jid:from_binary(?config(room_jid, Config)), 411: Message = <<"Hello All!">>, 412: BobNick = <<"Bobek">>, 413: enter_room(RoomJID, Bob, BobNick), 414: escalus:wait_for_stanza(Bob), 415: % Send message 416: Res = execute_user(user_send_message_to_room_body(RoomJID, Message, null), Bob, Config), 417: ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res), 418: <<"successfully">>)), 419: assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message, 420: escalus:wait_for_stanza(Bob)). 421: 422: user_send_message_to_room_with_specified_res(Config) -> 423: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 2}], 424: fun user_send_message_to_room_with_specified_res_story/4). 425: 426: user_send_message_to_room_with_specified_res_story(Config, _Alice, Bob, Bob2) -> 427: RoomJID = jid:from_binary(?config(room_jid, Config)), 428: Message = <<"Hello All!">>, 429: BobNick = <<"Bobek">>, 430: enter_room(RoomJID, Bob2, BobNick), 431: escalus:wait_for_stanza(Bob2), 432: % Send message 433: Res = execute_user(user_send_message_to_room_body(RoomJID, Message, <<"res2">>), Bob, Config), 434: ?assertNotEqual(nomatch, binary:match(get_ok_value(?SEND_MESSAGE_PATH, Res), 435: <<"successfully">>)), 436: assert_is_message_correct(RoomJID, BobNick, <<"groupchat">>, Message, 437: escalus:wait_for_stanza(Bob2)). 438: 439: user_without_session_send_message_to_room(Config) -> 440: muc_helper:story_with_room(Config, [], [{alice, 1}], 441: fun user_without_session_send_message_to_room_story/2). 442: 443: user_without_session_send_message_to_room_story(Config, Alice) -> 444: RoomJID = jid:from_binary(?config(room_jid, Config)), 445: JID = jid:from_binary(escalus_client:full_jid(Alice)), 446: {exit, _} = rpc(mim(), ejabberd_c2s, terminate_session, [JID, <<"Kicked">>]), 447: % Send message 448: Res = execute_user(user_send_message_to_room_body(RoomJID, <<"Hello!">>, null), Alice, Config), 449: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have any session">>)). 450: 451: user_get_room_config(Config) -> 452: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 453: fun user_get_room_config_story/3). 454: 455: user_get_room_config_story(Config, Alice, Bob) -> 456: RoomJID = jid:from_binary(?config(room_jid, Config)), 457: Res = execute_user(get_room_config_body(RoomJID), Alice, Config), 458: assert_default_room_config(Res), 459: % Not an owner tries to get room config 460: Res2 = execute_user(get_room_config_body(RoomJID), Bob, Config), 461: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)). 462: 463: user_try_get_nonexistent_room_config(Config) -> 464: escalus:fresh_story_with_config(Config, [{alice, 1}], 465: fun user_try_get_nonexistent_room_config_story/2). 466: 467: user_try_get_nonexistent_room_config_story(Config, Alice) -> 468: Res = execute_user(get_room_config_body(?NONEXISTENT_ROOM), Alice, Config), 469: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 470: 471: user_change_room_config(Config) -> 472: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 473: fun user_change_room_config_story/3). 474: 475: user_change_room_config_story(Config, Alice, Bob) -> 476: RoomJID = jid:from_binary(?config(room_jid, Config)), 477: Title = <<"aloes">>, 478: Description = <<"The chat about aloes">>, 479: Public = false, 480: RoomConfig = #{title => Title, description => Description, public => Public}, 481: Res = execute_user(change_room_config_body(RoomJID, RoomConfig), Alice, Config), 482: ?assertMatch(#{<<"title">> := Title, 483: <<"description">> := Description, 484: <<"public">> := Public}, get_ok_value(?CHANGE_ROOM_CONFIG_PATH, Res)), 485: % Not an owner tries to change the room config 486: Res2 = execute_user(change_room_config_body(RoomJID, RoomConfig), Bob, Config), 487: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"does not have permission">>)). 488: 489: user_try_change_nonexistent_room_config(Config) -> 490: escalus:fresh_story_with_config(Config, [{alice, 1}], 491: fun user_try_change_nonexistent_room_config_story/2). 492: 493: user_try_change_nonexistent_room_config_story(Config, Alice) -> 494: RoomConfig = #{title => <<"NewTitle">>}, 495: Res = execute_user(change_room_config_body(?NONEXISTENT_ROOM, RoomConfig), Alice, Config), 496: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 497: 498: user_list_room_users(Config) -> 499: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 500: fun user_list_room_users_story/3). 501: 502: user_list_room_users_story(Config, Alice, Bob) -> 503: RoomJID = jid:from_binary(?config(room_jid, Config)), 504: BobNick = <<"Bobek">>, 505: AliceNick = <<"Ali">>, 506: enter_room(RoomJID, Bob, BobNick), 507: enter_room(RoomJID, Alice, AliceNick), 508: Res = execute_user(list_room_users_body(RoomJID), Alice, Config), 509: ExpectedUsers = [{null, BobNick, <<"PARTICIPANT">>}, 510: {null, AliceNick, <<"MODERATOR">>}], 511: assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)). 512: 513: user_list_room_users_without_anonymous_mode(Config) -> 514: muc_helper:story_with_room(Config, [{anonymous, false}], [{alice, 1}, {bob, 1}], 515: fun user_list_room_users_without_anonymous_mode_story/3). 516: 517: user_list_room_users_without_anonymous_mode_story(Config, Alice, Bob) -> 518: RoomJID = jid:from_binary(?config(room_jid, Config)), 519: BobNick = <<"Bobek">>, 520: AliceNick = <<"Ali">>, 521: enter_room(RoomJID, Bob, BobNick), 522: enter_room(RoomJID, Alice, AliceNick), 523: Res = execute_user(list_room_users_body(RoomJID), Alice, Config), 524: ExpectedUsers = [{escalus_client:full_jid(Bob), BobNick, <<"PARTICIPANT">>}, 525: {escalus_client:full_jid(Alice), AliceNick, <<"MODERATOR">>}], 526: assert_room_users(ExpectedUsers, get_ok_value(?LIST_ROOM_USERS_PATH, Res)). 527: 528: user_try_list_nonexistent_room_users(Config) -> 529: escalus:fresh_story_with_config(Config, [{alice, 1}], 530: fun user_try_list_nonexistent_room_users_story/2). 531: 532: user_try_list_nonexistent_room_users_story(Config, Alice) -> 533: Res = execute_user(list_room_users_body(?NONEXISTENT_ROOM), Alice, Config), 534: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)). 535: 536: user_try_list_room_users_without_permission(Config) -> 537: muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}], 538: fun user_try_list_room_users_without_permission_story/3). 539: 540: user_try_list_room_users_without_permission_story(Config, _Alice, Bob) -> 541: RoomJID = jid:from_binary(?config(room_jid, Config)), 542: Res = execute_user(list_room_users_body(RoomJID), Bob, Config), 543: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)). 544: 545: user_get_room_messages(Config) -> 546: muc_helper:story_with_room(Config, [], [{alice, 1}, {bob, 1}], 547: fun user_get_room_messages_story/3). 548: 549: user_get_room_messages_story(Config, Alice, Bob) -> 550: RoomJID = jid:from_binary(?config(room_jid, Config)), 551: enter_room(RoomJID, Bob, <<"Bobek">>), 552: enter_room(RoomJID, Alice, <<"Ali">>), 553: escalus:wait_for_stanzas(Bob, 2), 554: execute_user(user_send_message_to_room_body(RoomJID, <<"Hi!">>, null), Bob, Config), 555: escalus:wait_for_stanzas(Bob, 1), 556: mam_helper:maybe_wait_for_archive(Config), 557: Res = execute_user(get_room_messages_body(RoomJID, 50, null), Alice, Config), 558: #{<<"stanzas">> := [#{<<"stanza">> := StanzaXML}], <<"limit">> := 50} = 559: get_ok_value(?GET_MESSAGES_PATH, Res), 560: ?assertMatch({ok, #xmlel{name = <<"message">>}}, exml:parse(StanzaXML)). 561: 562: user_try_get_nonexistent_room_messages(Config) -> 563: escalus:fresh_story_with_config(Config, [{alice, 1}], 564: fun user_try_get_nonexistent_room_messages_story/2). 565: 566: user_try_get_nonexistent_room_messages_story(Config, Alice) -> 567: % Non-existent room with non-existent domain 568: Res = execute_user(get_room_messages_body(?NONEXISTENT_ROOM, null, null), Alice, Config), 569: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"not found">>)), 570: % Non-existent room with existent domain 571: Res2 = execute_user(get_room_messages_body(?NONEXISTENT_ROOM2, null, null), Alice, Config), 572: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res2), <<"not found">>)). 573: 574: user_try_get_room_messages_without_permission(Config) -> 575: muc_helper:story_with_room(Config, [{members_only, true}], [{alice, 1}, {bob, 1}], 576: fun user_try_get_room_messages_without_permission/3). 577: 578: user_try_get_room_messages_without_permission(Config, _Alice, Bob) -> 579: RoomJID = jid:from_binary(?config(room_jid, Config)), 580: Res = execute_user(get_room_messages_body(RoomJID, null, null), Bob, Config), 581: ?assertNotEqual(nomatch, binary:match(get_err_msg(Res), <<"does not have permission">>)). 582: 583: %% Helpers 584: 585: rand_name() -> 586: rpc(mim(), mongoose_bin, gen_from_crypto, []). 587: 588: -spec assert_room_users([{jid:jid(), binary(), binary()}], [map()]) -> ok. 589: assert_room_users(Expected, Actual) -> 590: ActualTuples = [{JID, Nick, Role} || #{<<"jid">> := JID, <<"role">> := Role, <<"nick">> := Nick} <- Actual], 591: ?assertEqual(lists:sort(Expected), lists:sort(ActualTuples)). 592: 593: assert_is_message_correct(RoomJID, SenderNick, Type, Text, ReceivedMessage) -> 594: escalus_pred:is_message(ReceivedMessage), 595: From = jid:to_binary(jid:replace_resource(RoomJID, SenderNick)), 596: From = exml_query:attr(ReceivedMessage, <<"from">>), 597: Type = exml_query:attr(ReceivedMessage, <<"type">>), 598: Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content=Text}]}, 599: Body = exml_query:subelement(ReceivedMessage, <<"body">>). 600: 601: enter_room(RoomJID, User, Nick) -> 602: JID = jid:to_binary(jid:replace_resource(RoomJID, Nick)), 603: Pres = escalus_stanza:to(escalus_stanza:presence(<<"available">>, []), JID), 604: escalus:send(User, Pres), 605: escalus:wait_for_stanza(User). 606: 607: contain_room(Name, #{<<"rooms">> := Rooms}) -> 608: contain_room(Name, Rooms); 609: contain_room(Name, Rooms) when is_list(Rooms) -> 610: lists:any(fun(#{<<"title">> := T}) -> T =:= Name end, Rooms). 611: 612: assert_default_room_config(Response) -> 613: ?assertMatch(#{<<"title">> := <<>>, 614: <<"description">> := <<>>, 615: <<"allowChangeSubject">> := true, 616: <<"allowQueryUsers">> := true, 617: <<"allowPrivateMessages">> := true, 618: <<"allowVisitorStatus">> := true, 619: <<"allowVisitorNickchange">> := true, 620: <<"public">> := true, 621: <<"publicList">> := true, 622: <<"persistent">> := false, 623: <<"moderated">> := true, 624: <<"membersByDefault">> := true, 625: <<"membersOnly">> := false, 626: <<"allowUserInvites">> := false, 627: <<"allowMultipleSession">> := false, 628: <<"passwordProtected">> := false, 629: <<"password">> := <<>>, 630: <<"anonymous">> := true, 631: <<"mayGetMemberList">> := [], 632: <<"maxUsers">> := 200, 633: <<"logging">> := false}, get_ok_value(?GET_ROOM_CONFIG_PATH, Response)). 634: 635: %% Request bodies 636: 637: admin_create_instant_room_body(MUCDomain, Name, Owner, Nick) -> 638: Query = <<"mutation M1($mucDomain: String!, $name: String!, $owner: JID!, $nick: String!) 639: { muc { createInstantRoom(mucDomain: $mucDomain, name: $name, owner: $owner, nick: $nick) 640: { jid title private usersNumber } } }">>, 641: OpName = <<"M1">>, 642: Vars = #{mucDomain => MUCDomain, name => Name, owner => user_to_bin(Owner), nick => Nick}, 643: #{query => Query, operationName => OpName, variables => Vars}. 644: 645: admin_invite_user_body(Room, Sender, Recipient, Reason) -> 646: Query = <<"mutation M1($room: JID!, $sender: JID!, $recipient: JID!, $reason: String) 647: { muc { inviteUser(room: $room, sender: $sender, recipient: $recipient, reason: $reason) } }">>, 648: OpName = <<"M1">>, 649: Vars = #{room => jid:to_binary(Room), sender => user_to_bin(Sender), 650: recipient => user_to_bin(Recipient), reason => Reason}, 651: #{query => Query, operationName => OpName, variables => Vars}. 652: 653: kick_user_body(Room, Nick, Reason) -> 654: Query = <<"mutation M1($room: JID!, $nick: String!, $reason: String) 655: { muc { kickUser(room: $room, nick: $nick, reason: $reason) } }">>, 656: OpName = <<"M1">>, 657: Vars = #{room => jid:to_binary(Room), nick => Nick, reason => Reason}, 658: #{query => Query, operationName => OpName, variables => Vars}. 659: 660: admin_send_message_to_room_body(Room, From, Body) -> 661: Query = <<"mutation M1($room: JID!, $from: JID!, $body: String!) 662: { muc { sendMessageToRoom(room: $room, from: $from, body: $body) } }">>, 663: OpName = <<"M1">>, 664: Vars = #{room => jid:to_binary(Room), from => user_to_full_bin(From), body => Body}, 665: #{query => Query, operationName => OpName, variables => Vars}. 666: 667: delete_room_body(Room, Reason) -> 668: Query = <<"mutation M1($room: JID!, $reason: String) 669: { muc { deleteRoom(room: $room, reason: $reason) } }">>, 670: OpName = <<"M1">>, 671: Vars = #{room => jid:to_binary(Room), reason => Reason}, 672: #{query => Query, operationName => OpName, variables => Vars}. 673: 674: change_room_config_body(Room, Config) -> 675: Query = <<"mutation M1($room: JID!, $config: MUCRoomConfigInput!) 676: { muc { changeRoomConfiguration(room: $room, config: $config) 677: { title description allowChangeSubject allowQueryUsers allowPrivateMessages 678: allowVisitorStatus allowVisitorNickchange public publicList persistent 679: moderated membersByDefault membersOnly allowUserInvites allowMultipleSession 680: passwordProtected password anonymous mayGetMemberList maxUsers logging } } }">>, 681: OpName = <<"M1">>, 682: Vars = #{room => jid:to_binary(Room), config => Config}, 683: #{query => Query, operationName => OpName, variables => Vars}. 684: 685: admin_list_rooms_body(MUCDomain, From, Limit, Index) -> 686: Query = <<"query Q1($mucDomain: String!, $from: JID, $limit: Int, $index: Int) 687: { muc { listRooms(mucDomain: $mucDomain, from: $from, limit: $limit, index: $index) 688: { rooms { jid title private usersNumber } count index first last} } }">>, 689: OpName = <<"Q1">>, 690: Vars = #{mucDomain => MUCDomain, from => user_to_bin(From), limit => Limit, index => Index}, 691: #{query => Query, operationName => OpName, variables => Vars}. 692: 693: get_room_config_body(Room) -> 694: Query = <<"query Q1($room: JID!) 695: { muc { getRoomConfig(room: $room) 696: { title description allowChangeSubject allowQueryUsers allowPrivateMessages 697: allowVisitorStatus allowVisitorNickchange public publicList persistent 698: moderated membersByDefault membersOnly allowUserInvites allowMultipleSession 699: passwordProtected password anonymous mayGetMemberList maxUsers logging } } }">>, 700: OpName = <<"Q1">>, 701: Vars = #{room => jid:to_binary(Room)}, 702: #{query => Query, operationName => OpName, variables => Vars}. 703: 704: list_room_users_body(RoomJID) -> 705: Query = <<"query Q1($room: JID!) 706: { muc { listRoomUsers(room: $room) 707: { jid nick role } } }">>, 708: OpName = <<"Q1">>, 709: Vars = #{room => jid:to_binary(RoomJID)}, 710: #{query => Query, operationName => OpName, variables => Vars}. 711: 712: get_room_messages_body(RoomJID, PageSize, Before) -> 713: Query = <<"query Q1($room: JID!, $pageSize: Int, $before: DateTime) 714: { muc { getRoomMessages(room: $room, pageSize: $pageSize, before: $before) 715: { stanzas { stanza } limit } } }">>, 716: OpName = <<"Q1">>, 717: Vars = #{<<"room">> => jid:to_binary(RoomJID), <<"pageSize">> => PageSize, 718: <<"before">> => Before}, 719: #{query => Query, operationName => OpName, variables => Vars}. 720: 721: user_list_rooms_body(MUCDomain, Limit, Index) -> 722: Query = <<"query Q1($mucDomain: String!, $limit: Int, $index: Int) 723: { muc { listRooms(mucDomain: $mucDomain, limit: $limit, index: $index) 724: { rooms { jid title private usersNumber } count index first last} } }">>, 725: OpName = <<"Q1">>, 726: Vars = #{mucDomain => MUCDomain, limit => Limit, index => Index}, 727: #{query => Query, operationName => OpName, variables => Vars}. 728: 729: user_send_message_to_room_body(Room, Body, Resource) -> 730: Query = <<"mutation M1($room: JID!, $body: String!, $resource: String) 731: { muc { sendMessageToRoom(room: $room, body: $body, resource: $resource) } }">>, 732: OpName = <<"M1">>, 733: Vars = #{room => jid:to_binary(Room), body => Body, resource => Resource}, 734: #{query => Query, operationName => OpName, variables => Vars}. 735: 736: user_create_instant_room_body(MUCDomain, Name, Nick) -> 737: Query = <<"mutation M1($mucDomain: String!, $name: String!, $nick: String!) 738: { muc { createInstantRoom(mucDomain: $mucDomain, name: $name, nick: $nick) 739: { jid title private usersNumber } } }">>, 740: OpName = <<"M1">>, 741: Vars = #{mucDomain => MUCDomain, name => Name, nick => Nick}, 742: #{query => Query, operationName => OpName, variables => Vars}. 743: 744: user_invite_user_body(Room, Recipient, Reason) -> 745: Query = <<"mutation M1($room: JID!, $recipient: JID!, $reason: String) 746: { muc { inviteUser(room: $room, recipient: $recipient, reason: $reason) } }">>, 747: OpName = <<"M1">>, 748: Vars = #{room => jid:to_binary(Room), recipient => user_to_bin(Recipient), reason => Reason}, 749: #{query => Query, operationName => OpName, variables => Vars}.