1: %%============================================================================== 2: %% Copyright 2012 Erlang Solutions Ltd. 3: %% 4: %% Licensed under the Apache License, Version 2.0 (the "License"); 5: %% you may not use this file except in compliance with the License. 6: %% You may obtain a copy of the License at 7: %% 8: %% http://www.apache.org/licenses/LICENSE-2.0 9: %% 10: %% Unless required by applicable law or agreed to in writing, software 11: %% distributed under the License is distributed on an "AS IS" BASIS, 12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13: %% See the License for the specific language governing permissions and 14: %% limitations under the License. 15: %%============================================================================== 16: 17: -module(muc_SUITE). 18: -compile([export_all, nowarn_export_all]). 19: 20: -include_lib("escalus/include/escalus_xmlns.hrl"). 21: -include_lib("common_test/include/ct.hrl"). 22: -include_lib("eunit/include/eunit.hrl"). 23: -include_lib("exml/include/exml.hrl"). 24: -include("assert_received_match.hrl"). 25: 26: -import(distributed_helper, [mim/0, 27: subhost_pattern/1, 28: rpc/4]). 29: 30: -import(muc_helper, 31: [muc_host/0, 32: start_room/5, 33: generate_rpc_jid/1, 34: destroy_room/1, 35: destroy_room/2, 36: stanza_muc_enter_room/2, 37: stanza_to_room/2, 38: stanza_to_room/3, 39: room_address/1, 40: room_address/2, 41: fresh_room_name/0, 42: fresh_room_name/1, 43: disco_features_story/2, 44: has_features/2, 45: disco_service_story/1, 46: story_with_room/4, 47: change_nick_form_iq/1, 48: set_nick/2 49: ]). 50: 51: -import(domain_helper, [host_type/0, domain/0]). 52: -import(mongoose_helper, [backup_and_set_config_option/3, restore_config_option/2]). 53: -import(config_parser_helper, [config/2, default_mod_config/1]). 54: 55: -define(PASSWORD, <<"pa5sw0rd">>). 56: -define(SUBJECT, <<"subject">>). 57: -define(WAIT_TIME, 1500). 58: -define(WAIT_TIMEOUT, 10000). 59: 60: -define(FAKEPID, fakepid). 61: 62: -define(NS_MUC_REQUEST, <<"http://jabber.org/protocol/muc#request">>). 63: -define(NS_MUC_ROOMCONFIG, <<"http://jabber.org/protocol/muc#roomconfig">>). 64: -define(NS_MUC_STABLE_ID, <<"http://jabber.org/protocol/muc#stable_id">>). 65: 66: 67: -define(assert_equal(E, V), ( 68: [ct:fail("assert_equal( ~p, ~p) failed~n\tExpected ~p~n\tValue ~p~n", 69: [??E, ??V, (E), (V)]) 70: || (E) =/= (V)] 71: )). 72: 73: -record(rsm_in, { 74: max :: non_neg_integer() | undefined, 75: direction :: before | 'after' | undefined, 76: id :: binary() | undefined, 77: index ::non_neg_integer() | undefined 78: }). 79: 80: -record(rsm_out, { 81: index :: non_neg_integer() | undefined, 82: count :: non_neg_integer(), 83: first :: binary() | undefined, 84: last :: binary() | undefined, 85: items :: [#xmlel{}] 86: }). 87: 88: %%-------------------------------------------------------------------- 89: %% Suite configuration 90: %%-------------------------------------------------------------------- 91: 92: all() -> [ 93: {group, disco}, 94: {group, disco_with_mam}, 95: {group, disco_rsm}, 96: {group, disco_rsm_with_offline}, 97: {group, moderator}, 98: {group, admin}, 99: {group, admin_membersonly}, 100: {group, occupant}, 101: {group, owner}, 102: {group, owner_no_parallel}, 103: {group, room_management}, 104: {group, http_auth_no_server}, 105: {group, http_auth}, 106: {group, hibernation}, 107: {group, room_registration_race_condition}, 108: {group, register}, 109: {group, register_over_s2s}, 110: {group, service} 111: ]. 112: 113: groups() -> 114: [ 115: {hibernation, [parallel], [room_is_hibernated, 116: room_with_participants_is_hibernated, 117: hibernation_metrics_are_updated, 118: room_with_participants_and_messages_is_hibernated, 119: hibernated_room_can_be_queried_for_archive, 120: hibernated_room_is_stopped, 121: hibernated_room_is_stopped_and_restored_by_presence, 122: stopped_rooms_history_is_available, 123: stopped_members_only_room_process_invitations_correctly, 124: room_with_participants_is_not_stopped, 125: room_with_only_owner_is_stopped, 126: deep_hibernation_metrics_are_updated, 127: can_found_in_db_when_stopped 128: ]}, 129: {disco, [parallel], [ 130: disco_service, 131: disco_features, 132: disco_rooms, 133: disco_info, 134: disco_items, 135: disco_items_nonpublic 136: ]}, 137: {disco_with_mam, [parallel], [ 138: disco_features_with_mam, 139: disco_info_with_mam 140: ]}, 141: {disco_rsm, [parallel], rsm_cases()}, 142: {disco_rsm_with_offline, [parallel], rsm_cases_with_offline()}, 143: {moderator, [parallel], [ 144: moderator_subject, 145: moderator_subject_unauthorized, 146: moderator_kick, 147: moderator_kick_with_reason, 148: moderator_kick_unauthorized, 149: moderator_voice, 150: moderator_voice_with_reason, 151: moderator_voice_unauthorized, 152: moderator_voice_list, 153: moderator_voice_approval, 154: moderator_voice_approval_errors, 155: moderator_voice_forbidden, 156: moderator_voice_not_occupant, 157: moderator_voice_nonick 158: ]}, 159: {admin, [parallel], [ 160: admin_ban, 161: admin_ban_with_reason, 162: admin_ban_list, 163: admin_get_form, 164: admin_invalid_affiliation, 165: admin_invalid_jid, 166: %% test should fail, temporarily changed 167: admin_ban_higher_user, 168: admin_membership, 169: admin_membership_with_reason, 170: admin_member_list, 171: admin_member_list_allowed, 172: admin_moderator, 173: admin_moderator_with_reason, 174: admin_moderator_revoke_owner, 175: admin_moderator_list, 176: admin_invalid_role, 177: admin_invalid_nick 178: ]}, 179: {admin_membersonly, [], [ 180: admin_mo_revoke, 181: admin_mo_invite, 182: admin_mo_invite_with_reason, 183: admin_mo_invite_mere 184: ]}, 185: {occupant, [parallel], [ 186: %nick registration in a room is not implemented and will not be tested 187: groupchat_user_enter, 188: groupchat_user_enter_twice, 189: groupchat_user_enter_no_nickname, 190: groupchat_user_enter_old_protocol, 191: muc_user_enter, 192: enter_non_anonymous_room, 193: deny_access_to_password_protected_room, 194: enter_password_protected_room, 195: deny_accesss_to_memebers_only_room, 196: deny_entry_to_a_banned_user, 197: deny_entry_nick_conflict, 198: multi_sessions_enter, 199: multi_sessions_messages, 200: multi_sessions_exit_session, 201: multi_sessions_exit, 202: deny_entry_with_multiple_sessions_disallowed, 203: enter_room_with_logging, 204: deny_entry_user_limit_reached, 205: send_history, 206: history_since, 207: 208: %% the following tests fail and have been commented because 209: %% certain features are not implemented in ejabberd 210: %% send_non_anonymous_history, 211: %% limit_history_chars, 212: %% limit_history_messages, 213: %% recent_history, %unfinished, 214: %% no_history, 215: 216: subject, 217: no_subject, 218: send_to_all, 219: send_and_receive_private_message_client_with_x_elem, 220: send_and_receive_private_message_client_without_x_elem, 221: send_private_groupchat, 222: change_nickname, 223: deny_nickname_change_conflict, 224: change_availability_status, 225: direct_invite, 226: mediated_invite, 227: one2one_chat_to_muc, 228: exit_room, 229: exit_room_with_status, 230: kicked_after_sending_malformed_presence 231: ]}, 232: {owner, [parallel], [ 233: %% fails, see testcase 234: cant_enter_locked_room, 235: create_instant_room, 236: destroy_locked_room, 237: disco_info_locked_room, 238: create_reserved_room, 239: %% fails, see testcase 240: reserved_room_cancel, 241: reserved_room_unacceptable, 242: reserved_room_configuration, 243: owner_grant_revoke, 244: owner_grant_revoke_with_reason, 245: owner_list, 246: owner_unauthorized, 247: admin_grant_revoke, 248: admin_grant_revoke_with_reason, 249: admin_list, 250: admin_unauthorized, 251: destroy, 252: destroy_unauthorized, 253: config_denial, 254: config_cancel, 255: configure, 256: configure_errors, 257: configure_logging, 258: %% fails, see testcase 259: configure_anonymous, 260: cancel_iq_sent_to_locked_room_destroys_it, 261: cancel_iq_sent_to_unlocked_room_has_no_effect 262: ]}, 263: {owner_no_parallel, [], [ 264: room_creation_not_allowed, 265: create_instant_persistent_room 266: ]}, 267: {room_management, [], [ 268: create_and_destroy_room, 269: create_and_destroy_room_multiple_x_elements 270: ]}, 271: {http_auth_no_server, [parallel], [ 272: deny_access_to_http_password_protected_room_service_unavailable, 273: deny_creation_of_http_password_protected_room_service_unavailable 274: ]}, 275: {http_auth, [parallel], [ 276: enter_http_password_protected_room, 277: deny_access_to_password_protected_room, 278: deny_access_to_http_password_protected_room_wrong_password, 279: create_instant_http_password_protected_room, 280: deny_creation_of_http_password_protected_room, 281: deny_creation_of_http_password_protected_room_wrong_password 282: ]}, 283: {room_registration_race_condition, [], [ 284: create_already_registered_room, 285: check_presence_route_to_offline_room, 286: check_message_route_to_offline_room 287: ]}, 288: {register, [parallel], register_cases()}, 289: {register_over_s2s, [parallel], register_cases()}, 290: {service, [], [service_shutdown_kick]} 291: ]. 292: 293: register_cases() -> 294: [user_asks_for_registration_form, 295: user_submits_registration_form, 296: user_submits_registration_form_twice, 297: user_changes_nick, 298: user_unregisters_nick, 299: user_unregisters_nick_twice, 300: user_cancels_registration, 301: user_registration_errors]. 302: 303: rsm_cases() -> 304: [pagination_first5, 305: pagination_last5, 306: pagination_before10, 307: pagination_after10, 308: pagination_empty_rset, 309: pagination_after_index_not_all, 310: pagination_after_index_all, 311: pagination_after_index_all_and_more, 312: pagination_index_out_of_range_above, 313: pagination_index_out_of_range_bellow, 314: pagination_index_out_of_range_closest, 315: pagination_at_index]. 316: 317: rsm_cases_with_offline() -> 318: [pagination_all_with_offline]. 319: suite() -> 320: distributed_helper:require_rpc_nodes([mim, fed]) ++ escalus:suite(). 321: 322: %%-------------------------------------------------------------------- 323: %% Init & teardown 324: %%-------------------------------------------------------------------- 325: 326: 327: init_per_suite(Config) -> 328: %% For mocking with unnamed functions 329: mongoose_helper:inject_module(?MODULE), 330: Config2 = escalus:init_per_suite(Config), 331: Config3 = dynamic_modules:save_modules(host_type(), Config2), 332: dynamic_modules:restart(host_type(), mod_disco, default_mod_config(mod_disco)), 333: muc_helper:load_muc(), 334: mongoose_helper:ensure_muc_clean(), 335: Config3. 336: 337: end_per_suite(Config) -> 338: escalus_fresh:clean(), 339: mongoose_helper:ensure_muc_clean(), 340: muc_helper:unload_muc(), 341: dynamic_modules:restore_modules(Config), 342: escalus:end_per_suite(Config). 343: 344: init_per_group(room_registration_race_condition, Config) -> 345: escalus_fresh:create_users(Config, [{alice, 1}]); 346: 347: init_per_group(moderator, Config) -> 348: Config; 349: init_per_group(admin, Config) -> 350: Config; 351: init_per_group(admin_membersonly, Config) -> 352: Config; 353: 354: init_per_group(G, Config) when G =:= disco -> 355: Config1 = escalus:create_users(Config, escalus:get_users([alice, bob])), 356: [Alice | _] = ?config(escalus_users, Config1), 357: start_room(Config1, Alice, <<"alicesroom">>, <<"aliceonchat">>, [{persistent, true}]); 358: init_per_group(G, Config) when G =:= disco_with_mam -> 359: Config1 = escalus:create_users(Config, escalus:get_users([alice, bob])), 360: Config2 = dynamic_modules:save_modules(host_type(), Config1), 361: setup_mam(mam_helper:backend()), 362: [Alice | _] = ?config(escalus_users, Config2), 363: start_room(Config2, Alice, <<"alicesroom">>, <<"aliceonchat">>, [{persistent, true}]); 364: init_per_group(disco_rsm, Config) -> 365: mongoose_helper:ensure_muc_clean(), 366: Config1 = escalus:create_users(Config, escalus:get_users([alice, bob])), 367: [Alice | _] = ?config(escalus_users, Config1), 368: start_rsm_rooms(Config1, Alice, <<"aliceonchat">>); 369: init_per_group(disco_rsm_with_offline, Config) -> 370: mongoose_helper:ensure_muc_clean(), 371: Config1 = escalus:create_users(Config, escalus:get_users([alice, bob])), 372: [Alice | _] = ?config(escalus_users, Config1), 373: ok = rpc(mim(), mod_muc, store_room, [host_type(), muc_host(), <<"persistentroom">>, []]), 374: start_rsm_rooms(Config1, Alice, <<"aliceonchat">>); 375: init_per_group(G, Config) when G =:= http_auth_no_server; 376: G =:= http_auth -> 377: PoolOpts = #{strategy => available_worker, workers => 5}, 378: ConnOpts = #{host => "http://localhost:8080", path_prefix => <<"/muc/auth/">>, 379: request_timeout => 2000}, 380: Pool = config([outgoing_pools, http, muc_http_auth_test], 381: #{opts => PoolOpts, conn_opts => ConnOpts}), 382: [{ok, _Pid}] = rpc(mim(), mongoose_wpool, start_configured_pools, [[Pool]]), 383: case G of 384: http_auth -> http_helper:start(8080, "/muc/auth/check_password", fun handle_http_auth/1); 385: _ -> ok 386: end, 387: ConfigWithModules = dynamic_modules:save_modules(host_type(), Config), 388: dynamic_modules:ensure_modules(host_type(), required_modules(http_auth)), 389: ConfigWithModules; 390: init_per_group(hibernation, Config) -> 391: Config1 = dynamic_modules:save_modules(host_type(), Config), 392: setup_mam(mam_helper:backend()), 393: Config1; 394: init_per_group(register_over_s2s, Config) -> 395: Config1 = s2s_helper:init_s2s(Config), 396: Config2 = s2s_helper:configure_s2s(both_plain, Config1), 397: [{_,AliceSpec2}|Others] = escalus:get_users([alice2, bob, kate]), 398: Users = [{alice,AliceSpec2}|Others], 399: escalus:create_users(Config2, Users); 400: init_per_group(_GroupName, Config) -> 401: escalus:create_users(Config, escalus:get_users([alice, bob, kate])). 402: 403: required_modules(http_auth) -> 404: #{mod_muc := OrigOpts} = dynamic_modules:get_current_modules(host_type()), 405: #{default_room := DefRoomOpts} = OrigOpts, 406: Opts = OrigOpts#{http_auth_pool => muc_http_auth_test, 407: default_room => DefRoomOpts#{password_protected => true}}, 408: [{mod_muc, Opts}]; 409: required_modules(persistent_by_default) -> 410: #{mod_muc := OrigOpts} = dynamic_modules:get_current_modules(host_type()), 411: #{default_room := DefRoomOpts} = OrigOpts, 412: Opts = OrigOpts#{default_room => DefRoomOpts#{persistent => true}}, 413: [{mod_muc, Opts}]. 414: 415: handle_http_auth(Req) -> 416: Qs = cowboy_req:parse_qs(Req), 417: {Code, Msg} = case proplists:get_value(<<"pass">>, Qs, undefined) of 418: ?PASSWORD -> {0, <<"OK">>}; 419: _ -> {121, <<"Password expired">>} 420: end, 421: Resp = jiffy:encode(#{code => Code, msg => Msg}), 422: Headers = #{<<"content-type">> => <<"application/json">>}, 423: cowboy_req:reply(200, Headers, Resp, Req). 424: 425: end_per_group(room_registration_race_condition, Config) -> 426: rpc(mim(), meck, unload, []), 427: escalus:delete_users(Config, escalus:get_users([bob, alice])); 428: 429: end_per_group(admin_membersonly, Config) -> 430: Config; 431: 432: end_per_group(G, Config) when G =:= disco -> 433: destroy_room(Config), 434: escalus:delete_users(Config, escalus:get_users([alice, bob])); 435: 436: end_per_group(G, Config) when G =:= disco_with_mam -> 437: destroy_room(Config), 438: escalus:delete_users(Config, escalus:get_users([alice, bob])), 439: dynamic_modules:restore_modules(Config); 440: 441: end_per_group(G, Config) when G =:= disco_rsm_with_offline; 442: G =:= disco_rsm -> 443: destroy_rsm_rooms(Config), 444: escalus:delete_users(Config, escalus:get_users([alice, bob])); 445: 446: end_per_group(G, Config) when G =:= http_auth_no_server; 447: G =:= http_auth -> 448: case G of 449: http_auth -> http_helper:stop(); 450: _ -> ok 451: end, 452: ejabberd_node_utils:call_fun(mongoose_wpool, stop, [http, global, muc_http_auth_test]), 453: dynamic_modules:restore_modules(Config); 454: end_per_group(hibernation, Config) -> 455: dynamic_modules:restore_modules(Config); 456: end_per_group(register_over_s2s, Config) -> 457: s2s_helper:end_s2s(Config), 458: escalus:delete_users(Config, escalus:get_users([alice2, bob, kate])); 459: end_per_group(_GroupName, Config) -> 460: escalus:delete_users(Config, escalus:get_users([alice, bob, kate])). 461: 462: init_per_testcase(CaseName = create_already_registered_room, Config) -> 463: meck_room(), 464: meck_room_start(), 465: escalus:init_per_testcase(CaseName, Config); 466: init_per_testcase(CaseName = check_presence_route_to_offline_room, Config) -> 467: meck_room(), 468: meck_room_start(), 469: meck_room_route(), 470: escalus:init_per_testcase(CaseName, Config); 471: init_per_testcase(CaseName = check_message_route_to_offline_room, Config) -> 472: meck_room(), 473: meck_room_start(), 474: meck_room_route(), 475: escalus:init_per_testcase(CaseName, Config); 476: 477: init_per_testcase(CaseName = send_non_anonymous_history, Config) -> 478: [Alice | _] = ?config(escalus_users, Config), 479: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, [{anonymous, false}]), 480: escalus:init_per_testcase(CaseName, Config1); 481: init_per_testcase(CaseName = limit_history_chars, Config) -> 482: [Alice | _] = ?config(escalus_users, Config), 483: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 484: escalus:init_per_testcase(CaseName, Config1); 485: init_per_testcase(CaseName = limit_history_messages, Config) -> 486: [Alice | _] = ?config(escalus_users, Config), 487: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 488: escalus:init_per_testcase(CaseName, Config1); 489: init_per_testcase(CaseName = recent_history, Config) -> 490: [Alice | _] = ?config(escalus_users, Config), 491: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 492: escalus:init_per_testcase(CaseName, Config1); 493: init_per_testcase(CaseName = no_history, Config) -> 494: [Alice | _] = ?config(escalus_users, Config), 495: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 496: escalus:init_per_testcase(CaseName, Config1); 497: init_per_testcase(CaseName = registration_request, Config) -> 498: [Alice | _] = ?config(escalus_users, Config), 499: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 500: escalus:init_per_testcase(CaseName, Config1); 501: init_per_testcase(CaseName = reserved_nickname_request, Config) -> 502: [Alice | _] = ?config(escalus_users, Config), 503: Config1 = start_room(Config, Alice, <<"alicesroom">>, <<"alice">>, []), 504: escalus:init_per_testcase(CaseName, Config1); 505: init_per_testcase(CN, Config) when CN =:= hibernated_room_can_be_queried_for_archive; 506: CN =:= stopped_rooms_history_is_available; 507: CN =:= disco_features_with_mam; 508: CN =:= disco_info_with_mam -> 509: case mam_helper:backend() of 510: disabled -> 511: {skip, "No MAM backend available"}; 512: _Backend -> 513: escalus:init_per_testcase(CN, Config) 514: end; 515: init_per_testcase(CaseName = room_creation_not_allowed, Config) -> 516: Config1 = backup_and_set_config_option(Config, [{access, host_type()}, muc_create], 517: [#{acl => all, value => deny}]), 518: escalus:init_per_testcase(CaseName, Config1); 519: init_per_testcase(CaseName = create_instant_persistent_room, Config) -> 520: ConfigWithModules = dynamic_modules:save_modules(host_type(), Config), 521: dynamic_modules:ensure_modules(host_type(), required_modules(persistent_by_default)), 522: escalus:init_per_testcase(CaseName, ConfigWithModules); 523: init_per_testcase(CaseName, Config) -> 524: escalus:init_per_testcase(CaseName, Config). 525: 526: setup_mam(disabled) -> ok; 527: setup_mam(Backend) -> 528: HostPattern = subhost_pattern(muc_helper:muc_host_pattern()), 529: dynamic_modules:ensure_modules( 530: host_type(), [{mod_mam, 531: mam_helper:config_opts(#{backend => Backend, 532: muc => #{host => HostPattern}})}]). 533: 534: meck_room() -> 535: RPCSpec = (mim())#{timeout => timer:seconds(10)}, % it takes long to compile this module 536: ok = rpc(RPCSpec, meck, new, [mod_muc_room, [no_link, passthrough]]). 537: 538: %% Meck will register a fake room right before a 'real' room is started 539: meck_room_start() -> 540: rpc(mim(), meck, expect, [mod_muc_room, init, fun ?MODULE:meck_init/1]). 541: 542: meck_init(#{muc_host := Host, host_type := HostType, room_name := Room} = Args) -> 543: mod_muc:register_room(HostType, Host, Room, ?FAKEPID), 544: meck:passthrough([Args]). 545: 546: %% Meck will forward all calls to route to the test case instead 547: meck_room_route() -> 548: TestCasePid = self(), 549: ok = rpc(mim(), meck, expect, [mod_muc_room, route, 550: fun(Pid, _From, _ToNick, _Acc, _Packet) -> 551: TestCasePid ! Pid 552: end]). 553: 554: end_per_testcase(CaseName = create_already_registered_room, Config) -> 555: rpc(mim(), meck, unload, []), 556: escalus:end_per_testcase(CaseName, Config); 557: end_per_testcase(CaseName = check_presence_route_to_offline_room, Config) -> 558: rpc(mim(), meck, unload, []), 559: escalus:end_per_testcase(CaseName, Config); 560: end_per_testcase(CaseName = check_message_route_to_offline_room, Config) -> 561: rpc(mim(), meck, unload, []), 562: escalus:end_per_testcase(CaseName, Config); 563: end_per_testcase(CaseName = send_non_anonymous_history, Config) -> 564: destroy_room(Config), 565: escalus:end_per_testcase(CaseName, Config); 566: end_per_testcase(CaseName = limit_history_chars, Config) -> 567: destroy_room(Config), 568: escalus:end_per_testcase(CaseName, Config); 569: end_per_testcase(CaseName = limit_history_messages, Config) -> 570: destroy_room(Config), 571: escalus:end_per_testcase(CaseName, Config); 572: end_per_testcase(CaseName = recent_history, Config) -> 573: destroy_room(Config), 574: escalus:end_per_testcase(CaseName, Config); 575: end_per_testcase(CaseName = no_history, Config) -> 576: destroy_room(Config), 577: escalus:end_per_testcase(CaseName, Config); 578: end_per_testcase(CaseName = registration_request, Config) -> 579: destroy_room(Config), 580: escalus:end_per_testcase(CaseName, Config); 581: end_per_testcase(CaseName = reserved_nickname_request, Config) -> 582: destroy_room(Config), 583: escalus:end_per_testcase(CaseName, Config); 584: end_per_testcase(CaseName = room_creation_not_allowed, Config) -> 585: restore_config_option(Config, [{access, host_type()}, muc_create]), 586: escalus:end_per_testcase(CaseName, Config); 587: end_per_testcase(CaseName = create_instant_persistent_room, Config) -> 588: dynamic_modules:restore_modules(Config), 589: escalus:end_per_testcase(CaseName, Config); 590: end_per_testcase(CaseName, Config) -> 591: escalus:end_per_testcase(CaseName, Config). 592: 593: %%-------------------------------------------------------------------- 594: %% Room options 595: 596: moderator_room_opts() -> 597: [{persistent, true}, {allow_change_subj, false}, 598: {moderated, true}, {members_by_default, false}]. 599: 600: admin_room_opts() -> 601: [{persistent, true}]. 602: 603: admin_mo_room_opts() -> 604: [{persistent, true}, {members_only, true}]. 605: 606: %%-------------------------------------------------------------------- 607: %% Moderator use case tests 608: %% 609: %% Tests the usecases described here : 610: %% http://xmpp.org/extensions/xep-0045.html/#moderator 611: %%-------------------------------------------------------------------- 612: 613: %% Examples 84-85 614: moderator_subject(ConfigIn) -> 615: story_with_room(ConfigIn, moderator_room_opts(), [{alice, 1}], fun(Config, Alice) -> 616: %% Alice joins room 617: EnterRoom = stanza_muc_enter_room(?config(room, Config), <<"alice">>), 618: escalus:send(Alice, EnterRoom), 619: escalus:wait_for_stanzas(Alice, 2), 620: 621: %% Alice sets room subuject 622: SetSubject = stanza_room_subject(?config(room,Config), <<"Lets have a chat!">>), 623: escalus:send(Alice, SetSubject), 624: 625: %% Alice receives subject change message 626: Message = escalus:wait_for_stanza(Alice), 627: true = is_subject_message(Message, <<"Lets have a chat!">>), 628: escalus:assert(is_stanza_from, 629: [room_address(?config(room,Config), <<"alice">>)], Message) 630: end). 631: 632: %% Example 87 633: %% This test doesn't fail anymore 634: %% According to XEP error message should be from chatroom@service/nick, 635: %% however ejabberd provides it from chatroom@service 636: moderator_subject_unauthorized(ConfigIn) -> 637: UserSpecs = [{alice, 1}, {bob, 1}], 638: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 639: %% Alice joins room 640: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 641: escalus:wait_for_stanzas(Alice, 2), 642: %% Bob joins room 643: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 644: escalus:wait_for_stanzas(Bob, 3), 645: %% Skip Bob's presence 646: escalus:wait_for_stanza(Alice), 647: 648: %% Alice grants voice to Bob 649: escalus:send(Alice, stanza_set_roles(?config(room,Config), 650: [{<<"bob">>,<<"participant">>}])), 651: 652: %% skip Bob's new presence 653: escalus:wait_for_stanza(Bob), 654: 655: %% Bob tries to set the room subject 656: escalus:send(Bob, 657: stanza_room_subject(?config(room,Config), <<"Lets have a chat!">>)), 658: 659: %% Bob should receive an error 660: Error = escalus:wait_for_stanza(Bob), 661: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error), 662: escalus:assert(is_stanza_from, 663: [room_address(?config(room, Config), <<"bob">>)], Error) 664: end). 665: 666: %% Examples 89-92 667: %% Apparently user has to be in the room to kick someone, however XEP doesn't need that 668: moderator_kick(ConfigIn) -> 669: UserSpecs = [{alice, 1}, {bob, 1}], 670: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 671: %% Alice joins room 672: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 673: escalus:wait_for_stanzas(Alice, 2), 674: %% Bob joins room 675: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 676: escalus:wait_for_stanzas(Bob, 3), 677: %% Skip Bob's presence 678: escalus:wait_for_stanza(Alice), 679: 680: %% Alice kicks Bob 681: escalus:send(Alice, stanza_set_roles( 682: ?config(room,Config), [{<<"bob">>,<<"none">>}])), 683: 684: %% Alice receives both iq result and Bob's unavailable presence 685: Pred = fun(Stanza) -> 686: is_unavailable_presence(Stanza, <<"307">>) andalso 687: escalus_pred:is_stanza_from( 688: room_address(?config(room, Config), <<"bob">>), Stanza) 689: end, 690: escalus:assert_many([is_iq_result, Pred], 691: escalus:wait_for_stanzas(Alice, 2)), 692: 693: %% Bob receives his presence 694: escalus:assert(Pred, escalus:wait_for_stanza(Bob)) 695: end). 696: 697: moderator_kick_with_reason(ConfigIn) -> 698: UserSpecs = [{alice, 1}, {bob, 1}], 699: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 700: %% Alice joins room 701: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 702: escalus:wait_for_stanzas(Alice, 2), 703: %% Bob joins room 704: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 705: escalus:wait_for_stanzas(Bob, 3), 706: %% Skip Bob's presence 707: escalus:wait_for_stanza(Alice), 708: 709: %% Alice kicks Bob 710: escalus:send(Alice, stanza_set_roles( 711: ?config(room,Config), [{<<"bob">>,<<"none">>,<<"Some serious reason">>}])), 712: 713: %% Alice receives both iq result and Bob's unavailable presence 714: Pred = fun(Stanza) -> 715: has_reason(Stanza) andalso 716: is_unavailable_presence(Stanza, <<"307">>) andalso 717: escalus_pred:is_stanza_from( 718: room_address(?config(room, Config), <<"bob">>), Stanza) 719: end, 720: escalus:assert_many([is_iq_result, Pred], 721: escalus:wait_for_stanzas(Alice, 2)), 722: %% Bob receives his presence 723: Pres = escalus:wait_for_stanza(Bob), 724: escalus:assert(Pred, Pres), 725: true = has_reason(Pres) 726: end). 727: 728: %% Example 93 729: moderator_kick_unauthorized(ConfigIn) -> 730: UserSpecs = [{alice, 1}, {bob, 1}], 731: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 732: %% Alice joins room 733: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 734: escalus:wait_for_stanzas(Alice, 2), 735: %% Bob joins room 736: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 737: escalus:wait_for_stanzas(Bob, 3), 738: %% Skip Bob's presence 739: escalus:wait_for_stanza(Alice), 740: 741: %% Bob tries to kick Alice 742: escalus:send(Bob, stanza_set_roles( 743: ?config(room,Config), [{<<"alice">>,<<"none">>}])), 744: 745: %% Bob should get an error 746: Error = escalus:wait_for_stanza(Bob), 747: escalus:assert(is_error, [<<"cancel">>,<<"not-allowed">>], Error), 748: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 749: end). 750: 751: %% Examples 94-101 752: moderator_voice(ConfigIn) -> 753: UserSpecs = [{alice, 1}, {bob, 1}], 754: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 755: %% Alice joins room 756: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 757: escalus:wait_for_stanzas(Alice, 2), 758: %% Bob joins room 759: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 760: escalus:wait_for_stanzas(Bob, 3), 761: %% Skip Bob's presence 762: escalus:wait_for_stanza(Alice), 763: 764: %% Alice grants voice to Bob 765: escalus:send(Alice, stanza_set_roles(?config(room,Config), 766: [{<<"bob">>,<<"participant">>}])), 767: 768: %% Alice receives success information and new Bob's presence 769: Pred = fun(Stanza) -> 770: is_presence_with_role(Stanza, <<"participant">>) andalso 771: escalus_pred:is_stanza_from( 772: room_address(?config(room, Config), <<"bob">>), Stanza) 773: end, 774: escalus:assert_many([is_iq_result, Pred], 775: escalus:wait_for_stanzas(Alice, 2)), 776: 777: %% Bob should receive his new presence 778: escalus:assert(Pred, escalus:wait_for_stanza(Bob)), 779: 780: %% Revoke Bob's voice 781: escalus:send(Alice, stanza_set_roles(?config(room,Config), 782: [{<<"bob">>,<<"visitor">>}])), 783: 784: %% Alice receives success information and new Bob's presence 785: Pred2 = fun(Stanza) -> 786: is_presence_with_role(Stanza, <<"visitor">>) andalso 787: escalus_pred:is_stanza_from( 788: room_address(?config(room, Config), <<"bob">>), Stanza) 789: end, 790: escalus:assert_many([is_iq_result, Pred2], 791: escalus:wait_for_stanzas(Alice, 2)), 792: 793: %% Bob should receive his new presence 794: escalus:assert(Pred2, escalus:wait_for_stanza(Bob)) 795: end). 796: 797: moderator_voice_with_reason(ConfigIn) -> 798: UserSpecs = [{alice, 1}, {bob, 1}], 799: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 800: %% Alice joins room 801: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 802: escalus:wait_for_stanzas(Alice, 2), 803: %% Bob joins room 804: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 805: escalus:wait_for_stanzas(Bob, 3), 806: %% Skip Bob's presence 807: escalus:wait_for_stanza(Alice), 808: 809: %% Alice grants voice to Bob 810: escalus:send(Alice, stanza_set_roles(?config(room,Config), 811: [{<<"bob">>,<<"participant">>,<<"Lets chat!">>}])), 812: 813: %% Alice receives success information and new Bob's presence 814: Pred = fun(Stanza) -> 815: has_reason(Stanza) andalso 816: is_presence_with_role(Stanza, <<"participant">>) andalso 817: escalus_pred:is_stanza_from( 818: room_address(?config(room, Config), <<"bob">>), Stanza) 819: end, 820: escalus:assert_many([is_iq_result, Pred], 821: escalus:wait_for_stanzas(Alice, 2)), 822: 823: %% Bob should receive his new presence 824: Pres = escalus:wait_for_stanza(Bob), 825: escalus:assert(Pred, Pres), 826: true = has_reason(Pres), 827: 828: %% Revoke Bob's voice 829: escalus:send(Alice, stanza_set_roles(?config(room,Config), 830: [{<<"bob">>,<<"visitor">>,<<"No, let's not">>}])), 831: 832: %% Alice receives success information and new Bob's presence 833: Pred2 = fun(Stanza) -> 834: is_presence_with_role(Stanza, <<"visitor">>) andalso 835: escalus_pred:is_stanza_from( 836: room_address(?config(room, Config), <<"bob">>), Stanza) 837: end, 838: escalus:assert_many([is_iq_result, Pred2], 839: escalus:wait_for_stanzas(Alice, 2)), 840: 841: %% Bob should receive his new presence 842: Pres2 = escalus:wait_for_stanza(Bob), 843: escalus:assert(Pred2, Pres2), 844: true = has_reason(Pres2) 845: end). 846: %% Example 102, 107 847: moderator_voice_unauthorized(ConfigIn) -> 848: UserSpecs = [{alice, 1}, {bob, 1}], 849: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 850: %% Alice joins room 851: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 852: escalus:wait_for_stanzas(Alice, 2), 853: %% Bob joins room 854: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 855: escalus:wait_for_stanzas(Bob, 3), 856: %% Skip Bob's presence 857: escalus:wait_for_stanza(Alice), 858: 859: %% Bob tries to revoke voice from Alice 860: escalus:send(Bob, stanza_set_roles(?config(room,Config), 861: [{<<"alice">>,<<"visitor">>}])), 862: 863: %% Bob should get an error 864: Error = escalus:wait_for_stanza(Bob), 865: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Error), 866: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 867: end). 868: 869: %% Examples 103-106 870: %% ejabberd behaves strange, responds that owner doesn't have moderator privileges 871: %% if she isn't in the room 872: moderator_voice_list(ConfigIn) -> 873: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 874: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 875: %% Alice joins room 876: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 877: escalus:wait_for_stanzas(Alice, 2), 878: %% Bob joins room 879: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 880: escalus:wait_for_stanzas(Bob, 3), 881: %% Kate joins room 882: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 883: escalus:wait_for_stanzas(Kate, 4), 884: %% Skip Kate's presence 885: escalus:wait_for_stanza(Bob), 886: %% Skip Kate's and Bob's presences 887: escalus:wait_for_stanzas(Alice, 3), 888: 889: %% Alice requests voice list 890: escalus:send(Alice, 891: stanza_role_list_request(?config(room, Config), <<"participant">>)), 892: List = escalus:wait_for_stanza(Alice), 893: escalus:assert(is_iq_result, List), 894: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], List), 895: %% List should be empty 896: true = is_item_list_empty(List), 897: 898: %% Grant voice to Bob and Kate 899: escalus:send(Alice, stanza_set_roles(?config(room, Config), 900: [{<<"bob">>, <<"participant">>}, {<<"kate">>,<<"participant">>}])), 901: 902: %% Alice receives confirmation and Bob's and Kate's new presences 903: Preds = [fun(Stanza) -> 904: is_presence_with_role(Stanza, <<"participant">>) andalso 905: escalus_pred:is_stanza_from( 906: room_address(?config(room, Config), <<"bob">>), Stanza) 907: end, 908: fun(Stanza) -> 909: is_presence_with_role(Stanza, <<"participant">>) andalso 910: escalus_pred:is_stanza_from( 911: room_address(?config(room, Config), <<"kate">>), Stanza) 912: end], 913: escalus:assert_many([is_iq_result | Preds], 914: escalus:wait_for_stanzas(Alice, 3)), 915: 916: %% Bob and Kates get their presences 917: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 918: escalus:assert_many(Preds, escalus:wait_for_stanzas(Kate, 2)), 919: 920: %% Alice requests voice list again 921: escalus:send(Alice, 922: stanza_role_list_request(?config(room, Config), <<"participant">>)), 923: List2 = escalus:wait_for_stanza(Alice), 924: escalus:assert(is_iq_result, List2), 925: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], List2), 926: %% Bob and Kate should be on it 927: true = is_iq_with_jid(List2, Bob), 928: true = is_iq_with_jid(List2, Kate), 929: 930: %% Revoke Bob's and Kate's voices 931: escalus:send(Alice, stanza_set_roles(?config(room, Config), 932: [{<<"bob">>, <<"visitor">>}, {<<"kate">>,<<"visitor">>}])), 933: 934: %% Alice receives confirmation and Bob's and Kate's new presences 935: Preds2 = [fun(Stanza) -> 936: is_presence_with_role(Stanza, <<"visitor">>) andalso 937: escalus_pred:is_stanza_from( 938: room_address(?config(room, Config), <<"bob">>), Stanza) 939: end, 940: fun(Stanza) -> 941: is_presence_with_role(Stanza, <<"visitor">>) andalso 942: escalus_pred:is_stanza_from( 943: room_address(?config(room, Config), <<"kate">>), Stanza) 944: end], 945: escalus:assert_many([is_iq_result | Preds2], 946: escalus:wait_for_stanzas(Alice, 3)), 947: 948: %% Bob and Kates get their presences 949: escalus:assert_many(Preds2, escalus:wait_for_stanzas(Bob, 2)), 950: escalus:assert_many(Preds2, escalus:wait_for_stanzas(Kate, 2)) 951: end). 952: 953: %% This test doesn't fail anymore, moderator used to never get voice approval form 954: %% This test works, but XEP doesn't specify what error messages should be here if something goes wrong... 955: %% Examples 108-109 956: moderator_voice_approval(ConfigIn) -> 957: UserSpecs = [{alice, 1}, {bob, 1}], 958: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 959: %% Alice joins room 960: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 961: escalus:wait_for_stanzas(Alice, 2), 962: %% Bob joins room 963: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 964: escalus:wait_for_stanzas(Bob, 3), 965: %% Skip Bob's presence 966: escalus:wait_for_stanza(Alice), 967: 968: %% Bob sends voice request 969: escalus:send(Bob, stanza_voice_request_form(?config(room, Config))), 970: 971: %% Alice should get the request 972: Form = escalus:wait_for_stanza(Alice), 973: true = is_message_form(Form), 974: 975: Appr = stanza_voice_request_approval(?config(room, Config), 976: escalus_utils:get_short_jid(Bob), <<"bob">>, true), 977: escalus:send(Alice, Appr), 978: 979: %% Bob should get his new presence 980: Pres = escalus:wait_for_stanza(Bob), 981: true = is_presence_with_role(Pres, <<"participant">>) 982: 983: end). 984: 985: moderator_voice_approval_errors(ConfigIn) -> 986: UserSpecs = [{alice, 1}, {bob, 1}], 987: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 988: %% Alice joins room 989: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 990: escalus:wait_for_stanzas(Alice, 2), 991: %% Bob joins room 992: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 993: escalus:wait_for_stanzas(Bob, 3), 994: %% Skip Bob's presence 995: escalus:wait_for_stanza(Alice), 996: 997: Req = stanza_voice_request_approval(?config(room, Config), 998: escalus_utils:get_short_jid(Bob), <<"bob">>, true), 999: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 1000: escalus:send_and_wait(Alice, form_helper:remove_form_types(Req))), 1001: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 1002: escalus:send_and_wait(Alice, form_helper:remove_form_ns(Req))), 1003: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 1004: escalus:send_and_wait(Alice, form_helper:remove_forms(Req))), 1005: 1006: %% 'false' approval also results in an error 1007: Req2 = stanza_voice_request_approval(?config(room, Config), 1008: escalus_utils:get_short_jid(Bob), <<"bob">>, false), 1009: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 1010: escalus:send_and_wait(Alice, Req2)) 1011: end). 1012: 1013: moderator_voice_forbidden(ConfigIn) -> 1014: UserSpecs = [{alice, 1}, {bob, 1}], 1015: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1016: %% Alice joins room 1017: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1018: escalus:wait_for_stanzas(Alice, 2), 1019: %% Bob joins room 1020: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1021: escalus:wait_for_stanzas(Bob, 3), 1022: %% Skip Bob's presence 1023: escalus:wait_for_stanza(Alice), 1024: 1025: %% Bob tries to send request approval 1026: Appr = stanza_voice_request_approval(?config(room, Config), 1027: escalus_utils:get_short_jid(Bob), <<"bob">>, true), 1028: escalus:send(Bob, Appr), 1029: 1030: %% Bob should get an error 1031: Err = escalus:wait_for_stanza(Bob), 1032: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Err) 1033: end). 1034: 1035: moderator_voice_not_occupant(ConfigIn) -> 1036: UserSpecs = [{alice, 1}, {bob, 1}], 1037: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1038: %% Alice tries to send request approval while she isn't in the room 1039: Appr = stanza_voice_request_approval(?config(room, Config), 1040: escalus_utils:get_short_jid(Bob), <<"bob">>, true), 1041: escalus:send(Alice, Appr), 1042: 1043: %% Alice should get an error 1044: Err = escalus:wait_for_stanza(Alice), 1045: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], Err) 1046: end). 1047: 1048: moderator_voice_nonick(ConfigIn) -> 1049: UserSpecs = [{alice, 1}, {bob, 1}], 1050: story_with_room(ConfigIn, moderator_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1051: %% Alice joins room 1052: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1053: escalus:wait_for_stanzas(Alice, 2), 1054: %% Bob joins room 1055: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1056: escalus:wait_for_stanzas(Bob, 3), 1057: %% Skip Bob's presence 1058: escalus:wait_for_stanza(Alice), 1059: 1060: %% Bob sends voice request 1061: escalus:send(Bob, stanza_voice_request_form(?config(room, Config))), 1062: 1063: %% Alice should get the request 1064: Form = escalus:wait_for_stanza(Alice), 1065: true = is_message_form(Form), 1066: 1067: Appr = stanza_voice_request_approval_nonick(?config(room, Config), 1068: escalus_utils:get_short_jid(Bob)), 1069: escalus:send(Alice, Appr), 1070: 1071: %% Alice should get an error 1072: Error = escalus:wait_for_stanza(Alice), 1073: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 1074: Error) 1075: 1076: end). 1077: %%-------------------------------------------------------------------- 1078: %% Admin use case tests 1079: %% 1080: %% Tests the usecases described here : 1081: %% http://xmpp.org/extensions/xep-0045.html/#admin 1082: %%-------------------------------------------------------------------- 1083: 1084: %% Examples 110-114 1085: admin_ban(ConfigIn) -> 1086: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1087: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1088: %% Bob joins room 1089: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1090: escalus:wait_for_stanzas(Bob, 2), 1091: %% Kate joins room 1092: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1093: escalus:wait_for_stanzas(Kate, 3), 1094: %% Skip Kate's presence 1095: escalus:wait_for_stanza(Bob), 1096: 1097: %% Alice bans Bob 1098: escalus:send(Alice, stanza_ban_user(Bob, ?config(room, Config))), 1099: 1100: %% Alice receives confirmation 1101: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1102: 1103: %% Bob receives outcast presence 1104: Outcast = escalus:wait_for_stanza(Bob), 1105: escalus:assert(is_presence_with_type, [<<"unavailable">>], Outcast), 1106: escalus:assert(is_stanza_from, 1107: [room_address(?config(room, Config), <<"bob">>)], Outcast), 1108: true = is_presence_with_status_code(Outcast, <<"301">>), 1109: true = is_presence_with_affiliation(Outcast, <<"outcast">>), 1110: true = is_presence_with_role(Outcast, <<"none">>), 1111: 1112: %% Kate receives Bob's outcast presence 1113: BobOutcast = escalus:wait_for_stanza(Kate), 1114: escalus:assert(is_presence_with_type, [<<"unavailable">>], BobOutcast), 1115: true = is_presence_with_affiliation(BobOutcast, <<"outcast">>), 1116: true = is_presence_with_role(BobOutcast, <<"none">>), 1117: escalus:assert(is_stanza_from, [room_address(?config(room, Config), <<"bob">>)], 1118: BobOutcast) 1119: %% ejabberd doesn't send jid attribute in presence as in ex. 114 1120: end). 1121: 1122: admin_ban_with_reason(ConfigIn) -> 1123: UserSpecs = [{alice, 1}, {kate, 1}], 1124: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Kate) -> 1125: %% Kate joins room 1126: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1127: escalus:wait_for_stanzas(Kate, 2), 1128: 1129: %% Alice bans Kate 1130: escalus:send(Alice, stanza_ban_user(Kate, ?config(room, Config), <<"Be rational!">>)), 1131: 1132: %% Alice receives confirmation 1133: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1134: 1135: %% Kate receives outcast presence 1136: Outcast = escalus:wait_for_stanza(Kate), 1137: escalus:assert(is_presence_with_type, [<<"unavailable">>], Outcast), 1138: escalus:assert(is_stanza_from, 1139: [room_address(?config(room, Config), <<"kate">>)], Outcast), 1140: true = is_presence_with_status_code(Outcast, <<"301">>), 1141: true = is_presence_with_affiliation(Outcast, <<"outcast">>), 1142: true = is_presence_with_role(Outcast, <<"none">>), 1143: true = has_reason(Outcast) 1144: 1145: end). 1146: 1147: %% Example 115 1148: %% Reponse 'from' field should be full JID, ejabberd provides chatroom JID 1149: %% However it's a bit strange as other cancel/not-allowed errors must be from the room JID 1150: %% Temporarily left room address check 1151: admin_ban_higher_user(ConfigIn) -> 1152: UserSpecs = [{alice, 1}, {bob, 1}], 1153: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1154: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1155: escalus:wait_for_stanzas(Bob, 2), 1156: %% Bob tries to ban Alice 1157: escalus:send(Bob, stanza_ban_user(Alice, ?config(room, Config))), 1158: %% Bob receives an error 1159: Error = escalus:wait_for_stanza(Bob), 1160: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Error), 1161: %% escalus:assert(is_stanza_from, 1162: %% [escalus_utils:get_jid(Bob)], Error) 1163: escalus:assert(is_stanza_from, 1164: [room_address(?config(room, Config))], Error) 1165: end). 1166: 1167: %% Examples 116-119 1168: admin_ban_list(ConfigIn) -> 1169: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1170: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1171: %% Bob joins room 1172: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1173: escalus:wait_for_stanzas(Bob, 2), 1174: %% Kate joins room 1175: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1176: escalus:wait_for_stanzas(Kate, 3), 1177: %% Skip Kate's presence 1178: escalus:wait_for_stanza(Bob), 1179: %% Alice requests ban list 1180: %% Alice bans Bob 1181: escalus:send(Alice, stanza_ban_user(Bob, ?config(room, Config))), 1182: 1183: %% Alice receives confirmation 1184: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1185: 1186: %% Bob receives outcast presence 1187: escalus:wait_for_stanza(Bob), 1188: %% Kate receives presence 1189: escalus:wait_for_stanza(Kate), 1190: %% Alice bans Kate 1191: escalus:send(Alice, stanza_ban_user(Kate, ?config(room, Config), <<"Be rational!">>)), 1192: 1193: %% Alice receives confirmation 1194: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1195: 1196: %% Kate receives Bob's outcast presence 1197: escalus:wait_for_stanza(Kate), 1198: 1199: escalus:send(Alice, stanza_ban_list_request(?config(room, Config))), 1200: List = escalus:wait_for_stanza(Alice), 1201: escalus:assert(is_iq_result, List), 1202: 1203: %% Bob and Kate should be banned 1204: true = is_iq_with_affiliation(List, <<"outcast">>), 1205: true = is_iq_with_short_jid(List, Bob), 1206: true = is_iq_with_short_jid(List, Kate), 1207: 1208: %% Remove Bob's ban 1209: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_ADMIN, []), ?config(room, Config)), 1210: Items = [{escalus_utils:get_short_jid(Bob),<<"none">>}, 1211: {escalus_utils:get_short_jid(Kate), <<"none">>}], 1212: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items)), 1213: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1214: 1215: %% Request again 1216: escalus:send(Alice, stanza_ban_list_request(?config(room, Config))), 1217: List2 = escalus:wait_for_stanza(Alice), 1218: 1219: %% Noone should be banned 1220: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], 1221: List2), 1222: true = is_item_list_empty(List2) 1223: end). 1224: 1225: admin_get_form(ConfigIn) -> 1226: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1227: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, _Bob, _Kate) -> 1228: timer:sleep(?WAIT_TIME), 1229: %%%% Bootstrap: 1230: %% Alice is admin 1231: %% enter Bob, we make him moderator 1232: %% enter Kate, she's just a participant 1233: %% Alice joins room 1234: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1235: escalus:wait_for_stanzas(Alice, 2), 1236: F = stanza_form_request(?config(room, Config)), 1237: escalus:send(Alice, F), 1238: Form = escalus:wait_for_stanza(Alice), 1239: escalus:assert(is_iq_result, Form), 1240: ok 1241: end), 1242: ok. 1243: 1244: admin_invalid_affiliation(ConfigIn) -> 1245: UserSpecs = [{alice, 1}, {bob, 1}], 1246: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1247: %% Bob joins room 1248: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1249: escalus:wait_for_stanzas(Bob, 2), 1250: 1251: %% Alice tries to give invalid affiliation to Bob 1252: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), 1253: [{escalus_utils:get_short_jid(Bob), <<"some-random-affiliation">>}])), 1254: %% Alice receives error 1255: Error = escalus:wait_for_stanza(Alice), 1256: escalus:assert(is_iq_error, Error), 1257: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], Error), 1258: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1259: 1260: end). 1261: 1262: admin_invalid_jid(ConfigIn) -> 1263: UserSpecs = [{alice, 1}, {bob, 1}], 1264: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1265: %% Bob joins room 1266: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1267: escalus:wait_for_stanzas(Bob, 2), 1268: 1269: %% Alice tries to give invalid affiliation to Bob 1270: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), 1271: [{<<"@mistyped-jid">>, <<"admin">>}])), 1272: %% Alice receives error 1273: Error = escalus:wait_for_stanza(Alice), 1274: escalus:assert(is_iq_error, Error), 1275: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], Error), 1276: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1277: 1278: end). 1279: 1280: %% Examples 120-127 1281: admin_membership(ConfigIn) -> 1282: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1283: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1284: %% Bob joins room 1285: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1286: escalus:wait_for_stanzas(Bob, 2), 1287: %% Kate joins room 1288: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1289: escalus:wait_for_stanzas(Kate, 3), 1290: %% Skip Kate's presence 1291: escalus:wait_for_stanza(Bob), 1292: 1293: %% Alice grants membership to Bob 1294: Items = [{escalus_utils:get_short_jid(Bob),<<"member">>}], 1295: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items)), 1296: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1297: 1298: %% Bob receives his notice 1299: Bobs = escalus:wait_for_stanza(Bob), 1300: true = is_presence_with_affiliation(Bobs, <<"member">>), 1301: escalus:assert(is_stanza_from, 1302: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1303: 1304: %% Kate receives Bob's notice 1305: Kates = escalus:wait_for_stanza(Kate), 1306: true = is_presence_with_affiliation(Kates, <<"member">>), 1307: escalus:assert(is_stanza_from, 1308: [room_address(?config(room, Config), <<"bob">>)], Kates), 1309: 1310: %% Alice revokes Bob's membership 1311: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>}], 1312: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items2)), 1313: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1314: 1315: %% Bob receives his loss of membership presence 1316: Bobs2 = escalus:wait_for_stanza(Bob), 1317: true = is_presence_with_affiliation(Bobs2, <<"none">>), 1318: escalus:assert(is_stanza_from, 1319: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 1320: 1321: %% Kate receives Bob's loss of membership presence 1322: Kates2 = escalus:wait_for_stanza(Kate), 1323: true = is_presence_with_affiliation(Kates2, <<"none">>), 1324: escalus:assert(is_stanza_from, 1325: [room_address(?config(room,Config), <<"bob">>)], Kates2) 1326: end). 1327: 1328: admin_membership_with_reason(ConfigIn) -> 1329: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1330: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1331: %% Bob joins room 1332: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1333: escalus:wait_for_stanzas(Bob, 2), 1334: %% Kate joins room 1335: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1336: escalus:wait_for_stanzas(Kate, 3), 1337: %% Skip Kate's presence 1338: escalus:wait_for_stanza(Bob), 1339: 1340: %% Alice grants membership to Bob 1341: Items = [{escalus_utils:get_short_jid(Bob),<<"member">>,<<"Member?">>}], 1342: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items)), 1343: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1344: 1345: %% Bob receives his notice 1346: Bobs = escalus:wait_for_stanza(Bob), 1347: true = has_reason(Bobs), 1348: true = is_presence_with_affiliation(Bobs, <<"member">>), 1349: escalus:assert(is_stanza_from, 1350: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1351: 1352: %% Kates receives Bob's presence 1353: Kates = escalus:wait_for_stanza(Kate), 1354: true = has_reason(Kates), 1355: true = is_presence_with_affiliation(Bobs, <<"member">>), 1356: escalus:assert(is_stanza_from, 1357: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1358: 1359: 1360: %% Alice revokes Bob's membership 1361: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>, <<"Your call">>}], 1362: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items2)), 1363: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1364: 1365: %% Bob receives his loss of membership presence 1366: Bobs2 = escalus:wait_for_stanza(Bob), 1367: true = has_reason(Bobs2), 1368: true = is_presence_with_affiliation(Bobs2, <<"none">>), 1369: escalus:assert(is_stanza_from, 1370: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 1371: 1372: %% Kate receives his loss of membership presence 1373: Kates2 = escalus:wait_for_stanza(Kate), 1374: true = has_reason(Kates2), 1375: true = is_presence_with_affiliation(Kates2, <<"none">>), 1376: escalus:assert(is_stanza_from, 1377: [room_address(?config(room,Config), <<"bob">>)], Kates2) 1378: 1379: end). 1380: 1381: %% Examples 129-136 1382: admin_member_list(ConfigIn) -> 1383: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1384: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1385: %% Bob joins room 1386: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1387: escalus:wait_for_stanzas(Bob, 2), 1388: %% Kate joins room 1389: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1390: escalus:wait_for_stanzas(Kate, 3), 1391: %% Skip Kate's presence 1392: escalus:wait_for_stanza(Bob), 1393: 1394: %% Alice requests member list 1395: escalus:send(Alice, stanza_affiliation_list_request( 1396: ?config(room, Config), <<"member">>)), 1397: List = escalus:wait_for_stanza(Alice), 1398: escalus:assert(is_iq_result, List), 1399: 1400: %% List should be empty 1401: true = is_item_list_empty(List), 1402: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], List), 1403: 1404: %% Make Bob a member 1405: Items = [{escalus_utils:get_short_jid(Bob), <<"member">>}], 1406: escalus:send(Alice, stanza_set_affiliations(?config(room, Config), Items)), 1407: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1408: 1409: %% Bob receives his notice 1410: Bobs = escalus:wait_for_stanza(Bob), 1411: true = is_presence_with_affiliation(Bobs, <<"member">>), 1412: escalus:assert(is_stanza_from, 1413: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1414: 1415: %% Kate receives Bob's notice 1416: Kates = escalus:wait_for_stanza(Kate), 1417: true = is_presence_with_affiliation(Kates, <<"member">>), 1418: escalus:assert(is_stanza_from, 1419: [room_address(?config(room, Config), <<"bob">>)], Kates), 1420: 1421: %% Request again 1422: escalus:send(Alice, stanza_affiliation_list_request( 1423: ?config(room, Config), <<"member">>)), 1424: List2 = escalus:wait_for_stanza(Alice), 1425: escalus:assert(is_iq_result, List2), 1426: 1427: %% Bob should be on the list 1428: true = is_iq_with_affiliation(List2, <<"member">>), 1429: true = is_iq_with_short_jid(List2, Bob), 1430: 1431: %% Revoke Bob's membership and make Kate a member 1432: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>}, 1433: {escalus_utils:get_short_jid(Kate), <<"member">>}], 1434: escalus:send(Alice, stanza_set_affiliations(?config(room,Config), Items2)), 1435: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 1436: 1437: %% Bob receives his and Kate's presence 1438: Preds = [ 1439: fun(Stanza) -> 1440: escalus_pred:is_stanza_from( 1441: room_address(?config(room, Config), <<"kate">>),Stanza) andalso 1442: is_presence_with_affiliation(Stanza, <<"member">>) 1443: end, 1444: fun(Stanza) -> 1445: escalus_pred:is_stanza_from( 1446: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 1447: is_presence_with_affiliation(Stanza, <<"none">>) 1448: end 1449: ], 1450: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 1451: 1452: %% Kate receives her and Bob's presence 1453: escalus:assert_many(Preds, escalus:wait_for_stanzas(Kate, 2)), 1454: 1455: %% Now Kate requests member list, and doesn't get it because she is neither owner, admin or moderator 1456: %% and the room is configured without the roomconfig_getmemberlist setting 1457: escalus:send(Kate, stanza_affiliation_list_request( 1458: ?config(room, Config), <<"member">>)), 1459: Error = escalus:wait_for_stanza(Kate), 1460: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error) 1461: end). 1462: 1463: check_memberlist(LoginData, yes, Config) -> 1464: escalus:send(LoginData, stanza_affiliation_list_request( 1465: ?config(room, Config), <<"member">>)), 1466: escalus:assert(is_iq_result, escalus:wait_for_stanza(LoginData)); 1467: check_memberlist(LoginData, no, Config) -> 1468: escalus:send(LoginData, stanza_affiliation_list_request( 1469: ?config(room, Config), <<"member">>)), 1470: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], escalus:wait_for_stanza(LoginData)). 1471: 1472: check_rolelist(LoginData, yes, Config) -> 1473: escalus:send(LoginData, stanza_role_list_request( 1474: ?config(room, Config), <<"moderator">>)), 1475: escalus:assert(is_iq_result, escalus:wait_for_stanza(LoginData)); 1476: check_rolelist(LoginData, no, Config) -> 1477: escalus:send(LoginData, stanza_role_list_request( 1478: ?config(room, Config), <<"moderator">>)), 1479: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], escalus:wait_for_stanza(LoginData)). 1480: 1481: 1482: %% This one tests a roomconfig_getmemberlist setting 1483: admin_member_list_allowed(ConfigIn) -> 1484: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1485: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1486: timer:sleep(?WAIT_TIME), 1487: %%%% Bootstrap: 1488: %% Alice is admin 1489: %% enter Bob, we make him moderator 1490: %% enter Kate, she's just a participant 1491: %% Alice joins room 1492: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1493: escalus:wait_for_stanzas(Alice, 2), 1494: %% Bob joins room 1495: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1496: escalus:wait_for_stanzas(Bob, 3), 1497: %% Kate joins room 1498: KateNick = escalus_utils:get_username(Kate), 1499: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), KateNick)), 1500: escalus:wait_for_stanzas(Kate, 4), 1501: %% Skip Kate's presence 1502: escalus:wait_for_stanza(Bob), 1503: %% Skip Kate's and Bob's presences 1504: escalus:wait_for_stanzas(Alice, 3), 1505: %% Grant bob moderator status 1506: escalus:send(Alice, stanza_set_roles( 1507: ?config(room, Config), [{<<"bob">>,<<"moderator">>}])), 1508: escalus:wait_for_stanzas(Alice, 2), 1509: %% Bob receives his notice 1510: escalus:wait_for_stanza(Bob), 1511: %% Kate receives Bob's notice 1512: escalus:wait_for_stanza(Kate), 1513: %%%% end of bootstrap 1514: %% default room setup - config var is empty 1515: %% Alice can get member list 1516: check_memberlist(Alice, yes, Config), 1517: %% Bob can't get member list 1518: check_memberlist(Bob, no, Config), 1519: %% Kate can't get member list 1520: check_memberlist(Kate, no, Config), 1521: %% same for role list (it doesn't matter which role we ask, we use moderator) 1522: %% Alice can get moderator list 1523: check_rolelist(Alice, yes, Config), 1524: %% Bob can get moderator list because he is a moderator 1525: check_rolelist(Bob, yes, Config), 1526: %% Kate can't get member list 1527: check_memberlist(Kate, no, Config), 1528: %% setup room - allow getmemberlist for moderator 1529: Fields = [#{var => <<"muc#roomconfig_getmemberlist">>, values => [<<"moderator">>], 1530: type => <<"list-multi">>}], 1531: Form = stanza_configuration_form(?config(room, Config), Fields), 1532: escalus:send_iq_and_wait_for_result(Alice, Form), 1533: %% memberlist 1534: %% Alice - yes 1535: check_memberlist(Alice, yes, Config), 1536: %% Bob - yes 1537: check_memberlist(Bob, yes, Config), 1538: %% Kate - no 1539: check_memberlist(Kate, no, Config), 1540: %% same for moderator list 1541: %% Alice - yes 1542: check_rolelist(Alice, yes, Config), 1543: %% Bob - yes, as always 1544: check_rolelist(Bob, yes, Config), 1545: %% Kate - no 1546: check_rolelist(Bob, yes, Config), 1547: %% setup room - allow getmemberlist for participant 1548: Fields1 = [#{var => <<"muc#roomconfig_getmemberlist">>, values => [<<"participant">>], 1549: type => <<"list-multi">>}], 1550: Form1 = stanza_configuration_form(?config(room, Config), Fields1), 1551: escalus:send_iq_and_wait_for_result(Alice, Form1), 1552: %% memberlist 1553: %% Alice - yes 1554: check_memberlist(Alice, yes, Config), 1555: %% Bob - no (moderator is not a participant) 1556: check_memberlist(Bob, no, Config), 1557: %% Kate - yes 1558: check_memberlist(Kate, yes, Config), 1559: %% role list 1560: %% Alice - yes 1561: check_rolelist(Alice, yes, Config), 1562: %% Bob - yes 1563: check_rolelist(Bob, yes, Config), 1564: %% Kate - yes 1565: check_rolelist(Kate, yes, Config), 1566: %% exit Kate 1567: escalus:send(Kate, stanza_to_room(escalus_stanza:presence(<<"unavailable">>), ?config(room, Config), 1568: escalus_utils:get_username(Kate))), 1569: assert_is_exit_message_correct(Kate, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Alice)), 1570: assert_is_exit_message_correct(Kate, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Bob)), 1571: assert_is_exit_message_correct(Kate, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Kate)), 1572: %% memberlist 1573: %% Kate - no 1574: check_memberlist(Kate, no, Config), 1575: %% role list 1576: %% Kate - no 1577: check_rolelist(Kate, no, Config), 1578: %% setup room - allow getmemberlist for visitor 1579: Fields2 = [#{var => <<"muc#roomconfig_getmemberlist">>, values => [<<"visitor">>], 1580: type => <<"list-multi">>}], 1581: Form2 = stanza_configuration_form(?config(room, Config), Fields2), 1582: escalus:send_iq_and_wait_for_result(Alice, Form2), 1583: %% member list 1584: %% Alice - yes 1585: check_memberlist(Alice, yes, Config), 1586: %% Bob - no (gahhh...) 1587: check_memberlist(Bob, no, Config), 1588: %% Kate - yes 1589: check_memberlist(Kate, yes, Config), 1590: %% role list 1591: %% Alice - yes (as admin) 1592: check_rolelist(Alice, yes, Config), 1593: %% Bob - yes (as moderator) 1594: check_rolelist(Bob, yes, Config), 1595: %% Kate - yes (as visitor) 1596: check_rolelist(Kate, yes, Config), 1597: ok 1598: end), 1599: ok. 1600: 1601: %% Examples 137-145 1602: admin_moderator(ConfigIn) -> 1603: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1604: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1605: timer:sleep(?WAIT_TIME), 1606: %% Alice joins room 1607: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1608: escalus:wait_for_stanzas(Alice, 2), 1609: %% Bob joins room 1610: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1611: escalus:wait_for_stanzas(Bob, 3), 1612: %% Kate joins room 1613: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1614: escalus:wait_for_stanzas(Kate, 4), 1615: %% Skip Kate's presence 1616: escalus:wait_for_stanza(Bob), 1617: %% Skip Kate's and Bob's presences 1618: escalus:wait_for_stanzas(Alice, 3), 1619: 1620: %% Grant bob moderator status 1621: escalus:send(Alice, stanza_set_roles( 1622: ?config(room, Config), [{<<"bob">>,<<"moderator">>}])), 1623: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 1624: 1625: %% Bob receives his notice 1626: Bobs = escalus:wait_for_stanza(Bob), 1627: true = is_presence_with_role(Bobs, <<"moderator">>), 1628: escalus:assert(is_stanza_from, 1629: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1630: 1631: %% Kate receives Bob's notice 1632: Kates = escalus:wait_for_stanza(Kate), 1633: true = is_presence_with_role(Kates, <<"moderator">>), 1634: escalus:assert(is_stanza_from, 1635: [room_address(?config(room, Config), <<"bob">>)], Kates), 1636: 1637: %% Revoke bob moderator status 1638: Pred = fun(Stanza) -> 1639: escalus_pred:is_stanza_from( 1640: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 1641: is_presence_with_role(Stanza, <<"participant">>) 1642: end, 1643: 1644: escalus:send(Alice, stanza_set_roles( 1645: ?config(room, Config), [{<<"bob">>, <<"participant">>}])), 1646: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Alice, 2)), 1647: 1648: %% Bob receives his loss of moderator presence 1649: Bobs2 = escalus:wait_for_stanza(Bob), 1650: true = is_presence_with_role(Bobs2, <<"participant">>), 1651: escalus:assert(is_stanza_from, 1652: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 1653: 1654: %% Kate receives Bob's loss of moderator presence 1655: Kates2 = escalus:wait_for_stanza(Kate), 1656: true = is_presence_with_role(Kates2, <<"participant">>), 1657: escalus:assert(is_stanza_from, 1658: [room_address(?config(room,Config), <<"bob">>)], Kates2) 1659: 1660: end). 1661: 1662: admin_moderator_with_reason(ConfigIn) -> 1663: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1664: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1665: %% Alice joins room 1666: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1667: escalus:wait_for_stanzas(Alice, 2), 1668: %% Bob joins room 1669: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1670: escalus:wait_for_stanzas(Bob, 3), 1671: %% Kate joins room 1672: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1673: escalus:wait_for_stanzas(Kate, 4), 1674: %% Skip Kate's presence 1675: escalus:wait_for_stanza(Bob), 1676: %% Skip Kate's and Bob's presences 1677: escalus:wait_for_stanzas(Alice, 3), 1678: 1679: %% Grant bob moderator status 1680: escalus:send(Alice, stanza_set_roles( 1681: ?config(room, Config), [{<<"bob">>,<<"moderator">>,<<"He should be fair">>}])), 1682: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 1683: 1684: %% Bob receives his notice 1685: Bobs = escalus:wait_for_stanza(Bob), 1686: true = is_presence_with_role(Bobs, <<"moderator">>), 1687: true = has_reason(Bobs), 1688: escalus:assert(is_stanza_from, 1689: [room_address(?config(room, Config), <<"bob">>)], Bobs), 1690: 1691: %% Kate receives Bob's notice 1692: Kates = escalus:wait_for_stanza(Kate), 1693: true = has_reason(Kates), 1694: true = is_presence_with_role(Kates, <<"moderator">>), 1695: escalus:assert(is_stanza_from, 1696: [room_address(?config(room, Config), <<"bob">>)], Kates), 1697: 1698: %% Revoke bob moderator status 1699: Pred = fun(Stanza) -> 1700: escalus_pred:is_stanza_from( 1701: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 1702: is_presence_with_role(Stanza, <<"participant">>) 1703: end, 1704: 1705: escalus:send(Alice, stanza_set_roles( 1706: ?config(room, Config), [{<<"bob">>, <<"participant">>, <<"He wasn't">>}])), 1707: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Alice, 2)), 1708: 1709: %% Bob receives his loss of moderator presence 1710: Bobs2 = escalus:wait_for_stanza(Bob), 1711: true = is_presence_with_role(Bobs2, <<"participant">>), 1712: true = has_reason(Bobs2), 1713: escalus:assert(is_stanza_from, 1714: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 1715: 1716: %% Kate receives Bob's loss of moderator presence 1717: Kates2 = escalus:wait_for_stanza(Kate), 1718: true = is_presence_with_role(Kates2, <<"participant">>), 1719: true = has_reason(Kates2), 1720: escalus:assert(is_stanza_from, 1721: [room_address(?config(room,Config), <<"bob">>)], Kates2) 1722: 1723: end). 1724: 1725: %% Examples 145, 150 1726: admin_moderator_revoke_owner(ConfigIn) -> 1727: UserSpecs = [{alice, 1}], 1728: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice) -> 1729: %% Alice joins room 1730: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1731: escalus:wait_for_stanzas(Alice, 2), 1732: %% Alice tries to revoke moderator status from herself 1733: escalus:send(Alice, stanza_set_roles(?config(room, Config), 1734: [{<<"alice">>, <<"participant">>}])), 1735: %% Should be an error 1736: Error = escalus:wait_for_stanza(Alice), 1737: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], Error), 1738: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1739: end). 1740: 1741: %% Examples 146-150 1742: admin_moderator_list(ConfigIn) -> 1743: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1744: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1745: %% Alice joins room 1746: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1747: escalus:wait_for_stanzas(Alice, 2), 1748: %% Bob joins room 1749: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1750: escalus:wait_for_stanzas(Bob, 3), 1751: %% Kate joins room 1752: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1753: escalus:wait_for_stanzas(Kate, 4), 1754: %% Skip Kate's presence 1755: escalus:wait_for_stanza(Bob), 1756: %% Skip Kate's and Bob's presences 1757: escalus:wait_for_stanzas(Alice, 3), 1758: 1759: %% Request moderator list 1760: List = escalus:send_iq_and_wait_for_result( 1761: Alice, stanza_role_list_request(?config(room, Config), <<"moderator">>)), 1762: %% Alice should be on it 1763: true = is_iq_with_jid(List, Alice), 1764: true = is_iq_with_role(List, <<"moderator">>), 1765: 1766: %% Grant Bob and Kate moderators role 1767: Preds = [ 1768: fun(Stanza) -> 1769: escalus_pred:is_stanza_from( 1770: room_address(?config(room, Config), <<"kate">>),Stanza) andalso 1771: is_presence_with_role(Stanza, <<"moderator">>) 1772: end, 1773: fun(Stanza) -> 1774: escalus_pred:is_stanza_from( 1775: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 1776: is_presence_with_role(Stanza, <<"moderator">>) 1777: end 1778: ], 1779: escalus:send(Alice, stanza_set_roles(?config(room, Config), 1780: [{<<"bob">>,<<"moderator">>},{<<"kate">>,<<"moderator">>}])), 1781: escalus:assert_many([is_iq_result | Preds], escalus:wait_for_stanzas(Alice,3)), 1782: 1783: %% Bob receives his and Kate's moderator presence 1784: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob,2)), 1785: 1786: %% Kate receives her and Bob's moderator presence 1787: escalus:assert_many(Preds, escalus:wait_for_stanzas(Kate,2)), 1788: 1789: %% Request again 1790: List2 = escalus:send_iq_and_wait_for_result( 1791: Alice, stanza_role_list_request(?config(room, Config), <<"moderator">>)), 1792: 1793: %% Alice, Bob and Kate should be on it 1794: true = is_iq_with_jid(List2, Alice), 1795: true = is_iq_with_jid(List2, Bob), 1796: true = is_iq_with_jid(List2, Kate), 1797: 1798: %% Revoke Bob's and Kate's roles 1799: Preds2 = [ 1800: fun(Stanza) -> 1801: escalus_pred:is_stanza_from( 1802: room_address(?config(room, Config), <<"kate">>),Stanza) andalso 1803: is_presence_with_role(Stanza, <<"participant">>) 1804: end, 1805: fun(Stanza) -> 1806: escalus_pred:is_stanza_from( 1807: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 1808: is_presence_with_role(Stanza, <<"participant">>) 1809: end 1810: ], 1811: escalus:send(Alice, stanza_set_roles(?config(room, Config), 1812: [{<<"bob">>,<<"participant">>},{<<"kate">>,<<"participant">>}])), 1813: escalus:assert_many([is_iq_result|Preds2], escalus:wait_for_stanzas(Alice,3)), 1814: 1815: %% Bob receives his and Kate's participant presence 1816: escalus:assert_many(Preds2, escalus:wait_for_stanzas(Bob,2)), 1817: 1818: %% Kate receives her and Bob's participant presence 1819: escalus:assert_many(Preds2, escalus:wait_for_stanzas(Kate,2)) 1820: end). 1821: 1822: admin_invalid_role(ConfigIn) -> 1823: UserSpecs = [{alice, 1}, {bob, 1}], 1824: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1825: %% Alice joins room 1826: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1827: escalus:wait_for_stanzas(Alice, 2), 1828: %% Bob joins room 1829: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1830: escalus:wait_for_stanzas(Bob, 3), 1831: %% Skip Bob's presences 1832: escalus:wait_for_stanza(Alice), 1833: 1834: %% Grant bob moderator status 1835: escalus:send(Alice, stanza_set_roles( 1836: ?config(room, Config), [{<<"bob">>,<<"role-that-i-made-up">>}])), 1837: Error = escalus:wait_for_stanza(Alice), 1838: escalus:assert(is_iq_error, Error), 1839: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], Error), 1840: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1841: end). 1842: 1843: admin_invalid_nick(ConfigIn) -> 1844: UserSpecs = [{alice, 1}, {bob, 1}], 1845: story_with_room(ConfigIn, admin_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1846: %% Alice joins room 1847: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 1848: escalus:wait_for_stanzas(Alice, 2), 1849: %% Bob joins room 1850: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1851: escalus:wait_for_stanzas(Bob, 3), 1852: %% Skip Bob's presences 1853: escalus:wait_for_stanza(Alice), 1854: 1855: %% Grant bob moderator status 1856: escalus:send(Alice, stanza_set_roles( 1857: ?config(room, Config), [{<<"mistyped-nickname">>,<<"moderator">>}])), 1858: Error = escalus:wait_for_stanza(Alice), 1859: escalus:assert(is_iq_error, Error), 1860: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], Error), 1861: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1862: end). 1863: 1864: %% Example 128 1865: admin_mo_revoke(ConfigIn) -> 1866: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1867: story_with_room(ConfigIn, admin_mo_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1868: %% Make Bob and Kate members 1869: Items = [{escalus_utils:get_short_jid(Bob), <<"member">>}, 1870: {escalus_utils:get_short_jid(Kate), <<"member">>}], 1871: escalus:send_iq_and_wait_for_result( 1872: Alice, stanza_set_affiliations(?config(room,Config), Items)), 1873: 1874: %% Bob gets invitation 1875: is_invitation(escalus:wait_for_stanza(Bob)), 1876: %% Kate gets invitation 1877: is_invitation(escalus:wait_for_stanza(Kate)), 1878: 1879: %% Bob joins room 1880: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1881: escalus:wait_for_stanzas(Bob, 2), 1882: %% Kate joins room 1883: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 1884: escalus:wait_for_stanzas(Kate, 3), 1885: %% Skip Kate's presence 1886: escalus:wait_for_stanza(Bob), 1887: 1888: %% Alice revokes Bob's membership 1889: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>}], 1890: escalus:send_iq_and_wait_for_result( 1891: Alice, stanza_set_affiliations(?config(room, Config), Items2)), 1892: 1893: %% Skip Bob's lost of membership presence (tested in the other case) 1894: escalus:wait_for_stanza(Bob), 1895: 1896: %% Kate receives Bob's loss of unavailable presence 1897: Kates = escalus:wait_for_stanza(Kate), 1898: true = is_membership_presence(Kates, <<"none">>, <<"none">>), 1899: true = is_unavailable_presence(Kates, <<"321">>), 1900: escalus:assert(is_stanza_from, 1901: [room_address(?config(room, Config),<<"bob">>)], Kates) 1902: end). 1903: 1904: %% Example 134 1905: %% ejabberd doesn't send an invitation after adding user to a member list 1906: admin_mo_invite(ConfigIn) -> 1907: UserSpecs = [{alice, 1}, {bob, 1}], 1908: story_with_room(ConfigIn, admin_mo_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1909: %% Make Bob a member 1910: Items = [{escalus_utils:get_short_jid(Bob), <<"member">>}], 1911: escalus:send(Alice, stanza_set_affiliations(?config(room,Config), Items)), 1912: escalus:wait_for_stanza(Alice), 1913: 1914: %% Bob should receive an invitation 1915: Inv = escalus:wait_for_stanza(Bob), 1916: is_invitation(Inv), 1917: escalus:assert(is_stanza_from, [room_address(?config(room,Config))], Inv), 1918: 1919: %% Alice revokes Bob's membership 1920: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>}], 1921: escalus:send_iq_and_wait_for_result( 1922: Alice, stanza_set_affiliations(?config(room, Config), Items2)) 1923: end). 1924: 1925: admin_mo_invite_with_reason(ConfigIn) -> 1926: UserSpecs = [{alice, 1}, {bob, 1}], 1927: story_with_room(ConfigIn, admin_mo_room_opts(), UserSpecs, fun(Config, Alice, Bob) -> 1928: %% Make Bob a member 1929: Items = [{escalus_utils:get_short_jid(Bob), <<"member">>, <<"Just an invitation">>}], 1930: escalus:send(Alice, stanza_set_affiliations(?config(room,Config), Items)), 1931: escalus:wait_for_stanza(Alice), 1932: 1933: %% Bob should receive an invitation 1934: Inv = escalus:wait_for_stanza(Bob), 1935: is_invitation(Inv), 1936: true = invite_has_reason(Inv), 1937: escalus:assert(is_stanza_from, [room_address(?config(room,Config))], Inv), 1938: 1939: %% Alice revokes Bob's membership 1940: Items2 = [{escalus_utils:get_short_jid(Bob), <<"none">>}], 1941: escalus:send_iq_and_wait_for_result( 1942: Alice, stanza_set_affiliations(?config(room, Config), Items2)) 1943: end). 1944: 1945: %% Example 135 1946: %% ejabberd returns cancel/not-allowed error while it should return auth/forbidden according to XEP 1947: admin_mo_invite_mere(ConfigIn) -> 1948: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 1949: story_with_room(ConfigIn, admin_mo_room_opts(), UserSpecs, fun(Config, Alice, Bob, Kate) -> 1950: %% Make Bob a member 1951: Items = [{escalus_utils:get_short_jid(Bob), <<"member">>}], 1952: escalus:send(Alice, stanza_set_affiliations(?config(room,Config), Items)), 1953: escalus:wait_for_stanza(Alice), 1954: 1955: %% Bob gets na invitation 1956: escalus:wait_for_stanza(Bob), 1957: 1958: %% Bob joins room 1959: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 1960: escalus:wait_for_stanzas(Bob, 2), 1961: 1962: %% Bob tries to invite Kate 1963: escalus:send(Bob, stanza_mediated_invitation(?config(room,Config), Kate)), 1964: 1965: %% He should receive an error 1966: Error = escalus:wait_for_stanza(Bob), 1967: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error), 1968: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error) 1969: end). 1970: 1971: %%-------------------------------------------------------------------- 1972: %% Occupant use case tests 1973: %% 1974: %% Tests the usecases described here : 1975: %% http://xmpp.org/extensions/xep-0045.html/#user 1976: %% 1977: %% note: new user presence broadcast is unconfigurable and enabled for participants 1978: %% by default 1979: %% 1980: %% convention - in this part of the suite user names are uses aas nicknames if a testcase does not require otherwise 1981: %% TO DO: 1982: %% 1983: %% JID is not sent to participancts, use owner to throuhtly test some of the use cases 1984: %% is this behavious configurable? 1985: %%-------------------------------------------------------------------- 1986: %Example 18 1987: groupchat_user_enter(ConfigIn) -> 1988: UserSpecs = [{alice, 1}, {bob, 1}], 1989: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob) -> 1990: EnterRoomStanza = stanza_groupchat_enter_room(?config(room, Config), escalus_utils:get_username(Bob)), 1991: escalus:send(Bob, EnterRoomStanza), 1992: Presence = escalus:wait_for_stanza(Bob), 1993: escalus_pred:is_presence(Presence), 1994: From = room_address(?config(room, Config), escalus_utils:get_username(Bob)), 1995: From = exml_query:attr(Presence, <<"from">>) 1996: end). 1997: 1998: groupchat_user_enter_twice(ConfigIn) -> 1999: UserSpecs = [{alice, 1}, {bob, 1}], 2000: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob) -> 2001: EnterRoomStanza = stanza_groupchat_enter_room(?config(room, Config), escalus_utils:get_username(Bob)), 2002: escalus:send(Bob, EnterRoomStanza), 2003: Presence = escalus:wait_for_stanza(Bob), 2004: escalus_pred:is_presence(Presence), 2005: From = room_address(?config(room, Config), escalus_utils:get_username(Bob)), 2006: From = exml_query:attr(Presence, <<"from">>), 2007: escalus:wait_for_stanza(Bob), 2008: escalus:send(Bob, EnterRoomStanza), 2009: Presence2 = escalus:wait_for_stanza(Bob), 2010: escalus_pred:is_presence(Presence2), 2011: From = exml_query:attr(Presence2, <<"from">>) 2012: end). 2013: 2014: groupchat_user_enter_old_protocol(ConfigIn) -> 2015: UserSpecs = [{alice, 1}, {bob, 1}], 2016: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob) -> 2017: Room = ?config(room, Config), 2018: Nick = escalus_utils:get_username(Bob), 2019: EnterRoomStanza = stanza_to_room(escalus_stanza:presence(<<"available">>), Room, Nick), 2020: escalus:send(Bob, EnterRoomStanza), 2021: Presence = escalus:wait_for_stanza(Bob), 2022: is_self_presence(Bob, ?config(room, Config), Presence), 2023: has_status_codes(Presence, [<<"110">>, <<"307">>, <<"333">>]) 2024: end). 2025: 2026: %Example 19 2027: %Fails - no error message sent from the server 2028: groupchat_user_enter_no_nickname(ConfigIn) -> 2029: UserSpecs = [{alice, 1}, {bob, 1}], 2030: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob) -> 2031: escalus:send(Bob, stanza_groupchat_enter_room_no_nick(?config(room, Config))), 2032: escalus:assert(is_error, [<<"modify">>, <<"jid-malformed">>], escalus:wait_for_stanza(Bob)), 2033: escalus_assert:has_no_stanzas(Alice), 2034: escalus_assert:has_no_stanzas(Bob) 2035: end). 2036: 2037: 2038: % Examples 20, 21, 22 2039: % Fails - no 110 status code in the self-presence messages 2040: muc_user_enter(ConfigIn) -> 2041: UserSpecs = [{alice, 0}, {bob, 1}, {kate, 1}], 2042: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Bob, Kate) -> 2043: %Bob enters the room 2044: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2045: 2046: Presence = escalus:wait_for_stanza(Bob), 2047: is_presence_with_affiliation(Presence, <<"none">>), 2048: is_self_presence(Bob, ?config(room, Config), Presence), 2049: escalus:wait_for_stanza(Bob), %topic 2050: 2051: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2052: 2053: Presence2 = escalus:wait_for_stanza(Bob), 2054: is_presence_with_affiliation(Presence2, <<"none">>), 2055: is_presence_from(Kate, ?config(room, Config), Presence2), 2056: 2057: Presence3 = escalus:wait_for_stanza(Kate), 2058: is_presence_with_affiliation(Presence3, <<"none">>), 2059: is_presence_from(Bob, ?config(room, Config), Presence3), 2060: 2061: Presence4 = escalus:wait_for_stanza(Kate), 2062: is_presence_with_affiliation(Presence4, <<"none">>), 2063: is_self_presence(Kate, ?config(room, Config), Presence4), 2064: escalus:wait_for_stanza(Kate) %topic 2065: end). 2066: 2067: % Example 23 ,24 2068: % No simple way to lock down the nicknames 2069: 2070: % Example 25, 26 2071: % fails - sends an additional message instead of including code 100 in the presence 2072: enter_non_anonymous_room(ConfigIn) -> 2073: RoomOpts = [{anonymous, false}], 2074: UserSpecs = [{alice, 0}, {bob, 1}], 2075: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2076: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2077: %should include code 100 in the presence messages to inform users alobut the room being non-annymous. 2078: %sends an additional simple message instead 2079: Presence = escalus:wait_for_stanza(Bob), 2080: is_self_presence(Bob, ?config(room, Config), Presence), 2081: has_status_codes(Presence, [<<"100">>]), 2082: escalus:wait_for_stanza(Bob) %topic 2083: end). 2084: 2085: %TO DO: 2086: % semi-anonymous rooms 2087: % no option to turn a room into a semi-anonymous one 2088: % (No examples, section 7.2.5) 2089: 2090: %Example 27 2091: deny_access_to_password_protected_room(ConfigIn) -> 2092: RoomOpts = [{password_protected, true}], 2093: UserSpecs = [{alice, 0}, {bob, 1}], 2094: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2095: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2096: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"auth">>, <<"not-authorized">>) 2097: end). 2098: 2099: %Example 28 2100: % Fails - no 110 status code in the self-presence messages 2101: enter_password_protected_room(ConfigIn) -> 2102: RoomOpts = [{password_protected, true}, {password, ?PASSWORD}], 2103: UserSpecs = [{alice, 0}, {bob, 1}], 2104: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2105: escalus:send(Bob, stanza_muc_enter_password_protected_room(?config(room, Config), escalus_utils:get_username(Bob), ?PASSWORD)), 2106: Presence = escalus:wait_for_stanza(Bob), 2107: is_self_presence(Bob, ?config(room, Config), Presence) 2108: end). 2109: 2110: %Example 29 2111: deny_accesss_to_memebers_only_room(ConfigIn) -> 2112: RoomOpts = [{members_only, true}], 2113: UserSpecs = [{alice, 0}, {bob, 1}], 2114: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2115: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2116: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"auth">>, <<"registration-required">>) 2117: end). 2118: 2119: %Example 30 2120: deny_entry_to_a_banned_user(ConfigIn) -> 2121: UserSpecs = [{alice, 1}, {bob, 1}], 2122: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob) -> 2123: %% Alice bans Bob 2124: escalus:send_iq_and_wait_for_result(Alice, stanza_ban_user(Bob, ?config(room, Config))), 2125: 2126: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2127: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"auth">>, <<"forbidden">>) 2128: end). 2129: 2130: %Examlpe 31 2131: deny_entry_nick_conflict(ConfigIn) -> 2132: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2133: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2134: EnterRoomStanza = stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob)), 2135: escalus:send(Bob, EnterRoomStanza), 2136: escalus:wait_for_stanzas(Bob, 2), 2137: escalus:send(Kate, EnterRoomStanza), 2138: escalus_assert:is_error(escalus:wait_for_stanza(Kate), <<"cancel">>, <<"conflict">>) 2139: end). 2140: 2141: % Entering the room by one user from different devices 2142: multi_sessions_messages(ConfigIn) -> 2143: RoomOpts = [{allow_multiple_sessions, true}], 2144: UserSpecs = [{alice, 1}, {bob, 2}], 2145: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Bob2) -> 2146: populate_room_with_users([Alice, Bob, Bob2], Config), 2147: 2148: Msg = <<"Hi, Bobs!">>, 2149: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2150: 2151: true = is_groupchat_message(escalus:wait_for_stanza(Alice)), 2152: true = is_groupchat_message(escalus:wait_for_stanza(Bob)), 2153: true = is_groupchat_message(escalus:wait_for_stanza(Bob2)), 2154: 2155: Msg2 = <<"Chat, Bobs!">>, 2156: ChatMessage = escalus_stanza:chat_to(room_address(?config(room, Config), escalus_utils:get_username(Bob)), Msg2), 2157: escalus:send(Alice, ChatMessage), 2158: 2159: assert_is_message_correct(?config(room, Config), 2160: escalus_utils:get_username(Alice), <<"chat">>, Msg2, escalus:wait_for_stanza(Bob)), 2161: assert_is_message_correct(?config(room, Config), 2162: escalus_utils:get_username(Alice), <<"chat">>, Msg2, escalus:wait_for_stanza(Bob2)), 2163: 2164: Msg3 = <<"Chat, Alice!">>, 2165: ChatMessage2 = escalus_stanza:chat_to(room_address(?config(room, Config), escalus_utils:get_username(Alice)), Msg3), 2166: escalus:send(Bob, ChatMessage2), 2167: 2168: assert_is_message_correct(?config(room, Config), 2169: escalus_utils:get_username(Bob), <<"chat">>, Msg3, escalus:wait_for_stanza(Alice)) 2170: end). 2171: 2172: % Entering the room by one user from different devices 2173: multi_sessions_enter(ConfigIn) -> 2174: RoomOpts = [{allow_multiple_sessions, true}], 2175: UserSpecs = [{alice, 1}, {bob, 2}], 2176: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Bob2) -> 2177: populate_room_with_users([Alice, Bob, Bob2], Config) 2178: end). 2179: 2180: % Exiting from the room with multiple sessions 2181: multi_sessions_exit(ConfigIn) -> 2182: RoomOpts = [{allow_multiple_sessions, true}], 2183: UserSpecs = [{alice, 1}, {bob, 2}], 2184: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Bob2) -> 2185: populate_room_with_users([Alice, Bob, Bob2], Config), 2186: 2187: escalus:send(Alice, stanza_to_room(escalus_stanza:presence(<<"unavailable">>), ?config(room, Config), escalus_utils:get_username(Alice))), 2188: Message = escalus:wait_for_stanza(Alice), 2189: has_status_codes(Message, [<<"110">>]), 2190: assert_is_exit_message_correct(Alice, <<"none">>, ?config(room, Config), Message), 2191: assert_is_exit_message_correct(Alice, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Bob)), 2192: assert_is_exit_message_correct(Alice, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Bob2)) 2193: end). 2194: 2195: % Exiting from the room with multiple sessions 2196: multi_sessions_exit_session(ConfigIn) -> 2197: RoomOpts = [{allow_multiple_sessions, true}], 2198: UserSpecs = [{alice, 1}, {bob, 2}], 2199: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Bob2) -> 2200: populate_room_with_users([Alice, Bob, Bob2], Config), 2201: 2202: escalus:send(Bob, stanza_to_room(escalus_stanza:presence(<<"unavailable">>), ?config(room, Config), escalus_utils:get_username(Alice))), 2203: Message = escalus:wait_for_stanza(Bob), 2204: has_status_codes(Message, [<<"110">>]), 2205: assert_is_exit_message_correct(Bob, <<"owner">>, ?config(room, Config), Message), 2206: assert_is_exit_message_correct(Bob, <<"owner">>, ?config(room, Config), escalus:wait_for_stanza(Bob2)), 2207: 2208: escalus:send(Bob2, stanza_to_room(escalus_stanza:presence(<<"unavailable">>), ?config(room, Config), escalus_utils:get_username(Alice))), 2209: Message2 = escalus:wait_for_stanza(Bob2), 2210: has_status_codes(Message2, [<<"110">>]), 2211: assert_is_exit_message_correct(Bob2, <<"none">>, ?config(room, Config), Message2), 2212: assert_is_exit_message_correct(Bob2, <<"none">>, ?config(room, Config), escalus:wait_for_stanza(Alice)) 2213: end). 2214: 2215: % Entering the room by one user from different devices with multiple sessions disabled 2216: deny_entry_with_multiple_sessions_disallowed(ConfigIn) -> 2217: RoomOpts = [{allow_multiple_sessions, false}], 2218: UserSpecs = [{alice, 0}, {bob, 2}], 2219: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob, Bob2) -> 2220: EnterRoomStanza = stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob)), 2221: escalus:send(Bob, EnterRoomStanza), 2222: 2223: Presence = escalus:wait_for_stanza(Bob), 2224: is_presence_with_affiliation(Presence, <<"none">>), 2225: is_self_presence(Bob, ?config(room, Config), Presence), 2226: is_subject_message(escalus:wait_for_stanza(Bob)), 2227: 2228: escalus:send(Bob2, EnterRoomStanza), 2229: Stanza = escalus:wait_for_stanza(Bob2), 2230: escalus_assert:is_error(Stanza, <<"cancel">>, <<"conflict">>) 2231: end). 2232: 2233: %Example 32 2234: %fails: wrong error type. should be: 'wait', received: 'cancel' 2235: deny_entry_user_limit_reached(ConfigIn) -> 2236: RoomOpts = [{max_users, 1}], 2237: UserSpecs = [{alice, 0}, {bob, 2}], 2238: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob) -> 2239: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Alice))), 2240: escalus:wait_for_stanzas(Alice, 2), 2241: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2242: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"wait">>, <<"service-unavailable">>) 2243: end). 2244: 2245: %%Example 33 2246: %%requires creating a locked room in the init per testcase function somehow 2247: %deny_entry_locked_room(Config) -> 2248: % escalus:story(Config, [{alice, 1}, {bob, 1}], fun(_Alice, Bob) -> 2249: % escalus:send(Bob,stanza_muc_enter_room(<<"alicesroom">>, <<"aliceonchat">>)), 2250: % Message = escalus:wait_for_stanza(Bob), 2251: % error_logger:info_msg("Not a member error message: ~n~p~n", [Message]), 2252: % escalus_assert:is_error(Message, <<"cancal">>, <<"item-not-found">>) 2253: % end). 2254: 2255: % Nonexistent rooms: 2256: % If a user seeks to enter a non-existent room, servers behaviour is undefined. 2257: % See the xep: http://xmpp.org/extensions/xep-0045.html/#enter-nonexistent 2258: % 2259: 2260: %Example 34 2261: enter_room_with_logging(ConfigIn) -> 2262: RoomOpts = [{logging, true}], 2263: UserSpecs = [{alice, 0}, {bob, 1}], 2264: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2265: %Bob enters the room 2266: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2267: Presence = escalus:wait_for_stanza(Bob), 2268: is_self_presence(Bob, ?config(room, Config), Presence), 2269: has_status_codes(Presence, [<<"170">>]) 2270: end). 2271: 2272: %Example 35 2273: send_history(ConfigIn) -> 2274: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2275: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2276: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2277: escalus:wait_for_stanzas(Alice, 2), 2278: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2279: escalus:wait_for_stanzas(Bob, 3), 2280: escalus:wait_for_stanza(Alice), 2281: Msg = <<"Hi, Bob!">>, 2282: Msg2 = <<"Hi, Alice!">>, 2283: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2284: escalus:wait_for_stanza(Alice), 2285: escalus:wait_for_stanza(Bob), 2286: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2287: escalus:wait_for_stanza(Alice), 2288: escalus:wait_for_stanza(Bob), 2289: 2290: %Kate enters and receives the presences, the message history and finally the topic 2291: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), nick(Kate))), 2292: escalus:wait_for_stanza(Alice), 2293: escalus:wait_for_stanza(Bob), 2294: escalus:wait_for_stanzas(Kate, 3), %presences 2295: is_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Kate)), 2296: is_history_message_correct(?config(room, Config), nick(Bob),<<"groupchat">>,Msg2, escalus:wait_for_stanza(Kate)), 2297: escalus:wait_for_stanza(Kate), %% topic 2298: escalus_assert:has_no_stanzas(Alice), 2299: escalus_assert:has_no_stanzas(Bob), 2300: escalus_assert:has_no_stanzas(Kate) 2301: end). 2302: 2303: 2304: %Example 36 2305: %Fails - sends an additional message instead of including code 100 in the presence 2306: %also - From attribute in the delay element should contain the rooms address without the user name 2307: %and the addresses element is not icluded (note: this feature is optional) 2308: send_non_anonymous_history(Config) -> 2309: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2310: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2311: escalus:wait_for_stanzas(Alice, 2), 2312: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2313: escalus:wait_for_stanzas(Bob, 3), 2314: escalus:wait_for_stanza(Alice), 2315: Msg = <<"Hi, Bob!">>, 2316: Msg2 = <<"Hi, Alice!">>, 2317: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2318: escalus:wait_for_stanza(Alice), 2319: escalus:wait_for_stanza(Bob), 2320: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2321: escalus:wait_for_stanza(Alice), 2322: escalus:wait_for_stanza(Bob), 2323: 2324: %Eve enters and receives the presences, the message history and finally the topic 2325: escalus:send(Eve, stanza_muc_enter_room(?config(room, Config), nick(Eve))), 2326: escalus:wait_for_stanza(Alice), 2327: escalus:wait_for_stanza(Bob), 2328: escalus:wait_for_stanzas(Eve, 3), %presences 2329: is_non_anonymous_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Eve)), 2330: is_non_anonymous_history_message_correct(?config(room, Config), nick(Bob),<<"groupchat">>,Msg2, escalus:wait_for_stanza(Eve)), 2331: escalus:wait_for_stanza(Eve), 2332: escalus_assert:has_no_stanzas(Alice), 2333: escalus_assert:has_no_stanzas(Bob), 2334: escalus_assert:has_no_stanzas(Eve) 2335: end). 2336: 2337: 2338: %Example 37 2339: %fails - the history setting is ignored 2340: limit_history_chars(Config) -> 2341: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2342: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2343: escalus:wait_for_stanzas(Alice, 2), 2344: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2345: escalus:wait_for_stanza(Alice), 2346: escalus:wait_for_stanzas(Bob, 3), 2347: Msg = <<"Hi, Bob!">>, 2348: Msg2 = <<"Hi, Alice!">>, 2349: escalus:send(Alice, escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2350: escalus:wait_for_stanza(Alice), 2351: escalus:wait_for_stanza(Bob), 2352: escalus:send(Bob, escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2353: escalus:wait_for_stanza(Alice), 2354: escalus:wait_for_stanza(Bob), 2355: 2356: %Eve enters and receives the presences, the message history and finally the topic 2357: escalus:send(Eve, stanza_muc_enter_room_history_setting(?config(room, Config), nick(Eve), <<"maxchars">>,<<"500">>)), 2358: escalus:wait_for_stanza(Alice), 2359: escalus:wait_for_stanza(Bob), 2360: escalus:wait_for_stanzas(Eve, 3), %presences 2361: is_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Eve)), 2362: %% Topic 2363: escalus:wait_for_stanza(Eve), 2364: escalus_assert:has_no_stanzas(Alice), 2365: escalus_assert:has_no_stanzas(Bob), 2366: escalus_assert:has_no_stanzas(Eve) 2367: end). 2368: 2369: %Example 38 2370: %fails - the history setting is ignored 2371: limit_history_messages(Config) -> 2372: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2373: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2374: escalus:wait_for_stanzas(Alice, 2), 2375: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2376: escalus:wait_for_stanza(Alice), 2377: escalus:wait_for_stanzas(Bob, 3), 2378: Msg= <<"Hi, Bob!">>, 2379: Msg2= <<"Hi, Alice!">>, 2380: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2381: escalus:wait_for_stanza(Alice), 2382: escalus:wait_for_stanza(Bob), 2383: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2384: escalus:wait_for_stanza(Alice), 2385: escalus:wait_for_stanza(Bob), 2386: 2387: %Eve enters and receives the presences, the message history and finally the topic 2388: escalus:send(Eve, stanza_muc_enter_room_history_setting(?config(room, Config), nick(Eve), <<"maxstanzas">>,<<"1">>)), 2389: escalus:wait_for_stanza(Alice), 2390: escalus:wait_for_stanza(Bob), 2391: escalus:wait_for_stanzas(Eve, 3), %presences 2392: is_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Eve)), 2393: escalus:wait_for_stanza(Eve), %topic 2394: escalus_assert:has_no_stanzas(Alice), 2395: escalus_assert:has_no_stanzas(Bob), 2396: escalus_assert:has_no_stanzas(Eve) 2397: end). 2398: 2399: %Example 39 2400: %fails - the history setting is ignored 2401: recent_history(Config) -> 2402: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2403: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2404: escalus:wait_for_stanzas(Alice, 2), 2405: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2406: escalus:wait_for_stanza(Alice), 2407: escalus:wait_for_stanzas(Bob, 3), 2408: Msg = <<"Hi, Bob!">>, 2409: Msg2 = <<"Hi, Alice!">>, 2410: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2411: escalus:wait_for_stanza(Alice), 2412: escalus:wait_for_stanza(Bob), 2413: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2414: escalus:wait_for_stanza(Alice), 2415: escalus:wait_for_stanza(Bob), 2416: 2417: %Eve enters and receives the presences, the message history and finally the topic 2418: escalus:send(Eve, stanza_muc_enter_room_history_setting(?config(room, Config), nick(Eve), <<"seconds">>,<<"3">>)), 2419: escalus:wait_for_stanza(Alice), 2420: escalus:wait_for_stanza(Bob), 2421: escalus:wait_for_stanzas(Eve, 3), %presences 2422: is_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Eve)), 2423: escalus:wait_for_stanza(Eve), %topic 2424: escalus_assert:has_no_stanzas(Alice), 2425: escalus_assert:has_no_stanzas(Bob), 2426: escalus_assert:has_no_stanzas(Eve) 2427: end). 2428: 2429: %Example 40 2430: %should fail - unfinished, needs to be improved 2431: history_since(ConfigIn) -> 2432: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2433: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2434: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2435: escalus:wait_for_stanzas(Alice, 2), 2436: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2437: escalus:wait_for_stanza(Alice), 2438: escalus:wait_for_stanzas(Bob, 3), 2439: Msg = <<"Hi, Bob!">>, 2440: Msg2 = <<"Hi, Alice!">>, 2441: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2442: escalus:wait_for_stanza(Alice), 2443: escalus:wait_for_stanza(Bob), 2444: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2445: escalus:wait_for_stanza(Alice), 2446: escalus:wait_for_stanza(Bob), 2447: 2448: % Kate enters and receives the presences, the message history and finally the topic 2449: escalus:send(Kate, stanza_muc_enter_room_history_setting(?config(room, Config), nick(Kate), <<"since">>,<<"1970-01-01T00:00:00Z">>)), 2450: escalus:wait_for_stanza(Alice), 2451: escalus:wait_for_stanza(Bob), 2452: escalus:wait_for_stanzas(Kate, 3), %presences 2453: is_history_message_correct(?config(room, Config), nick(Alice),<<"groupchat">>,Msg, escalus:wait_for_stanza(Kate)), 2454: is_history_message_correct(?config(room, Config), nick(Bob),<<"groupchat">>,Msg2, escalus:wait_for_stanza(Kate)), 2455: escalus:wait_for_stanza(Kate), %topic 2456: escalus_assert:has_no_stanzas(Alice), 2457: escalus_assert:has_no_stanzas(Bob), 2458: escalus_assert:has_no_stanzas(Kate) 2459: end). 2460: 2461: %Example 41 2462: %Fails - server should not send the history 2463: no_history(Config) -> 2464: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2465: escalus:send(Alice , stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2466: escalus:wait_for_stanzas(Alice, 2), 2467: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2468: escalus:wait_for_stanza(Alice), 2469: escalus:wait_for_stanzas(Bob, 3), 2470: Msg = <<"Hi, Bob!">>, 2471: Msg2 = <<"Hi, Alice!">>, 2472: escalus:send(Alice,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 2473: escalus:wait_for_stanza(Alice), 2474: escalus:wait_for_stanza(Bob), 2475: escalus:send(Bob,escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg2)), 2476: escalus:wait_for_stanza(Alice), 2477: escalus:wait_for_stanza(Bob), 2478: 2479: % Eve enters and receives the presences, the message history and finally the topic 2480: escalus:send(Eve, stanza_muc_enter_room_history_setting(?config(room, Config), nick(Eve), <<"maxchars">>,<<"0">>)), 2481: escalus:wait_for_stanza(Alice), 2482: escalus:wait_for_stanza(Bob), 2483: escalus:wait_for_stanzas(Eve, 3), %presences 2484: escalus:wait_for_stanza(Eve), %topic 2485: timer:wait(5000), 2486: escalus_assert:has_no_stanzas(Alice), 2487: escalus_assert:has_no_stanzas(Bob), 2488: escalus_assert:has_no_stanzas(Eve) 2489: end). 2490: 2491: %Example 42 2492: subject(ConfigIn) -> 2493: RoomOpts = [{subject, ?SUBJECT}], 2494: UserSpecs = [{alice, 0}, {bob, 1}], 2495: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 2496: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2497: escalus:wait_for_stanza(Bob), 2498: Stanza = escalus:wait_for_stanza(Bob), 2499: Subject = exml_query:path(Stanza, [{element, <<"subject">>}, cdata]), 2500: Subject == ?SUBJECT, 2501: TimeStamp = exml_query:path(Stanza, [{element, <<"delay">>}, {attr, <<"stamp">>}]), 2502: SystemTime = calendar:rfc3339_to_system_time(binary_to_list(TimeStamp), [{unit, second}]), 2503: true = is_integer(SystemTime) 2504: end). 2505: 2506: %Example 43 2507: %Fails - the message should contain an empty subject element 2508: no_subject(ConfigIn)-> 2509: UserSpecs = [{alice, 0}, {bob, 1}], 2510: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Bob) -> 2511: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2512: escalus:wait_for_stanza(Bob), 2513: #xmlel{children = []} = exml_query:subelement(escalus:wait_for_stanza(Bob), <<"subject">>) 2514: end). 2515: 2516: %Example 44, 45 2517: send_to_all(ConfigIn) -> 2518: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2519: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2520: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2521: escalus:wait_for_stanzas(Bob, 2), 2522: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2523: escalus:wait_for_stanza(Bob), 2524: escalus:wait_for_stanzas(Kate, 3), 2525: 2526: Msg = <<"chat message">>, 2527: Id = <<"MyID">>, 2528: Stanza = escalus_stanza:set_id( 2529: escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg), Id), 2530: escalus:send(Kate, Stanza), 2531: BobStanza = escalus:wait_for_stanza(Bob), 2532: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Kate), <<"groupchat">>, Msg, BobStanza), 2533: Id = exml_query:attr(BobStanza, <<"id">>), 2534: KateStanza = escalus:wait_for_stanza(Kate), 2535: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Kate), <<"groupchat">>, Msg, KateStanza), 2536: Id = exml_query:attr(KateStanza, <<"id">>), 2537: escalus_assert:has_no_stanzas(Bob), 2538: escalus_assert:has_no_stanzas(Kate) 2539: end). 2540: 2541: 2542: %Examples 46, 47 2543: send_and_receive_private_message_client_with_x_elem(ConfigIn) -> 2544: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2545: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2546: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2547: escalus:wait_for_stanzas(Bob, 2), 2548: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2549: escalus:wait_for_stanzas(Kate, 3), 2550: escalus:wait_for_stanza(Bob), 2551: 2552: Msg = <<"chat message">>, 2553: ChatMessage = stanza_private_muc_message(room_address(?config(room, Config), escalus_utils:get_username(Kate)), Msg), 2554: true = has_x_elem(ChatMessage), 2555: escalus:send(Bob, ChatMessage), 2556: IncomingMessage = escalus:wait_for_stanza(Kate), 2557: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Bob), <<"chat">>, Msg, IncomingMessage), 2558: true = has_x_elem(IncomingMessage), 2559: escalus_assert:has_no_stanzas(Bob), 2560: escalus_assert:has_no_stanzas(Kate) 2561: end). 2562: 2563: send_and_receive_private_message_client_without_x_elem(ConfigIn) -> 2564: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2565: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2566: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2567: escalus:wait_for_stanzas(Bob, 2), 2568: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2569: escalus:wait_for_stanzas(Kate, 3), 2570: escalus:wait_for_stanza(Bob), 2571: 2572: Msg = <<"chat message">>, 2573: ChatMessage = escalus_stanza:chat_to(room_address(?config(room, Config), escalus_utils:get_username(Kate)), Msg), 2574: false = has_x_elem(ChatMessage), 2575: escalus:send(Bob, ChatMessage), 2576: IncomingMessage = escalus:wait_for_stanza(Kate), 2577: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Bob), <<"chat">>, Msg, IncomingMessage), 2578: true = has_x_elem(IncomingMessage), 2579: escalus_assert:has_no_stanzas(Bob), 2580: escalus_assert:has_no_stanzas(Kate) 2581: end). 2582: 2583: %Example 48 2584: send_private_groupchat(ConfigIn) -> 2585: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2586: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2587: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2588: escalus:wait_for_stanzas(Bob, 2), 2589: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2590: escalus:wait_for_stanza(Bob), 2591: escalus:wait_for_stanzas(Kate, 3), 2592: 2593: Msg = <<"chat message">>, 2594: ChatMessage = escalus_stanza:groupchat_to(room_address(?config(room, Config), nick(Kate)), Msg), 2595: escalus:send(Bob, ChatMessage), 2596: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"modify">>, <<"bad-request">>), 2597: 2598: escalus:send(Bob,escalus_stanza:chat_to(room_address(?config(room, Config), <<"non-existent">>), Msg)), 2599: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"cancel">>, <<"item-not-found">>), 2600: 2601: escalus:send(Alice,escalus_stanza:chat_to(room_address(?config(room, Config), nick(Bob)), Msg)), 2602: escalus_assert:is_error(escalus:wait_for_stanza(Alice), <<"modify">>, <<"not-acceptable">>), 2603: 2604: escalus_assert:has_no_stanzas(Bob), 2605: escalus_assert:has_no_stanzas(Kate) 2606: end). 2607: 2608: %Examples 49, 50 2609: % Fails - no 110 status code 2610: change_nickname(ConfigIn) -> 2611: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2612: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2613: BobNick = escalus_utils:get_username(Bob), 2614: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), BobNick)), 2615: escalus:wait_for_stanzas(Bob, 2), 2616: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2617: escalus:wait_for_stanza(Bob), 2618: escalus:wait_for_stanzas(Kate, 3), 2619: 2620: escalus:send(Bob, stanza_change_nick(?config(room, Config), <<"newbob">>)), 2621: Presence = escalus:wait_for_stanza(Bob), 2622: has_status_codes(Presence, [<<"110">>]), 2623: is_nick_unavailable_correct(?config(room, Config), BobNick, <<"newbob">>, escalus:wait_for_stanza(Kate)), 2624: is_nick_unavailable_correct(?config(room, Config), BobNick, <<"newbob">>, Presence), 2625: is_nick_update_correct(?config(room, Config), <<"newbob">>, escalus:wait_for_stanza(Kate)), 2626: Presence2 = escalus:wait_for_stanza(Bob), 2627: is_nick_update_correct(?config(room, Config), <<"newbob">>, Presence2), 2628: has_status_codes(Presence2, [<<"110">>]) 2629: end). 2630: 2631: %Example 51 2632: %How to set up nickname change policy? 2633: 2634: %Example 52 2635: deny_nickname_change_conflict(ConfigIn) -> 2636: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2637: story_with_room(ConfigIn, [], UserSpecs, fun(Config, _Alice, Bob, Kate) -> 2638: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 2639: escalus:wait_for_stanzas(Bob, 2), 2640: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"eve">>)), 2641: escalus:wait_for_stanza(Bob), 2642: escalus:wait_for_stanzas(Kate, 3), 2643: escalus:send(Bob, stanza_change_nick(?config(room, Config), <<"eve">>)), 2644: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"cancel">>, <<"conflict">>) 2645: end). 2646: 2647: %Example 53 2648: %how to lock down the roomnicks? 2649: 2650: %Example 54, 55 2651: %Full JID is not sent to participants, just to the owner. Assumess this to be the default configuration 2652: change_availability_status(ConfigIn) -> 2653: UserSpecs = [{alice, 1}, {bob, 1}], 2654: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob) -> 2655: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), nick(Bob))), 2656: escalus:wait_for_stanzas(Bob, 2), 2657: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2658: escalus:wait_for_stanza(Bob), 2659: escalus:wait_for_stanzas(Alice, 3), 2660: Status = <<"Bobs awesome new status">>, 2661: escalus:send(Bob, stanza_change_availability(Status, ?config(room, Config), nick(Bob))), 2662: is_availability_status_notification_correct(?config(room, Config), nick(Bob), Status, escalus:wait_for_stanza(Bob)), 2663: Notification = escalus:wait_for_stanza(Alice), 2664: is_availability_status_notification_correct(?config(room, Config), nick(Bob), Status, Notification), 2665: Jid = escalus_utils:get_jid(Bob), 2666: Jid = exml_query:path(Notification, [{element, <<"x">>}, {element, <<"item">>}, {attr, <<"jid">>}]) 2667: end). 2668: 2669: 2670: % Direct Invitations (example 1 from XEP-0249) 2671: % This test only checks if the server routes properly such invitation. 2672: % There is no server-side logic for this XEP, but we want to advertise 2673: % that clients which supports this can work with MIM in such way. 2674: 2675: direct_invite(ConfigIn) -> 2676: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2677: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2678: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2679: escalus:wait_for_stanzas(Alice, 2), 2680: escalus:send(Alice, stanza_direct_invitation(?config(room, Config), Alice, Bob)), 2681: escalus:send(Alice, stanza_direct_invitation(?config(room, Config), Alice, Kate)), 2682: %Bob ignores the invitation, Kate accepts 2683: is_direct_invitation(escalus:wait_for_stanza(Bob)), 2684: is_direct_invitation(escalus:wait_for_stanza(Kate)), 2685: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), nick(Kate))), 2686: [S1, S2] = escalus:wait_for_stanzas(Kate, 2), 2687: is_presence_with_affiliation(S1, <<"owner">>), 2688: is_presence_with_affiliation(S2, <<"none">>) 2689: end). 2690: 2691: %Example 56-59 2692: mediated_invite(ConfigIn) -> 2693: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2694: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2695: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), nick(Alice))), 2696: escalus:wait_for_stanzas(Alice, 2), 2697: escalus:send(Alice, stanza_mediated_invitation(?config(room, Config), Bob)), 2698: escalus:send(Alice, stanza_mediated_invitation(?config(room, Config), Kate)), 2699: %Bob ignores the invitation, Kate formally declines 2700: is_invitation(escalus:wait_for_stanza(Bob)), 2701: is_invitation(escalus:wait_for_stanza(Kate)), 2702: escalus:send(Kate, stanza_mediated_invitation_decline(?config(room, Config), Alice)), 2703: is_invitation_decline(escalus:wait_for_stanza(Alice)) 2704: end). 2705: 2706: %Example 60-65 2707: %No <thread> tag, so right now this does not test any new functionality. The thread 2708: %tag is recommended, but not required, so the test will not fail because of its absence 2709: %Also - the examples contain neither configuration of the room not confirmation that it 2710: %is supposed to be instant. Thit test assumes that an instant room should be created 2711: one2one_chat_to_muc(Config) -> 2712: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Eve) -> 2713: Msg1 = escalus_stanza:chat_to(Bob,<<"Hi,Bob!">>), 2714: Msg2 = escalus_stanza:chat_to(Alice,<<"Hi,Alice!">>), 2715: escalus:send(Alice, Msg1), 2716: escalus:send(Bob, Msg2), 2717: escalus:wait_for_stanza(Alice), 2718: escalus:wait_for_stanza(Bob), 2719: 2720: %Alice creates a room 2721: Room = <<"alicesroom">>, 2722: escalus:send(Alice,stanza_muc_enter_room(Room, <<"alice">>)), 2723: was_room_created(escalus:wait_for_stanza(Alice)), 2724: 2725: escalus:send(Alice, stanza_instant_room(Room)), 2726: escalus:wait_for_stanza(Alice), %topic 2727: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)), 2728: 2729: %Alice sends history to the room 2730: NewMsg1 = escalus_stanza:setattr(Msg1, <<"type">>, <<"groupchat">>), 2731: %print(stanza_to_room(NewMsg1,Room)), 2732: escalus:send(Alice, stanza_to_room(NewMsg1,Room)), 2733: NewMsg2 = escalus_stanza:setattr(Msg2, <<"type">>, <<"groupchat">>), 2734: escalus:send(Alice, stanza_to_room(NewMsg2,Room)), 2735: 2736: %Alice sends invitations 2737: %invitations should include contiue flag, but this makes no sense without the thread 2738: escalus:send(Alice, stanza_mediated_invitation_multi(Room, [Bob, Eve])), 2739: is_invitation(escalus:wait_for_stanza(Bob)), 2740: is_invitation(escalus:wait_for_stanza(Eve)), 2741: %Bob and Eve accept the invitations 2742: escalus:send(Bob, stanza_muc_enter_room(Room, <<"bob">>)), 2743: escalus:wait_for_stanzas(Bob, 2), 2744: escalus:send(Eve, stanza_muc_enter_room(Room, <<"eve">>)), 2745: escalus:wait_for_stanzas(Eve, 3), %presences 2746: %Bob and Eve receive the history 2747: is_history_message_correct(Room, <<"alice">>,<<"groupchat">>,<<"Hi,Bob!">>, escalus:wait_for_stanza(Bob)), 2748: is_history_message_correct(Room, <<"alice">>,<<"groupchat">>,<<"Hi,Alice!">>, escalus:wait_for_stanza(Bob)), 2749: is_history_message_correct(Room, <<"alice">>,<<"groupchat">>,<<"Hi,Bob!">>, escalus:wait_for_stanza(Eve)), 2750: is_history_message_correct(Room, <<"alice">>,<<"groupchat">>,<<"Hi,Alice!">>, escalus:wait_for_stanza(Eve)), 2751: escalus:wait_for_stanzas(Alice, 2), %messages 2752: escalus:wait_for_stanzas(Alice, 2), %presences 2753: escalus:wait_for_stanzas(Bob, 2), %topic & Eves presence 2754: escalus:wait_for_stanzas(Eve, 1), %topic 2755: escalus_assert:has_no_stanzas(Alice), 2756: escalus_assert:has_no_stanzas(Bob), 2757: escalus_assert:has_no_stanzas(Eve) 2758: end). 2759: 2760: 2761: %%-------------------------------------------------------------------- 2762: %% Registration at a server 2763: %%-------------------------------------------------------------------- 2764: 2765: %% You send the register IQ to room jid. 2766: %% But in MongooseIM you need to send it to "muc@host". 2767: user_asks_for_registration_form(Config) -> 2768: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2769: ?assert_equal(<<>>, get_nick(Alice)) 2770: end). 2771: 2772: %% Example 71. User Submits Registration Form 2773: %% You send the register IQ to room jid "muc@host/room". 2774: %% But in MongooseIM you need to send it to "muc@host". 2775: user_submits_registration_form(Config) -> 2776: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2777: Nick = fresh_nick_name(<<"thirdwitch">>), 2778: set_nick(Alice, Nick), 2779: ?assert_equal(Nick, get_nick(Alice)) 2780: end). 2781: 2782: user_submits_registration_form_over_s2s(Config) -> 2783: escalus:fresh_story(Config, [{alice2, 1}], fun(Alice) -> 2784: Nick = fresh_nick_name(<<"thirdwitch">>), 2785: set_nick(Alice, Nick), 2786: ?assert_equal(Nick, get_nick(Alice)) 2787: end). 2788: 2789: user_submits_registration_form_twice(Config) -> 2790: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2791: Nick = fresh_nick_name(<<"thirdwitch">>), 2792: set_nick(Alice, Nick), 2793: ?assert_equal(Nick, get_nick(Alice)), 2794: 2795: set_nick(Alice, Nick), 2796: ?assert_equal(Nick, get_nick(Alice)) 2797: end). 2798: 2799: user_changes_nick(Config) -> 2800: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2801: Nick1 = fresh_nick_name(<<"thirdwitch1">>), 2802: Nick2 = fresh_nick_name(<<"thirdwitch2">>), 2803: set_nick(Alice, Nick1), 2804: ?assert_equal(Nick1, get_nick(Alice)), 2805: 2806: set_nick(Alice, Nick2), 2807: ?assert_equal(Nick2, get_nick(Alice)) 2808: end). 2809: 2810: user_unregisters_nick(Config) -> 2811: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2812: Nick = fresh_nick_name(<<"thirdwitch1">>), 2813: set_nick(Alice, Nick), 2814: ?assert_equal(Nick, get_nick(Alice)), 2815: 2816: unset_nick(Alice), 2817: ?assert_equal(<<>>, get_nick(Alice)) 2818: end). 2819: 2820: user_unregisters_nick_twice(Config) -> 2821: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 2822: Nick = fresh_nick_name(<<"thirdwitch1">>), 2823: set_nick(Alice, Nick), 2824: ?assert_equal(Nick, get_nick(Alice)), 2825: 2826: unset_nick(Alice), 2827: ?assert_equal(<<>>, get_nick(Alice)), 2828: 2829: unset_nick(Alice), 2830: ?assert_equal(<<>>, get_nick(Alice)) 2831: end). 2832: 2833: user_cancels_registration(Config) -> 2834: escalus:fresh_story( 2835: Config, [{alice, 1}], 2836: fun(Alice) -> 2837: Form = form_helper:form(#{type => <<"cancel">>}), 2838: SetIQ = escalus_stanza:iq_set(?NS_INBAND_REGISTER, [Form]), 2839: Req = escalus_stanza:to(SetIQ, muc_helper:muc_host()), 2840: escalus:send_iq_and_wait_for_result(Alice, Req) 2841: end). 2842: 2843: user_registration_errors(Config) -> 2844: escalus:fresh_story( 2845: Config, [{alice, 1}], 2846: fun(Alice) -> 2847: Nick = fresh_nick_name(<<"thirdwitch">>), 2848: Req = change_nick_form_iq(Nick), 2849: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 2850: escalus:send_and_wait(Alice, form_helper:remove_form_types(Req))), 2851: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 2852: escalus:send_and_wait(Alice, form_helper:remove_form_ns(Req))), 2853: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 2854: escalus:send_and_wait(Alice, form_helper:remove_forms(Req))), 2855: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], 2856: escalus:send_and_wait(Alice, form_helper:remove_fields(Req, <<"nick">>))) 2857: end). 2858: 2859: %%-------------------------------------------------------------------- 2860: %% Registration in a room 2861: %%-------------------------------------------------------------------- 2862: 2863: %%Examples 66-76 2864: %%Registartion feature is not implemented 2865: %%TODO: create a differend group for the registration test cases (they will fail) 2866: %registration_request(Config) -> 2867: % escalus:story(Config, [{alice, 1}, {bob, 1}], fun(_Alice, Bob) -> 2868: % escalus:send(Bob, stanza_to_room(escalus_stanza:iq_get(<<"jabber:iq:register">>, []), ?config(room, Config))), 2869: % print_next_message(Bob) 2870: % end). 2871: % 2872: %%Example 67 2873: %registration_request_no_room(Config) -> 2874: % escalus:story(Config, [{alice, 1}, {bob, 1}], fun(_Alice, Bob) -> 2875: % escalus:send(Bob, stanza_to_room(escalus_stanza:iq_get(<<"jabber:iq:register">>, []), <<"non-existent-room">>)), 2876: % escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], escalus:wait_for_stanza(Bob)) 2877: % end). 2878: % 2879: %stanza_reserved_nickname_request() -> 2880: % escalus_stanza:iq(<<"get">>, [#xmlel{ 2881: % name = <<"query">>, 2882: % attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/disco#info">>}, {<<"node">>, <<"x-roomuser-item">>}], 2883: % children = [] 2884: % }]). 2885: % 2886: %%Example 77-78 2887: %%Not implemented - the 'node' element is ignored 2888: %reserved_nickname_request(Config) -> 2889: % escalus:story(Config, [{alice, 1}, {bob, 1}], fun(_Alice, Bob) -> 2890: % %escalus:send(Bob, stanza_to_room(escalus_stanza:iq_get(<<"jabber:iq:register">>, []), ?config(room, Config))), 2891: % %print_next_message(Bob) 2892: % print(stanza_to_room(stanza_reserved_nickname_request(), ?config(room, Config))), 2893: % escalus:send(Bob, (stanza_to_room(stanza_reserved_nickname_request(), ?config(room, Config)))), 2894: % print_next_message(Bob) 2895: % end). 2896: 2897: %Examlple 79 2898: %Does not work - tested elsewhere (Examples 108 - 109) 2899: %Unfinished - need to check if the form that shoudl be sent back (but isn't) is correct is correct 2900: 2901: 2902: %Example 80-82 2903: %No 110 status code in self-presence messages 2904: %No Jid, not event when the owner leaves tehe room (normally the owner receives senders jid along with a message 2905: exit_room(ConfigIn) -> 2906: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2907: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2908: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Alice))), 2909: escalus:wait_for_stanzas(Alice, 2), 2910: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2911: escalus:wait_for_stanzas(Bob, 3), 2912: escalus:wait_for_stanza(Alice), 2913: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2914: escalus:wait_for_stanzas(Kate, 4), 2915: escalus:wait_for_stanza(Alice), 2916: escalus:wait_for_stanza(Bob), 2917: escalus:send(Alice, stanza_to_room(escalus_stanza:presence(<<"unavailable">>), ?config(room, Config), escalus_utils:get_username(Alice))), 2918: Message = escalus:wait_for_stanza(Alice), 2919: has_status_codes(Message, [<<"110">>]), 2920: assert_is_exit_message_correct(Alice, <<"owner">>, ?config(room, Config), Message), 2921: assert_is_exit_message_correct(Alice, <<"owner">>, ?config(room, Config), escalus:wait_for_stanza(Bob)), 2922: assert_is_exit_message_correct(Alice, <<"owner">>, ?config(room, Config), escalus:wait_for_stanza(Kate)) 2923: end). 2924: 2925: 2926: 2927: %Example 80-83 2928: %No 110 status code in self-presence messages 2929: exit_room_with_status(ConfigIn) -> 2930: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2931: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2932: 2933: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Alice))), 2934: escalus:wait_for_stanzas(Alice, 2), 2935: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 2936: escalus:wait_for_stanzas(Bob, 3), 2937: escalus:wait_for_stanza(Alice), 2938: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 2939: escalus:wait_for_stanzas(Kate, 4), 2940: escalus:wait_for_stanza(Alice), 2941: escalus:wait_for_stanza(Bob), 2942: 2943: Status = <<"Alices exit status">>, 2944: StatusXml = #xmlel{name = <<"status">>, children = [#xmlcdata{content=Status}]}, 2945: Presence = escalus_stanza:presence(<<"unavailable">>), 2946: Presence2 = Presence#xmlel{children=[StatusXml]}, 2947: Stanza = stanza_to_room(Presence2, ?config(room, Config), escalus_utils:get_username(Alice)), 2948: escalus:send(Alice, Stanza), 2949: Message = escalus:wait_for_stanza(Alice), 2950: has_status_codes(Message, [<<"110">>]), 2951: is_exit_message_with_status_correct(Alice, <<"owner">>, ?config(room, Config), Status, Message), 2952: is_exit_message_with_status_correct(Alice, <<"owner">>, ?config(room, Config), Status, escalus:wait_for_stanza(Bob)), 2953: is_exit_message_with_status_correct(Alice, <<"owner">>, ?config(room, Config), Status, escalus:wait_for_stanza(Kate)) 2954: end). 2955: 2956: %% GIVEN Kate in the room, to ensure that the room does not get stopped 2957: %% WHEN Bob sends malformed presence 2958: %% THAN Bob gets kicked. Join Alice to check that Bob is not in the room. Kate and Bob receive presence unavailable. 2959: kicked_after_sending_malformed_presence(ConfigIn) -> 2960: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 2961: story_with_room(ConfigIn, [], UserSpecs, fun(Config, Alice, Bob, Kate) -> 2962: 2963: %% GIVEN Kate in the room, to ensure that the room does not get stopped 2964: Room = ?config(room, Config), 2965: KateUsername = escalus_utils:get_username(Kate), 2966: KateStanza = stanza_muc_enter_room(Room, KateUsername), 2967: escalus:send(Kate, KateStanza), 2968: KatePresence = escalus:wait_for_stanza(Kate), 2969: is_self_presence(Kate, ?config(room, Config),KatePresence), 2970: 2971: Username = escalus_utils:get_username(Bob), 2972: Stanza = stanza_muc_enter_room(Room, Username), 2973: escalus:send(Bob, Stanza), 2974: escalus:wait_for_stanza(Bob), 2975: is_presence_from(Bob, ?config(room, Config),escalus:wait_for_stanza(Bob)), 2976: %% WHEN Bob sends a malformed presence 2977: Error = stanza_to_room(escalus_stanza:presence(<<"error">>), Room, Username), 2978: escalus:send(Bob, Error), 2979: 2980: %% THEN He is kicked from the room 2981: escalus:wait_for_stanza(Bob), 2982: BobStanza = escalus:wait_for_stanza(Bob), 2983: escalus:assert(is_presence_with_type, [<<"unavailable">>], BobStanza), 2984: escalus:assert(is_stanza_from, [room_address(Room, Username)], BobStanza), 2985: 2986: %% THEN He is actually kicked 2987: %% Alice should not receive his presence 2988: AliceUsername = escalus_utils:get_username(Alice), 2989: AliceStanza = stanza_muc_enter_room(Room, AliceUsername), 2990: escalus:send(Alice, AliceStanza), 2991: escalus:wait_for_stanza(Alice), 2992: is_self_presence(Alice, ?config(room, Config), escalus:wait_for_stanza(Alice)), 2993: escalus:assert(is_message, escalus:wait_for_stanza(Alice)), %% subject 2994: ok 2995: end). 2996: 2997: %%------------------------------------------------------------------- 2998: %% Tests 2999: %%-------------------------------------------------------------------- 3000: 3001: disco_service(Config) -> 3002: disco_service_story(Config). 3003: 3004: disco_features(Config) -> 3005: disco_features_story(Config, [?NS_DISCO_INFO, 3006: ?NS_DISCO_ITEMS, 3007: ?NS_MUC, 3008: ?NS_MUC_UNIQUE, 3009: ?NS_INBAND_REGISTER, 3010: ?NS_RSM, 3011: ?NS_VCARD, 3012: ?NS_JABBER_X_CONF]). 3013: 3014: disco_features_with_mam(Config) -> 3015: disco_features_story(Config, [?NS_DISCO_INFO, 3016: ?NS_DISCO_ITEMS, 3017: ?NS_MUC, 3018: ?NS_MUC_UNIQUE, 3019: ?NS_INBAND_REGISTER, 3020: ?NS_RSM, 3021: ?NS_VCARD, 3022: ?NS_JABBER_X_CONF | 3023: mam_helper:namespaces()]). 3024: 3025: disco_rooms(Config) -> 3026: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3027: Room = <<"persistentroom">>, 3028: Host = muc_host(), 3029: ok = rpc(mim(), mod_muc, store_room, [host_type(), Host, Room, []]), 3030: 3031: escalus:send(Alice, stanza_get_rooms()), 3032: %% we should have room room_address(<<"aliceroom">>), created in init 3033: Stanza = escalus:wait_for_stanza(Alice), 3034: true = has_room(room_address(<<"alicesroom">>), Stanza), 3035: true = has_room(room_address(<<"persistentroom">>), Stanza), 3036: escalus:assert(is_stanza_from, [muc_host()], Stanza), 3037: ok = rpc(mim(), mod_muc, forget_room, [host_type(), Host, Room]) 3038: end). 3039: 3040: disco_info(Config) -> 3041: muc_helper:disco_info_story(Config, muc_namespaces()). 3042: 3043: disco_info_with_mam(Config) -> 3044: muc_helper:disco_info_story(Config, muc_namespaces() ++ mam_helper:namespaces()). 3045: 3046: muc_namespaces() -> 3047: [?NS_MUC, 3048: ?NS_MUC_STABLE_ID, 3049: <<"muc_public">>, 3050: <<"muc_persistent">>, 3051: <<"muc_open">>, 3052: <<"muc_semianonymous">>, 3053: <<"muc_moderated">>, 3054: <<"muc_unsecured">>]. 3055: 3056: disco_items(Config) -> 3057: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 3058: escalus:send(Alice, stanza_join_room(<<"alicesroom">>, <<"nicenick">>)), 3059: _Stanza = escalus:wait_for_stanza(Alice), 3060: 3061: %% works because the list is public 3062: _Stanza2 = escalus:send_iq_and_wait_for_result( 3063: Bob, stanza_to_room(escalus_stanza:iq_get(?NS_DISCO_ITEMS,[]), <<"alicesroom">>)) 3064: end). 3065: 3066: disco_items_nonpublic(ConfigIn) -> 3067: RoomOpts = [{persistent, true}, {public_list, false}], 3068: UserSpecs = [{alice, 1}, {bob, 1}], 3069: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob) -> 3070: 3071: RoomName = ?config(room, Config), 3072: escalus:send(Alice, stanza_join_room(RoomName, <<"nicenick">>)), 3073: _Stanza = escalus:wait_for_stanza(Alice), 3074: 3075: %% does not work because the list is not public and Bob is not an occupant 3076: escalus:send(Bob, stanza_to_room(escalus_stanza:iq_get(?NS_DISCO_ITEMS,[]), RoomName)), 3077: Error = escalus:wait_for_stanza(Bob), 3078: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error) 3079: end). 3080: 3081: 3082: create_and_destroy_room(Config) -> 3083: escalus:story(Config, [{alice, 1}], fun(Alice) -> 3084: Room1 = stanza_join_room(<<"room1">>, <<"nick1">>), 3085: escalus:send(Alice, Room1), 3086: was_room_created(escalus:wait_for_stanza(Alice)), 3087: escalus:wait_for_stanza(Alice), 3088: 3089: DestroyRoom1 = stanza_destroy_room(<<"room1">>), 3090: escalus:send(Alice, DestroyRoom1), 3091: [Presence, Iq] = escalus:wait_for_stanzas(Alice, 2), 3092: was_room_destroyed(Iq), 3093: was_destroy_presented(Presence) 3094: end). 3095: 3096: 3097: %% test if we are able to create room when presence has more than one subelemnets 3098: %% https://github.com/esl/MongooseIM/issues/376 3099: create_and_destroy_room_multiple_x_elements(Config) -> 3100: escalus:story(Config, [{alice, 1}], fun(Alice) -> 3101: Room2 = stanza_join_room_many_x_elements(<<"room2">>, <<"nick2">>), 3102: escalus:send(Alice, Room2), 3103: was_room_created(escalus:wait_for_stanza(Alice)), 3104: escalus:wait_for_stanza(Alice), 3105: 3106: DestroyRoom2 = stanza_destroy_room(<<"room2">>), 3107: escalus:send(Alice, DestroyRoom2), 3108: [Presence, Iq] = escalus:wait_for_stanzas(Alice, 2), 3109: was_room_destroyed(Iq), 3110: was_destroy_presented(Presence) 3111: end). 3112: 3113: %% DOES NOT FAIL ANYMORE 3114: %% Example 152. Service Informs User of Inability to Create a Room 3115: %% As of writing this testcase (2012-07-24) it fails. Room is not created 3116: %% as expected, but the returned error message is not the one specified by XEP. 3117: %% ejabberd returns 'forbidden' while it ought to return 'not-allowed'. 3118: room_creation_not_allowed(Config) -> 3119: escalus:story(Config, [{alice, 1}], fun(Alice) -> 3120: escalus:send(Alice, stanza_enter_room(<<"room1">>, <<"nick1">>)), 3121: escalus:assert(is_error, [<<"cancel">>, <<"not-allowed">>], 3122: escalus:wait_for_stanza(Alice)) 3123: end). 3124: 3125: %% Fails. 3126: cant_enter_locked_room(Config) -> 3127: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 3128: 3129: %% Create the room (should be locked on creation) 3130: RoomName = fresh_room_name(), 3131: escalus:send(Alice, stanza_muc_enter_room(RoomName, 3132: <<"alice-the-owner">>)), 3133: Presence = escalus:wait_for_stanza(Alice), 3134: was_room_created(Presence), 3135: 3136: %% Bob should not be able to join the room 3137: escalus:send(Bob, stanza_enter_room(RoomName, <<"just-bob">>)), 3138: R = escalus:wait_for_stanza(Bob), 3139: %% sometime the predicate itself should be moved to escalus 3140: escalus:assert(fun ?MODULE:is_room_locked/1, R) 3141: end). 3142: 3143: %% Example 155. Owner Requests Instant Room 3144: create_instant_room(Config) -> 3145: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 3146: 3147: %% Create the room (should be locked on creation) 3148: RoomName = fresh_room_name(), 3149: Presence = stanza_muc_enter_room(RoomName, <<"alice-the-owner">>), 3150: escalus:send(Alice, Presence), 3151: was_room_created(escalus:wait_for_stanza(Alice)), 3152: 3153: escalus:wait_for_stanza(Alice), % topic 3154: 3155: escalus:send_iq_and_wait_for_result(Alice, stanza_instant_room(RoomName)), 3156: 3157: %% Bob should be able to join the room 3158: escalus:send(Bob, stanza_muc_enter_room(RoomName, <<"bob">>)), 3159: escalus:wait_for_stanza(Alice), %Bobs presence 3160: %% Bob should receive (in that order): Alices presence, his presence and the topic 3161: 3162: Preds = [fun(Stanza) -> escalus_pred:is_presence(Stanza) andalso 3163: escalus_pred:is_stanza_from(room_address(RoomName, <<"bob">>), Stanza) 3164: end, 3165: fun(Stanza) -> escalus_pred:is_presence(Stanza) andalso 3166: escalus_pred:is_stanza_from(room_address(RoomName, <<"alice-the-owner">>), Stanza) 3167: end], 3168: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 3169: escalus:wait_for_stanza(Bob), %topic 3170: escalus_assert:has_no_stanzas(Bob), 3171: escalus_assert:has_no_stanzas(Alice) 3172: end). 3173: 3174: create_instant_persistent_room(Config) -> 3175: RoomName = fresh_room_name(), 3176: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], 3177: fun(Alice, Bob) -> 3178: create_instant_persistent_room(Alice, Bob, RoomName) 3179: end), 3180: destroy_room(muc_host(), RoomName), 3181: forget_room(host_type(), muc_host(), RoomName). 3182: 3183: create_instant_persistent_room(Alice, Bob, RoomName) -> 3184: {ok, _, Pid} = given_fresh_room_is_hibernated(Alice, RoomName, [{instant, true}]), 3185: leave_room(RoomName, Alice), 3186: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 3187: 3188: escalus:send(Bob, stanza_muc_enter_room(RoomName, <<"bob">>)), 3189: Presence = escalus:wait_for_stanza(Bob), 3190: true = is_presence_with_affiliation(Presence, <<"none">>), 3191: true = is_presence_with_role(Presence, <<"participant">>), % Alice is the owner 3192: escalus:assert(is_message, escalus:wait_for_stanza(Bob)), 3193: escalus_assert:has_no_stanzas(Bob). 3194: 3195: destroy_locked_room(Config) -> 3196: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3197: RoomName = fresh_room_name(), 3198: Room1 = stanza_muc_enter_room(RoomName, <<"nick1">>), 3199: escalus:send(Alice, Room1), 3200: was_room_created(escalus:wait_for_stanza(Alice)), 3201: escalus:wait_for_stanza(Alice), 3202: 3203: DestroyRoom1 = stanza_destroy_room(RoomName), 3204: escalus:send(Alice, DestroyRoom1), 3205: [Presence, Iq] = escalus:wait_for_stanzas(Alice, 2), 3206: was_room_destroyed(Iq), 3207: was_destroy_presented(Presence) 3208: end). 3209: 3210: disco_info_locked_room(Config) -> 3211: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3212: %% GIVEN a new room is created (should be locked on creation) 3213: RoomName = fresh_room_name(), 3214: escalus:send(Alice, stanza_muc_enter_room(RoomName, <<"alice-the-owner">>)), 3215: was_room_created(escalus:wait_for_stanza(Alice)), 3216: 3217: %% WHEN the owner sends disco#info to the locked room 3218: escalus:wait_for_stanza(Alice), 3219: Stanza = escalus:send_iq_and_wait_for_result( 3220: Alice, stanza_to_room(escalus_stanza:iq_get(?NS_DISCO_INFO,[]), RoomName)), 3221: 3222: %% THEN receives MUC features 3223: Namespaces = [?NS_MUC, ?NS_MUC_STABLE_ID, <<"muc_public">>, <<"muc_temporary">>, 3224: <<"muc_open">>, <<"muc_semianonymous">>, <<"muc_moderated">>, 3225: <<"muc_unsecured">>], 3226: has_features(Stanza, Namespaces) 3227: end). 3228: 3229: %% Example 156 3230: create_reserved_room(Config) -> 3231: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3232: %% Create the room (should be locked on creation) 3233: RoomName = fresh_room_name(), 3234: escalus:send(Alice, stanza_muc_enter_room(RoomName, 3235: <<"alice-the-owner">>)), 3236: was_room_created(escalus:wait_for_stanza(Alice)), 3237: 3238: escalus:wait_for_stanza(Alice), 3239: 3240: S = escalus:send_iq_and_wait_for_result(Alice, stanza_configuration_form_request(RoomName)), 3241: true = is_form(S) 3242: 3243: end). 3244: 3245: %% Example 162 3246: %% This test fails, room should be destroyed after sending cancel message 3247: reserved_room_cancel(Config) -> 3248: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3249: %% Create the room (should be locked on creation) 3250: RoomName = fresh_room_name(), 3251: escalus:send(Alice, stanza_muc_enter_room(RoomName, 3252: <<"alice-the-owner">>)), 3253: was_room_created(escalus:wait_for_stanza(Alice)), 3254: 3255: escalus:wait_for_stanza(Alice), 3256: 3257: S = escalus:send_iq_and_wait_for_result(Alice, stanza_configuration_form_request(RoomName)), 3258: true = is_form(S), 3259: 3260: %% Send cancel request 3261: escalus:send(Alice, stanza_cancel(RoomName)), 3262: 3263: %% Alice must receive presence 3264: escalus:assert(is_presence_with_type, [<<"unavailable">>], 3265: escalus:wait_for_stanza(Alice)) 3266: 3267: end). 3268: 3269: %% Example 161 3270: reserved_room_unacceptable(Config) -> 3271: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3272: %% Create the room (should be locked on creation) 3273: RoomName = fresh_room_name(), 3274: escalus:send(Alice, stanza_muc_enter_room(RoomName, 3275: <<"alice-the-owner">>)), 3276: was_room_created(escalus:wait_for_stanza(Alice)), 3277: 3278: escalus:wait_for_stanza(Alice), 3279: S = escalus:send_iq_and_wait_for_result(Alice, stanza_configuration_form_request(RoomName)), 3280: true = is_form(S), 3281: 3282: %% Configure room to be password protected, with empty secret 3283: Fields = [#{var => <<"muc#roomconfig_passwordprotectedroom">>, values => [<<"1">>], 3284: type => <<"boolean">>}, 3285: #{var => <<"muc#roomconfig_roomsecret">>, values => [<<>>], 3286: type => <<"text-single">>}], 3287: Form = stanza_configuration_form(RoomName, Fields), 3288: escalus:send(Alice, Form), 3289: 3290: R = escalus:wait_for_stanza(Alice), 3291: escalus:assert(is_error, [<<"modify">>, <<"not-acceptable">>], R), 3292: escalus:assert(is_stanza_from, [room_address(RoomName)], R) 3293: 3294: end). 3295: 3296: %% Example 159 3297: %% Mysterious thing: when room is named "room5", creation confirmation doesn't return status code 3298: reserved_room_configuration(Config) -> 3299: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3300: %% Create the room (should be locked on creation) 3301: RoomName = fresh_room_name(), 3302: escalus:send(Alice, stanza_muc_enter_room(RoomName, 3303: <<"alice-the-owner">>)), 3304: was_room_created(escalus:wait_for_stanza(Alice)), 3305: 3306: escalus:wait_for_stanza(Alice), 3307: S = escalus:send_iq_and_wait_for_result(Alice, stanza_configuration_form_request(RoomName)), 3308: true = is_form(S), 3309: 3310: %% Configure room to be moderated, public and persistent 3311: Fields = [#{var => <<"muc#roomconfig_publicroom">>, values => [<<"1">>], type => <<"boolean">>}, 3312: #{var => <<"muc#roomconfig_moderatedroom">>, values => [<<"1">>], type => <<"boolean">>}, 3313: #{var => <<"muc#roomconfig_persistentroom">>, values => [<<"1">>], type => <<"boolean">>}], 3314: Form = stanza_configuration_form(RoomName, Fields), 3315: Result = escalus:send_iq_and_wait_for_result(Alice, Form), 3316: escalus:assert(is_stanza_from, [room_address(RoomName)], Result), 3317: 3318: %% Check if it worked 3319: Stanza = escalus:send_iq_and_wait_for_result( 3320: Alice, stanza_to_room(escalus_stanza:iq_get(?NS_DISCO_INFO,[]), RoomName)), 3321: has_feature(Stanza, <<"muc_persistent">>), 3322: has_feature(Stanza, <<"muc_moderated">>), 3323: has_feature(Stanza, <<"muc_public">>), 3324: 3325: %% Destroy the room to clean up 3326: escalus:send(Alice, stanza_destroy_room(RoomName)), 3327: escalus:wait_for_stanzas(Alice, 2) 3328: end). 3329: 3330: %% Example 164 3331: %% This test doesn't fail anymore 3332: %% ejabberd used to return error with no type 3333: config_denial(ConfigIn) -> 3334: RoomOpts = [{persistent, true}], 3335: UserSpecs = [{alice, 0}, {bob, 1}], 3336: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 3337: %% Bob requests configuration form 3338: escalus:send(Bob, stanza_to_room( 3339: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3340: 3341: %% Bob should get an error 3342: Res = escalus:wait_for_stanza(Bob), 3343: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Res), 3344: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res) 3345: end). 3346: 3347: %% Example 166 3348: config_cancel(ConfigIn) -> 3349: RoomOpts = [{persistent, true}], 3350: UserSpecs = [{alice, 1}], 3351: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice) -> 3352: %% Alice requests configuration form 3353: escalus:send(Alice, stanza_to_room( 3354: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3355: 3356: %% Alice receives form 3357: Res = escalus:wait_for_stanza(Alice), 3358: true = is_form(Res), 3359: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res), 3360: 3361: %% Alice cancels form 3362: escalus:send_iq_and_wait_for_result(Alice, stanza_cancel(?config(room, Config))), 3363: 3364: RoomsIqResp = escalus:send_iq_and_wait_for_result( 3365: Alice, stanza_room_list_request(<<"id">>, undefined)), 3366: true = has_room(room_address(?config(room, Config)), RoomsIqResp) 3367: end). 3368: 3369: 3370: %% Ejabberd doesn't let set admins nor owners in configuration form so testcases for ex. 167-170 would be useless 3371: 3372: configure(ConfigIn) -> 3373: RoomOpts = [{persistent, true}], 3374: UserSpecs = [{alice, 1}], 3375: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice) -> 3376: %% Alice requests configuration form 3377: escalus:send(Alice, stanza_to_room( 3378: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3379: 3380: %% Alice receives form 3381: Res = escalus:wait_for_stanza(Alice), 3382: true = is_form(Res), 3383: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res), 3384: 3385: %% Configure room to be moderated, public and persistent 3386: Fields = [#{var => <<"muc#roomconfig_publicroom">>, values => [<<"1">>], type => <<"boolean">>}, 3387: #{var => <<"muc#roomconfig_moderatedroom">>, values => [<<"1">>], type => <<"boolean">>}, 3388: #{var => <<"muc#roomconfig_persistentroom">>, values => [<<"1">>], type => <<"boolean">>}], 3389: Form = stanza_configuration_form(?config(room, Config), Fields), 3390: Result = escalus:send_iq_and_wait_for_result(Alice, Form), 3391: escalus:assert(is_stanza_from, 3392: [room_address(?config(room, Config))], Result), 3393: 3394: %% Check if it worked 3395: Stanza = escalus:send_iq_and_wait_for_result( 3396: Alice, stanza_to_room(escalus_stanza:iq_get(?NS_DISCO_INFO,[]), ?config(room, Config))), 3397: has_feature(Stanza, <<"muc_persistent">>), 3398: has_feature(Stanza, <<"muc_moderated">>), 3399: has_feature(Stanza, <<"muc_public">>) 3400: end). 3401: 3402: configure_errors(ConfigIn) -> 3403: RoomOpts = [{persistent, true}], 3404: UserSpecs = [{alice, 1}], 3405: story_with_room( 3406: ConfigIn, RoomOpts, UserSpecs, 3407: fun(Config, Alice) -> 3408: Req = stanza_configuration_form(?config(room, Config), []), 3409: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 3410: escalus:send_and_wait(Alice, form_helper:remove_form_types(Req))), 3411: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 3412: escalus:send_and_wait(Alice, form_helper:remove_form_ns(Req))), 3413: escalus:assert(is_error, [<<"modify">>, <<"bad-request">>], 3414: escalus:send_and_wait(Alice, form_helper:remove_forms(Req))) 3415: end). 3416: 3417: %% Example 171 3418: %% This test needs enabled mod_muc_log module and {access_log, muc_create} in options 3419: %% This test fails, ejabberd doesn't seem to send status code when room privacy changes 3420: configure_logging(ConfigIn) -> 3421: RoomOpts = [{persistent, true}, {anonymous, true}], 3422: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3423: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3424: %% Bob joins room 3425: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Bob))), 3426: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), escalus_utils:get_username(Kate))), 3427: escalus:wait_for_stanzas(Bob, 3), 3428: escalus:wait_for_stanzas(Kate, 3), 3429: 3430: %% Alice requests configuration form 3431: escalus:send(Alice, stanza_to_room( 3432: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3433: 3434: %% Alice receives form 3435: Res = escalus:wait_for_stanza(Alice), 3436: true = is_form(Res), 3437: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res), 3438: 3439: %% Configure room with logging enabled 3440: Fields = [#{var => <<"muc#roomconfig_enablelogging">>, values => [<<"1">>], 3441: type => <<"boolean">>}], 3442: Form = stanza_configuration_form(?config(room, Config), Fields), 3443: Result = escalus:send_iq_and_wait_for_result(Alice, Form), 3444: escalus:assert(is_stanza_from, 3445: [room_address(?config(room, Config))], Result), 3446: 3447: Res2 = escalus:wait_for_stanza(Bob), 3448: true = is_message_with_status_code(Res2, <<"170">>), 3449: true = is_groupchat_message(Res2), 3450: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res2), 3451: 3452: escalus:wait_for_stanza(Kate), 3453: 3454: %% Alice requests configuration form again 3455: escalus:send(Alice, stanza_to_room( 3456: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3457: 3458: %% Alice receives form 3459: Res3 = escalus:wait_for_stanza(Alice), 3460: true = is_form(Res3), 3461: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res3), 3462: 3463: %% Simple message exchange 3464: Msg = <<"chat message">>, 3465: escalus:send(Bob, escalus_stanza:groupchat_to(room_address(?config(room, Config)), Msg)), 3466: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Bob), <<"groupchat">>, Msg, escalus:wait_for_stanza(Bob)), 3467: assert_is_message_correct(?config(room, Config), escalus_utils:get_username(Bob), <<"groupchat">>, Msg, escalus:wait_for_stanza(Kate)), 3468: 3469: %% Disable logging 3470: Fields2 = [#{var => <<"muc#roomconfig_enablelogging">>, values => [<<"0">>], type => <<"boolean">>}], 3471: Form2 = stanza_configuration_form(?config(room, Config), Fields2), 3472: Result2 = escalus:send_iq_and_wait_for_result(Alice, Form2), 3473: escalus:assert(is_stanza_from, 3474: [room_address(?config(room, Config))], Result2), 3475: 3476: Res4 = escalus:wait_for_stanza(Bob), 3477: true = is_message_with_status_code(Res4, <<"171">>), 3478: true = is_groupchat_message(Res4), 3479: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res4), 3480: 3481: escalus:wait_for_stanza(Kate) 3482: end). 3483: 3484: 3485: %% Example 171 3486: %% This test fails, ejabberd apparently doesn't send room status update after privacy-related update 3487: configure_anonymous(ConfigIn) -> 3488: RoomOpts = [{persistent, true}, {anonymous, true}], 3489: UserSpecs = [{alice, 1}, {bob, 1}], 3490: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob) -> 3491: %% Bob joins room 3492: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3493: escalus:wait_for_stanzas(Bob, 2), 3494: 3495: %% Alice requests configuration form 3496: escalus:send(Alice, stanza_to_room( 3497: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3498: 3499: %% Alice receives form 3500: Res = escalus:wait_for_stanza(Alice), 3501: true = is_form(Res), 3502: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res), 3503: 3504: 3505: %% Configure room as non-anonymous 3506: Fields = [#{var => <<"muc#roomconfig_whois">>, values => [<<"anyone">>], 3507: type => <<"list-single">>}], 3508: Form = stanza_configuration_form(?config(room, Config), Fields), 3509: Result = escalus:send_iq_and_wait_for_result(Alice, Form), 3510: escalus:assert(is_stanza_from, 3511: [room_address(?config(room, Config))], Result), 3512: 3513: Res2 = escalus:wait_for_stanza(Bob), 3514: true = is_message_with_status_code(Res2, <<"172">>), 3515: true = is_groupchat_message(Res2), 3516: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res2), 3517: 3518: %% Alice requests configuration form again 3519: escalus:send(Alice, stanza_to_room( 3520: escalus_stanza:iq_get(?NS_MUC_OWNER,[]), ?config(room, Config))), 3521: 3522: %% Alice receives form 3523: Res3 = escalus:wait_for_stanza(Alice), 3524: true = is_form(Res3), 3525: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res3), 3526: 3527: %% Configure room as semi-anonymous 3528: Fields2 = [#{var => <<"muc#roomconfig_whois">>, values => [<<"moderators">>], 3529: type => <<"list-single">>}], 3530: Form2 = stanza_configuration_form(?config(room, Config), Fields2), 3531: Result2 = escalus:send_iq_and_wait_for_result(Alice, Form2), 3532: escalus:assert(is_stanza_from, 3533: [room_address(?config(room, Config))], Result2), 3534: 3535: Res4 = escalus:wait_for_stanza(Bob), 3536: true = is_message_with_status_code(Res4, <<"173">>), 3537: true = is_groupchat_message(Res4), 3538: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Res4) 3539: end). 3540: 3541: cancel_iq_sent_to_locked_room_destroys_it(Config) -> 3542: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3543: Room = fresh_room_name(), 3544: Nick = <<"the-owner">>, 3545: 3546: PresenceResp = escalus:send_and_wait(Alice, stanza_muc_enter_room(Room, Nick)), 3547: escalus:wait_for_stanza(Alice), 3548: ?assert(is_presence_with_affiliation(PresenceResp, <<"owner">>)), 3549: ?assert(is_presence_with_role(PresenceResp, <<"moderator">>)), 3550: 3551: PresenceLeave = escalus:send_and_wait(Alice, stanza_cancel(Room)), 3552: escalus:assert(is_presence_with_type, [<<"unavailable">>], PresenceLeave), 3553: escalus:assert(is_stanza_from, [room_address(Room, Nick)], PresenceLeave), 3554: escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)) 3555: end). 3556: 3557: cancel_iq_sent_to_unlocked_room_has_no_effect(Config) -> 3558: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 3559: Room = fresh_room_name(), 3560: Nick = <<"the-owner">>, 3561: 3562: PresenceResp = escalus:send_and_wait(Alice, stanza_muc_enter_room(Room, Nick)), 3563: escalus:wait_for_stanza(Alice), 3564: ?assert(is_presence_with_affiliation(PresenceResp, <<"owner">>)), 3565: ?assert(is_presence_with_role(PresenceResp, <<"moderator">>)), 3566: 3567: InstantRoomIq = stanza_instant_room(Room), 3568: escalus:send_iq_and_wait_for_result(Alice, InstantRoomIq), 3569: RoomsIqResp = escalus:send_iq_and_wait_for_result( 3570: Alice, stanza_room_list_request(<<"id">>, undefined)), 3571: true = has_room(room_address(Room), RoomsIqResp), 3572: 3573: escalus:send_iq_and_wait_for_result(Alice, stanza_cancel(Room)) 3574: end). 3575: 3576: %% Examples 172-180 3577: owner_grant_revoke(ConfigIn) -> 3578: RoomOpts = [{persistent, true}], 3579: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3580: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3581: %% Alice joins room 3582: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3583: escalus:wait_for_stanzas(Alice, 2), 3584: %% Bob joins room 3585: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3586: escalus:wait_for_stanzas(Bob, 3), 3587: %% Kate joins room 3588: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3589: escalus:wait_for_stanzas(Kate, 4), 3590: %% Skip Kate's presence 3591: escalus:wait_for_stanza(Bob), 3592: %% Skip Kate's and Bob's presences 3593: escalus:wait_for_stanzas(Alice, 3), 3594: 3595: %% Grant bob owner status 3596: escalus:send(Alice, stanza_set_affiliations( 3597: ?config(room, Config), 3598: [{escalus_utils:get_short_jid(Bob),<<"owner">>}])), 3599: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 3600: 3601: %% Bob receives his notice 3602: Bobs = escalus:wait_for_stanza(Bob), 3603: true = is_presence_with_affiliation(Bobs, <<"owner">>), 3604: escalus:assert(is_stanza_from, 3605: [room_address(?config(room, Config), <<"bob">>)], Bobs), 3606: 3607: %% Kate receives Bob's notice 3608: Kates = escalus:wait_for_stanza(Kate), 3609: true = is_presence_with_affiliation(Kates, <<"owner">>), 3610: escalus:assert(is_stanza_from, 3611: [room_address(?config(room, Config), <<"bob">>)], Kates), 3612: 3613: %% Revoke alice owner status 3614: Pred = fun(Stanza) -> 3615: escalus_pred:is_stanza_from( 3616: room_address(?config(room, Config), <<"alice">>),Stanza) andalso 3617: is_presence_with_affiliation(Stanza, <<"admin">>) 3618: end, 3619: 3620: escalus:send(Bob, stanza_set_affiliations( 3621: ?config(room, Config), 3622: [{escalus_utils:get_short_jid(Alice), <<"admin">>}])), 3623: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Bob, 2)), 3624: 3625: %% Alice receives her loss of ownership presence 3626: Alices = escalus:wait_for_stanza(Alice), 3627: true = is_presence_with_affiliation(Alices, <<"admin">>), 3628: escalus:assert(is_stanza_from, 3629: [room_address(?config(room,Config), <<"alice">>)], Alices), 3630: 3631: %% Kate receives Alice's loss of ownership presence 3632: Kates2 = escalus:wait_for_stanza(Kate), 3633: true = is_presence_with_affiliation(Kates2, <<"admin">>), 3634: escalus:assert(is_stanza_from, 3635: [room_address(?config(room,Config), <<"alice">>)], Kates2) 3636: 3637: end). 3638: 3639: owner_grant_revoke_with_reason(ConfigIn) -> 3640: RoomOpts = [{persistent, true}], 3641: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3642: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3643: %% Alice joins room 3644: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3645: escalus:wait_for_stanzas(Alice, 2), 3646: %% Bob joins room 3647: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3648: escalus:wait_for_stanzas(Bob, 3), 3649: %% Kate joins room 3650: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3651: escalus:wait_for_stanzas(Kate, 4), 3652: %% Skip Kate's presence 3653: escalus:wait_for_stanza(Bob), 3654: %% Skip Kate's and Bob's presences 3655: escalus:wait_for_stanzas(Alice, 3), 3656: 3657: %% Grant bob owner status 3658: escalus:send(Alice, stanza_set_affiliations( 3659: ?config(room, Config), 3660: [{escalus_utils:get_short_jid(Bob),<<"owner">>,<<"I trust him">>}])), 3661: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 3662: 3663: %% Bob receives his notice 3664: Bobs = escalus:wait_for_stanza(Bob), 3665: true = has_reason(Bobs), 3666: true = is_presence_with_affiliation(Bobs, <<"owner">>), 3667: escalus:assert(is_stanza_from, 3668: [room_address(?config(room, Config), <<"bob">>)], Bobs), 3669: 3670: %% Kate receives Bob's notice 3671: Kates = escalus:wait_for_stanza(Kate), 3672: true = has_reason(Kates), 3673: true = is_presence_with_affiliation(Kates, <<"owner">>), 3674: escalus:assert(is_stanza_from, 3675: [room_address(?config(room, Config), <<"bob">>)], Kates), 3676: 3677: %% Revoke alice owner status 3678: Pred = fun(Stanza) -> 3679: escalus_pred:is_stanza_from( 3680: room_address(?config(room, Config), <<"alice">>),Stanza) andalso 3681: is_presence_with_affiliation(Stanza, <<"admin">>) 3682: end, 3683: 3684: escalus:send(Bob, stanza_set_affiliations( 3685: ?config(room, Config), 3686: [{escalus_utils:get_short_jid(Alice), 3687: <<"admin">>, <<"Assassination!">>}])), 3688: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Bob, 2)), 3689: 3690: %% Alice receives her loss of ownership presence 3691: Alices = escalus:wait_for_stanza(Alice), 3692: true = has_reason(Alices), 3693: true = is_presence_with_affiliation(Alices, <<"admin">>), 3694: escalus:assert(is_stanza_from, 3695: [room_address(?config(room,Config), <<"alice">>)], Alices), 3696: 3697: %% Kate receives Alice's loss of ownership presence 3698: Kates2 = escalus:wait_for_stanza(Kate), 3699: true = has_reason(Kates2), 3700: true = is_presence_with_affiliation(Kates2, <<"admin">>), 3701: escalus:assert(is_stanza_from, 3702: [room_address(?config(room,Config), <<"alice">>)], Kates2) 3703: 3704: end). 3705: 3706: %% Examples 181-185 3707: %% Behaves strange when we try to revoke the only owner together with 3708: %% granting someone else 3709: owner_list(ConfigIn) -> 3710: RoomOpts = [{persistent, true}], 3711: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3712: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3713: %% Alice joins room 3714: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3715: escalus:wait_for_stanzas(Alice, 2), 3716: %% Bob joins room 3717: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3718: escalus:wait_for_stanzas(Bob, 3), 3719: %% Kate joins room 3720: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3721: escalus:wait_for_stanzas(Kate, 4), 3722: %% Skip Kate's presence 3723: escalus:wait_for_stanza(Bob), 3724: %% Skip Kate's and Bob's presences 3725: escalus:wait_for_stanzas(Alice, 3), 3726: 3727: %% Alice requests owner list 3728: List = escalus:send_iq_and_wait_for_result( 3729: Alice, stanza_affiliation_list_request(?config(room, Config), <<"owner">>)), 3730: 3731: %% Alice should be on it 3732: true = is_iq_with_affiliation(List, <<"owner">>), 3733: true = is_iq_with_short_jid(List, Alice), 3734: 3735: %% Grant Bob and Kate owners status 3736: escalus:send(Alice, stanza_set_affiliations( 3737: ?config(room, Config), 3738: [{escalus_utils:get_short_jid(Kate),<<"owner">>}, 3739: {escalus_utils:get_short_jid(Bob), <<"owner">>}])), 3740: escalus:assert_many([is_iq_result, is_presence, is_presence], 3741: escalus:wait_for_stanzas(Alice, 3)), 3742: 3743: %% Bob receives his and Kate's notice 3744: Preds = [fun(Stanza) -> 3745: is_presence_with_affiliation(Stanza, <<"owner">>) andalso 3746: escalus_pred:is_stanza_from( 3747: room_address(?config(room, Config), <<"bob">>), Stanza) 3748: end, 3749: fun(Stanza) -> 3750: is_presence_with_affiliation(Stanza, <<"owner">>) andalso 3751: escalus_pred:is_stanza_from( 3752: room_address(?config(room, Config), <<"kate">>), Stanza) 3753: end], 3754: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 3755: 3756: %% Kate receives her and Bob's notice 3757: escalus:assert_many(Preds, escalus:wait_for_stanzas(Kate, 2)) 3758: end). 3759: 3760: %% Example 184 3761: %% Test doesn't fail anymore, ejabberd used to return cancel/not-allowed error while it should 3762: %% return auth/forbidden according to XEP 3763: owner_unauthorized(ConfigIn) -> 3764: RoomOpts = [{persistent, true}], 3765: UserSpecs = [{alice, 1}, {bob, 1}], 3766: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, _Alice, Bob) -> 3767: %% Bob joins room 3768: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3769: escalus:wait_for_stanzas(Bob, 2), 3770: 3771: %% Bob tries to modify owner list 3772: escalus:send(Bob, stanza_set_affiliations( 3773: ?config(room, Config), 3774: [{escalus_utils:get_short_jid(Bob), <<"owner">>}])), 3775: %% Should get an error 3776: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], 3777: escalus:wait_for_stanza(Bob)) 3778: 3779: end). 3780: 3781: %% Examples 186-195 3782: admin_grant_revoke(ConfigIn) -> 3783: RoomOpts = [{persistent, true}], 3784: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3785: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3786: %% Alice joins room 3787: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3788: escalus:wait_for_stanzas(Alice, 2), 3789: %% Bob joins room 3790: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3791: escalus:wait_for_stanzas(Bob, 3), 3792: %% Kate joins room 3793: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3794: escalus:wait_for_stanzas(Kate, 4), 3795: %% Skip Kate's presence 3796: escalus:wait_for_stanza(Bob), 3797: %% Skip Kate's and Bob's presences 3798: escalus:wait_for_stanzas(Alice, 3), 3799: 3800: %% Grant bob owner status 3801: escalus:send(Alice, stanza_set_affiliations( 3802: ?config(room, Config), 3803: [{escalus_utils:get_short_jid(Bob),<<"admin">>}])), 3804: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 3805: 3806: %% Bob receives his notice 3807: Bobs = escalus:wait_for_stanza(Bob), 3808: true = is_presence_with_affiliation(Bobs, <<"admin">>), 3809: escalus:assert(is_stanza_from, 3810: [room_address(?config(room, Config), <<"bob">>)], Bobs), 3811: 3812: %% Kate receives Bob's notice 3813: Kates = escalus:wait_for_stanza(Kate), 3814: true = is_presence_with_affiliation(Kates, <<"admin">>), 3815: escalus:assert(is_stanza_from, 3816: [room_address(?config(room, Config), <<"bob">>)], Kates), 3817: 3818: %% Revoke Bob admin status 3819: Pred = fun(Stanza) -> 3820: escalus_pred:is_stanza_from( 3821: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 3822: is_presence_with_affiliation(Stanza, <<"none">>) 3823: end, 3824: 3825: escalus:send(Alice, stanza_set_affiliations( 3826: ?config(room, Config), 3827: [{escalus_utils:get_short_jid(Bob), <<"none">>}])), 3828: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Alice, 2)), 3829: 3830: %% Bob receives his loss of admin presence 3831: Bobs2 = escalus:wait_for_stanza(Bob), 3832: true = is_presence_with_affiliation(Bobs2, <<"none">>), 3833: escalus:assert(is_stanza_from, 3834: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 3835: 3836: %% Kate receives Bob's loss of admin presence 3837: Kates2 = escalus:wait_for_stanza(Kate), 3838: true = is_presence_with_affiliation(Kates2, <<"none">>), 3839: escalus:assert(is_stanza_from, 3840: [room_address(?config(room,Config), <<"bob">>)], Kates2) 3841: 3842: end). 3843: 3844: admin_grant_revoke_with_reason(ConfigIn) -> 3845: RoomOpts = [{persistent, true}], 3846: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3847: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3848: %% Alice joins room 3849: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3850: escalus:wait_for_stanzas(Alice, 2), 3851: %% Bob joins room 3852: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3853: escalus:wait_for_stanzas(Bob, 3), 3854: %% Kate joins room 3855: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3856: escalus:wait_for_stanzas(Kate, 4), 3857: %% Skip Kate's presence 3858: escalus:wait_for_stanza(Bob), 3859: %% Skip Kate's and Bob's presences 3860: escalus:wait_for_stanzas(Alice, 3), 3861: 3862: %% Grant bob admin status 3863: escalus:send(Alice, stanza_set_affiliations( 3864: ?config(room, Config), 3865: [{escalus_utils:get_short_jid(Bob),<<"admin">>,<<"He should be helpful">>}])), 3866: escalus:assert_many([is_iq_result, is_presence], escalus:wait_for_stanzas(Alice, 2)), 3867: 3868: %% Bob receives his notice 3869: Bobs = escalus:wait_for_stanza(Bob), 3870: true = has_reason(Bobs), 3871: true = is_presence_with_affiliation(Bobs, <<"admin">>), 3872: escalus:assert(is_stanza_from, 3873: [room_address(?config(room, Config), <<"bob">>)], Bobs), 3874: 3875: %% Kate receives Bob's notice 3876: Kates = escalus:wait_for_stanza(Kate), 3877: true = has_reason(Kates), 3878: true = is_presence_with_affiliation(Kates, <<"admin">>), 3879: escalus:assert(is_stanza_from, 3880: [room_address(?config(room, Config), <<"bob">>)], Kates), 3881: 3882: %% Revoke Bob admin status 3883: Pred = fun(Stanza) -> 3884: escalus_pred:is_stanza_from( 3885: room_address(?config(room, Config), <<"bob">>),Stanza) andalso 3886: is_presence_with_affiliation(Stanza, <<"none">>) 3887: end, 3888: 3889: escalus:send(Alice, stanza_set_affiliations( 3890: ?config(room, Config), 3891: [{escalus_utils:get_short_jid(Bob), 3892: <<"none">>, <<"Well, he wasn't">>}])), 3893: escalus:assert_many([is_iq_result, Pred], escalus:wait_for_stanzas(Alice, 2)), 3894: 3895: %% Bob receives his loss of admin presence 3896: Bobs2 = escalus:wait_for_stanza(Bob), 3897: true = has_reason(Bobs2), 3898: true = is_presence_with_affiliation(Bobs2, <<"none">>), 3899: escalus:assert(is_stanza_from, 3900: [room_address(?config(room,Config), <<"bob">>)], Bobs2), 3901: 3902: %% Kate receives Bob's loss of admin presence 3903: Kates2 = escalus:wait_for_stanza(Kate), 3904: true = has_reason(Kates2), 3905: true = is_presence_with_affiliation(Kates2, <<"none">>), 3906: escalus:assert(is_stanza_from, 3907: [room_address(?config(room,Config), <<"bob">>)], Kates2) 3908: 3909: end). 3910: 3911: %% Examples 196-200 3912: admin_list(ConfigIn) -> 3913: RoomOpts = [{persistent, true}], 3914: UserSpecs = [{alice, 1}, {bob, 1}, {kate, 1}], 3915: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob, Kate) -> 3916: %% Alice joins room 3917: escalus:send(Alice, stanza_muc_enter_room(?config(room, Config), <<"alice">>)), 3918: escalus:wait_for_stanzas(Alice, 2), 3919: %% Bob joins room 3920: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3921: escalus:wait_for_stanzas(Bob, 3), 3922: %% Kate joins room 3923: escalus:send(Kate, stanza_muc_enter_room(?config(room, Config), <<"kate">>)), 3924: escalus:wait_for_stanzas(Kate, 4), 3925: %% Skip Kate's presence 3926: escalus:wait_for_stanza(Bob), 3927: %% Skip Kate's and Bob's presences 3928: escalus:wait_for_stanzas(Alice, 3), 3929: 3930: %% Alice requests owner list 3931: escalus:send(Alice, stanza_affiliation_list_request( 3932: ?config(room, Config), <<"admin">>)), 3933: List = escalus:wait_for_stanza(Alice), 3934: %% Noone should be on it 3935: true = is_item_list_empty(List), 3936: 3937: %% Grant Bob and Kate admins status 3938: escalus:send(Alice, stanza_set_affiliations( 3939: ?config(room, Config), 3940: [{escalus_utils:get_short_jid(Kate),<<"admin">>}, 3941: {escalus_utils:get_short_jid(Bob), <<"admin">>}])), 3942: escalus:assert_many([is_iq_result, is_presence, is_presence], 3943: escalus:wait_for_stanzas(Alice, 3)), 3944: 3945: %% Bob receives his and Kate's notice 3946: Preds = [fun(Stanza) -> 3947: is_presence_with_affiliation(Stanza, <<"admin">>) andalso 3948: escalus_pred:is_stanza_from( 3949: room_address(?config(room, Config), <<"bob">>), Stanza) 3950: end, 3951: fun(Stanza) -> 3952: is_presence_with_affiliation(Stanza, <<"admin">>) andalso 3953: escalus_pred:is_stanza_from( 3954: room_address(?config(room, Config), <<"kate">>), Stanza) 3955: end], 3956: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 3957: 3958: %% Kate receives her and Bob's notice 3959: escalus:assert_many(Preds, escalus:wait_for_stanzas(Kate, 2)) 3960: end). 3961: 3962: %% Example 199 3963: %% Test does not fail anymoure, ejabberd used to return cancel/not-allowed error while it should 3964: %% return auth/forbidden according to XEP 3965: admin_unauthorized(ConfigIn) -> 3966: RoomOpts = [{persistent, true}], 3967: UserSpecs = [{alice, 1}, {bob, 1}], 3968: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, _Alice, Bob) -> 3969: %% Bob joins room 3970: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3971: escalus:wait_for_stanzas(Bob, 2), 3972: 3973: %% Bob tries to modify admin list 3974: escalus:send(Bob, stanza_set_affiliations( 3975: ?config(room, Config), 3976: [{escalus_utils:get_short_jid(Bob), <<"admin">>}])), 3977: Error = escalus:wait_for_stanza(Bob), 3978: %% Should get an error 3979: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], 3980: Error) 3981: 3982: end). 3983: 3984: %% Examples 201-203 3985: destroy(ConfigIn) -> 3986: RoomOpts = [{persistent, true}], 3987: UserSpecs = [{alice, 1}, {bob, 1}], 3988: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Alice, Bob) -> 3989: %% Bob joins room 3990: escalus:send(Bob, stanza_muc_enter_room(?config(room, Config), <<"bob">>)), 3991: escalus:wait_for_stanzas(Bob, 2), 3992: 3993: %% Alice requests room destruction 3994: escalus:send_iq_and_wait_for_result(Alice, stanza_destroy_room(?config(room, Config))), 3995: 3996: %% Bob gets unavailable presence 3997: Presence = escalus:wait_for_stanza(Bob), 3998: escalus:assert(is_presence_with_type, [<<"unavailable">>], Presence), 3999: escalus:assert(is_stanza_from, 4000: [room_address(?config(room, Config), <<"bob">>)], Presence) 4001: 4002: end). 4003: 4004: %% Example 204 4005: %% Test doesn't fail anymore 4006: %% Ejabberd used to return forbidden error without a type attribute 4007: destroy_unauthorized(ConfigIn) -> 4008: RoomOpts = [{persistent, true}], 4009: UserSpecs = [{alice, 0}, {bob, 1}], 4010: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 4011: %% Bob tries to destroy Alice's room 4012: escalus:send(Bob, stanza_destroy_room(?config(room, Config))), 4013: 4014: %% Bob gets an error 4015: Error = escalus:wait_for_stanza(Bob), 4016: escalus:assert(is_stanza_from, [room_address(?config(room, Config))], Error), 4017: escalus:assert(is_error, [<<"auth">>, <<"forbidden">>], Error) 4018: end). 4019: 4020: %% Example 207 4021: service_shutdown_kick(ConfigIn) -> 4022: escalus:fresh_story(ConfigIn, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 4023: %% Create a room 4024: Host = muc_host(), 4025: RoomName = fresh_room_name(), 4026: Presence = stanza_muc_enter_room(RoomName, <<"alice-the-owner">>), 4027: 4028: escalus:send(Alice, Presence), 4029: was_room_created(escalus:wait_for_stanza(Alice)), 4030: escalus:wait_for_stanza(Alice), 4031: escalus:send_iq_and_wait_for_result(Alice, stanza_instant_room(RoomName)), 4032: 4033: %% Participants join a room 4034: escalus:send(Bob, stanza_muc_enter_room(RoomName, <<"bob">>)), 4035: escalus:wait_for_stanza(Alice), 4036: escalus:wait_for_stanzas(Bob, 3), 4037: 4038: escalus:send(Kate, stanza_muc_enter_room(RoomName, <<"kate">>)), 4039: escalus:wait_for_stanza(Alice), 4040: escalus:wait_for_stanza(Bob), 4041: escalus:wait_for_stanzas(Kate, 4), 4042: 4043: escalus_assert:has_no_stanzas(Bob), 4044: escalus_assert:has_no_stanzas(Alice), 4045: escalus_assert:has_no_stanzas(Kate), 4046: 4047: %% Simulate shutdown 4048: RoomJID = mongoose_helper:make_jid(RoomName, Host, <<>>), 4049: rpc(mim(), mod_muc_room, delete_room, [RoomJID, none]), 4050: 4051: %% Check if the participants received stanzas with the appropriate status codes 4052: escalus:wait_for_stanza(Bob), 4053: BobStanza = escalus:wait_for_stanza(Bob), 4054: has_status_codes(BobStanza, [<<"332">>]), 4055: 4056: escalus:wait_for_stanza(Kate), 4057: KateStanza = escalus:wait_for_stanza(Kate), 4058: has_status_codes(KateStanza, [<<"332">>]) 4059: end). 4060: %%-------------------------------------------------------------------- 4061: %% RSM (a partial list of rooms) 4062: %%-------------------------------------------------------------------- 4063: 4064: pagination_empty_rset(Config) -> 4065: F = fun(Alice) -> 4066: %% Get the first page of size 5. 4067: RSM = #rsm_in{max=0}, 4068: escalus:send(Alice, stanza_room_list_request(<<"empty_rset">>, RSM)), 4069: wait_empty_rset(Alice, 15) 4070: end, 4071: escalus:story(Config, [{alice, 1}], F). 4072: 4073: pagination_first5(Config) -> 4074: F = fun(Alice) -> 4075: %% Get the first page of size 5. 4076: RSM = #rsm_in{max=5}, 4077: escalus:send(Alice, stanza_room_list_request(<<"first5">>, RSM)), 4078: wait_room_range(Alice, 1, 5), 4079: ok 4080: end, 4081: escalus:fresh_story(Config, [{alice, 1}], F). 4082: 4083: pagination_last5(Config) -> 4084: F = fun(Alice) -> 4085: %% Get the last page of size 5. 4086: RSM = #rsm_in{max=5, direction=before}, 4087: escalus:send(Alice, stanza_room_list_request(<<"last5">>, RSM)), 4088: wait_room_range(Alice, 11, 15), 4089: ok 4090: end, 4091: escalus:fresh_story(Config, [{alice, 1}], F). 4092: 4093: pagination_before10(Config) -> 4094: %% The last item in the page returned by the responding entity 4095: %% MUST be the item that immediately preceeds the item that 4096: %% the requesting entity indicated it has already received. 4097: F = fun(Alice) -> 4098: %% Get the last page of size 5. 4099: RSM = #rsm_in{max=5, direction=before, id=generate_room_name(10)}, 4100: escalus:send(Alice, stanza_room_list_request(<<"before10">>, RSM)), 4101: wait_room_range(Alice, 5, 9), 4102: ok 4103: end, 4104: escalus:fresh_story(Config, [{alice, 1}], F). 4105: 4106: pagination_after10(Config) -> 4107: F = fun(Alice) -> 4108: %% Get the last page of size 5. 4109: RSM = #rsm_in{max=5, direction='after', 4110: id=generate_room_name(10)}, 4111: escalus:send(Alice, stanza_room_list_request(<<"after10">>, RSM)), 4112: wait_room_range(Alice, 11, 15), 4113: ok 4114: end, 4115: escalus:fresh_story(Config, [{alice, 1}], F). 4116: 4117: 4118: pagination_at_index(Config) -> 4119: F = fun(Alice) -> 4120: RSM = #rsm_in{index = 11}, 4121: escalus:send(Alice, stanza_room_list_request(<<"at_index">>, RSM)), 4122: wait_room_range(Alice, 12, 15), 4123: ok 4124: end, 4125: escalus:fresh_story(Config, [{alice, 1}], F). 4126: 4127: 4128: pagination_after_index_not_all(Config) -> 4129: F = fun(Alice) -> 4130: RSM = #rsm_in{index = 6, max = 4, direction='after'}, 4131: escalus:send(Alice, stanza_room_list_request(<<"after_index_not_all">>, RSM)), 4132: wait_room_range(Alice, 7, 10), 4133: ok 4134: end, 4135: escalus:fresh_story(Config, [{alice, 1}], F). 4136: 4137: pagination_after_index_all(Config) -> 4138: F = fun(Alice) -> 4139: RSM = #rsm_in{index = 10, max = 5, direction='after'}, 4140: escalus:send(Alice, stanza_room_list_request(<<"after_index_all">>, RSM)), 4141: wait_room_range(Alice, 11, 15), 4142: ok 4143: end, 4144: escalus:fresh_story(Config, [{alice, 1}], F). 4145: 4146: pagination_after_index_all_and_more(Config) -> 4147: F = fun(Alice) -> 4148: RSM = #rsm_in{index = 9, max = 20, direction='after'}, 4149: escalus:send(Alice, stanza_room_list_request(<<"after_index_all_and_more">>, RSM)), 4150: wait_room_range(Alice, 10, 15), 4151: ok 4152: end, 4153: escalus:fresh_story(Config, [{alice, 1}], F). 4154: 4155: pagination_index_out_of_range_above(Config) -> 4156: F = fun(Alice) -> 4157: RSM = #rsm_in{index = 20}, 4158: escalus:send(Alice, stanza_room_list_request(<<"index_out_of_range_above_range">>, RSM)), 4159: wait_empty_rset(Alice, 15), 4160: ok 4161: end, 4162: escalus:fresh_story(Config, [{alice, 1}], F). 4163: 4164: pagination_index_out_of_range_bellow(Config) -> 4165: F = fun(Alice) -> 4166: RSM = #rsm_in{index = -1}, 4167: escalus:send(Alice, stanza_room_list_request(<<"index_out_of_range_bellow_range">>, RSM)), 4168: wait_empty_rset(Alice, 15), 4169: ok 4170: end, 4171: escalus:fresh_story(Config, [{alice, 1}], F). 4172: 4173: pagination_index_out_of_range_closest(Config) -> 4174: F = fun(Alice) -> 4175: RSM = #rsm_in{index = 15}, 4176: escalus:send(Alice, stanza_room_list_request(<<"index_out_of_range_edge">>, RSM)), 4177: wait_empty_rset(Alice, 15), 4178: ok 4179: end, 4180: escalus:fresh_story(Config, [{alice, 1}], F). 4181: 4182: pagination_all_with_offline(Config) -> 4183: F = fun(Alice) -> 4184: RSMBefore = #rsm_in{max=10, direction=before, id=generate_room_name(10)}, 4185: RSMAfter = #rsm_in{max=10, direction='after', id=generate_room_name(10)}, 4186: escalus:send(Alice, stanza_room_list_request(<<"before10">>, RSMBefore)), 4187: escalus:send(Alice, stanza_room_list_request(<<"after10">>, RSMAfter)), 4188: StanzaBefore = escalus:wait_for_stanza(Alice), 4189: StanzaAfter = escalus:wait_for_stanza(Alice), 4190: true = has_room(room_address(<<"persistentroom">>), StanzaBefore) 4191: orelse has_room(room_address(<<"persistentroom">>), StanzaAfter), 4192: ok 4193: end, 4194: escalus:fresh_story(Config, [{alice, 1}], F). 4195: 4196: %%-------------------------------------------------------------------- 4197: %% Password protection with HTTP external authentication 4198: %%-------------------------------------------------------------------- 4199: 4200: deny_access_to_http_password_protected_room_wrong_password(ConfigIn) -> 4201: RoomOpts = [{password_protected, true}], 4202: UserSpecs = [{alice, 0}, {bob, 1}], 4203: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 4204: escalus:send(Bob, stanza_muc_enter_password_protected_room(?config(room, Config), escalus_utils:get_username(Bob), <<"badpass">>)), 4205: escalus_assert:is_error(escalus:wait_for_stanza(Bob), <<"auth">>, <<"not-authorized">>) 4206: end). 4207: 4208: deny_access_to_http_password_protected_room_service_unavailable(ConfigIn) -> 4209: RoomOpts = [{password_protected, true}], 4210: UserSpecs = [{alice, 0}, {bob, 1}], 4211: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 4212: escalus:send(Bob, stanza_muc_enter_password_protected_room(?config(room, Config), escalus_utils:get_username(Bob), ?PASSWORD)), 4213: escalus_assert:is_error(escalus:wait_for_stanza(Bob, 6000), <<"cancel">>, <<"service-unavailable">>) 4214: end). 4215: 4216: enter_http_password_protected_room(ConfigIn) -> 4217: RoomOpts = [{password_protected, true}], 4218: UserSpecs = [{alice, 0}, {bob, 1}], 4219: story_with_room(ConfigIn, RoomOpts, UserSpecs, fun(Config, Bob) -> 4220: Room = ?config(room, Config), 4221: Username = escalus_utils:get_username(Bob), 4222: Stanza = stanza_muc_enter_password_protected_room(Room, Username, 4223: ?PASSWORD), 4224: escalus:send(Bob, Stanza), 4225: Presence = escalus:wait_for_stanza(Bob), 4226: is_self_presence(Bob, ?config(room, Config), Presence) 4227: end). 4228: 4229: create_instant_http_password_protected_room(Config) -> 4230: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4231: 4232: %% Create the room (should be locked on creation) 4233: RoomName = fresh_room_name(), 4234: Presence = stanza_muc_enter_password_protected_room(RoomName, <<"alice-the-owner">>, ?PASSWORD), 4235: escalus:send(Alice, Presence), 4236: was_room_created(escalus:wait_for_stanza(Alice)), 4237: 4238: escalus:wait_for_stanza(Alice), % topic 4239: 4240: escalus:send_iq_and_wait_for_result(Alice, stanza_instant_room(RoomName)), 4241: 4242: %% Bob should be able to join the room 4243: escalus:send(Bob, stanza_muc_enter_password_protected_room(RoomName, <<"bob">>, ?PASSWORD)), 4244: escalus:wait_for_stanza(Alice), %Bobs presence 4245: %% Bob should receive (in that order): Alices presence, his presence and the topic 4246: 4247: Preds = [fun(Stanza) -> escalus_pred:is_presence(Stanza) andalso 4248: escalus_pred:is_stanza_from(room_address(RoomName, <<"bob">>), Stanza) 4249: end, 4250: fun(Stanza) -> escalus_pred:is_presence(Stanza) andalso 4251: escalus_pred:is_stanza_from(room_address(RoomName, <<"alice-the-owner">>), Stanza) 4252: end], 4253: escalus:assert_many(Preds, escalus:wait_for_stanzas(Bob, 2)), 4254: escalus:wait_for_stanza(Bob), %topic 4255: escalus_assert:has_no_stanzas(Bob), 4256: escalus_assert:has_no_stanzas(Alice) 4257: end). 4258: 4259: deny_creation_of_http_password_protected_room(Config) -> 4260: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4261: %% Fail to create the room 4262: RoomName = fresh_room_name(), 4263: Presence = stanza_muc_enter_room(RoomName, <<"alice-the-owner">>), 4264: escalus:send(Alice, Presence), 4265: escalus_assert:is_error(escalus:wait_for_stanza(Alice), <<"auth">>, <<"not-authorized">>), 4266: escalus_assert:has_no_stanzas(Alice) 4267: end). 4268: 4269: deny_creation_of_http_password_protected_room_wrong_password(Config) -> 4270: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4271: %% Fail to create the room 4272: RoomName = fresh_room_name(), 4273: Presence = stanza_muc_enter_password_protected_room(RoomName, <<"alice-the-owner">>, <<"badpass">>), 4274: escalus:send(Alice, Presence), 4275: escalus_assert:is_error(escalus:wait_for_stanza(Alice), <<"auth">>, <<"not-authorized">>), 4276: escalus_assert:has_no_stanzas(Alice) 4277: end). 4278: 4279: 4280: deny_creation_of_http_password_protected_room_service_unavailable(Config) -> 4281: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4282: %% Fail to create the room 4283: RoomName = fresh_room_name(), 4284: Presence = stanza_muc_enter_password_protected_room(RoomName, <<"alice-the-owner">>, ?PASSWORD), 4285: escalus:send(Alice, Presence), 4286: escalus_assert:is_error(escalus:wait_for_stanza(Alice, 6000), <<"cancel">>, <<"service-unavailable">>), 4287: escalus_assert:has_no_stanzas(Alice) 4288: end). 4289: 4290: room_is_hibernated(Config) -> 4291: RoomName = fresh_room_name(), 4292: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4293: given_fresh_room_is_hibernated(Alice, RoomName, [{membersonly, false}]) 4294: end), 4295: 4296: destroy_room(muc_host(), RoomName). 4297: 4298: room_with_participants_is_hibernated(Config) -> 4299: RoomName = fresh_room_name(), 4300: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4301: given_fresh_room_with_participants_is_hibernated(Alice, RoomName, 4302: [{membersonly, false}], Bob) 4303: end), 4304: 4305: destroy_room(muc_host(), RoomName). 4306: 4307: hibernation_metrics_are_updated(Config) -> 4308: RoomName = fresh_room_name(), 4309: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4310: given_fresh_room_is_hibernated(Alice, RoomName, [{membersonly, false}]), 4311: 4312: OnlineRooms = rpc(mim(), mod_muc, online_rooms_number, []), 4313: true = OnlineRooms > 0, 4314: HibernationsCnt = get_spiral_metric_count(global, [mod_muc, hibernations]), 4315: true = HibernationsCnt > 0, 4316: HibernatedRooms = rpc(mim(), mod_muc, hibernated_rooms_number, []), 4317: true = HibernatedRooms > 0 4318: end), 4319: 4320: destroy_room(muc_host(), RoomName). 4321: 4322: room_with_participants_and_messages_is_hibernated(Config) -> 4323: RoomName = fresh_room_name(), 4324: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4325: given_fresh_room_with_messages_is_hibernated(Alice, RoomName, 4326: [{membersonly, false}], Bob) 4327: 4328: end), 4329: 4330: destroy_room(muc_host(), RoomName). 4331: 4332: hibernated_room_can_be_queried_for_archive(Config) -> 4333: RoomName = fresh_room_name(), 4334: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4335: Result = given_fresh_room_with_messages_is_hibernated(Alice, RoomName, 4336: [{membersonly, false}], Bob), 4337: {Msg, {ok, _, Pid}} = Result, 4338: wait_for_mam_result(RoomName, Bob, Msg), 4339: wait_for_hibernation(Pid) 4340: 4341: end), 4342: 4343: destroy_room(muc_host(), RoomName). 4344: 4345: hibernated_room_is_stopped(Config) -> 4346: RoomName = fresh_room_name(), 4347: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4348: {ok, _, Pid} = given_fresh_room_is_hibernated(Alice, RoomName, [{persistentroom, true}]), 4349: leave_room(RoomName, Alice), 4350: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)) 4351: end), 4352: 4353: destroy_room(muc_host(), RoomName), 4354: forget_room(host_type(), muc_host(), RoomName). 4355: 4356: hibernated_room_is_stopped_and_restored_by_presence(Config) -> 4357: RoomName = fresh_room_name(), 4358: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4359: Opts = [{persistentroom, true}, 4360: {subject, <<"Restorable">>}], 4361: Result = given_fresh_room_with_participants_is_hibernated(Alice, RoomName, Opts, Bob), 4362: {ok, RoomJID, Pid} = Result, 4363: leave_room(RoomName, Alice), 4364: escalus:wait_for_stanza(Bob), 4365: leave_room(RoomName, Bob), 4366: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4367: ct:sleep(timer:seconds(1)), 4368: 4369: escalus:send(Bob, stanza_join_room(RoomName, <<"bob">>)), 4370: Presence = escalus:wait_for_stanza(Bob, ?WAIT_TIMEOUT), 4371: escalus:assert(is_presence, Presence), 4372: MessageWithSubject = escalus:wait_for_stanza(Bob), 4373: true = is_subject_message(MessageWithSubject, <<"Restorable">>), 4374: 4375: {ok, _Pid2} = rpc(mim(), mod_muc, room_jid_to_pid, [RoomJID]), 4376: ok 4377: end), 4378: 4379: destroy_room(muc_host(), RoomName), 4380: forget_room(host_type(), muc_host(), RoomName). 4381: 4382: stopped_rooms_history_is_available(Config) -> 4383: RoomName = fresh_room_name(), 4384: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4385: Opts = [{persistentroom, true}], 4386: Result = given_fresh_room_with_messages_is_hibernated(Alice, RoomName, 4387: Opts, Bob), 4388: {Msg, {ok, RoomJID, Pid}} = Result, 4389: leave_room(RoomName, Alice), 4390: escalus:wait_for_stanza(Bob), 4391: leave_room(RoomName, Bob), 4392: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4393: 4394: wait_for_mam_result(RoomName, Bob, Msg), 4395: 4396: {ok, _Pid2} = rpc(mim(), mod_muc, room_jid_to_pid, [RoomJID]), 4397: ok 4398: end), 4399: 4400: destroy_room(muc_host(), RoomName), 4401: forget_room(host_type(), muc_host(), RoomName). 4402: 4403: stopped_members_only_room_process_invitations_correctly(Config) -> 4404: RoomName = fresh_room_name(), 4405: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 4406: Opts = [{persistentroom, true}, 4407: {membersonly, true}], 4408: Result = given_fresh_room_for_user(Alice, RoomName, Opts), 4409: {ok, _, Pid} = Result, 4410: 4411: Stanza = stanza_set_affiliations(RoomName, [{escalus_client:short_jid(Bob), <<"member">>}]), 4412: escalus:send_iq_and_wait_for_result(Alice, Stanza), 4413: is_invitation(escalus:wait_for_stanza(Bob)), 4414: 4415: leave_room(RoomName, Alice), 4416: 4417: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4418: 4419: Stanza2 = stanza_set_affiliations(RoomName, 4420: [{escalus_client:short_jid(Kate), <<"member">>}]), 4421: escalus:send_iq_and_wait_for_result(Alice, Stanza2, ?WAIT_TIMEOUT), 4422: is_invitation(escalus:wait_for_stanza(Kate)), 4423: 4424: ok 4425: end), 4426: 4427: destroy_room(muc_host(), RoomName), 4428: forget_room(host_type(), muc_host(), RoomName). 4429: 4430: room_with_participants_is_not_stopped(Config) -> 4431: RoomName = fresh_room_name(), 4432: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4433: {ok, _, Pid} = given_fresh_room_with_participants_is_hibernated( 4434: Alice, RoomName, [{persistentroom, true}], Bob), 4435: false = wait_for_room_to_be_stopped(Pid, timer:seconds(8)) 4436: end), 4437: 4438: destroy_room(muc_host(), RoomName), 4439: forget_room(host_type(), muc_host(), RoomName). 4440: 4441: room_with_only_owner_is_stopped(Config) -> 4442: RoomName = fresh_room_name(), 4443: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4444: {ok, _, Pid} = given_fresh_room_is_hibernated( 4445: Alice, RoomName, [{persistentroom, true}]), 4446: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4447: 4448: Unavailable = escalus:wait_for_stanza(Alice), 4449: escalus:assert(is_presence_with_type, [<<"unavailable">>], Unavailable) 4450: end), 4451: 4452: destroy_room(muc_host(), RoomName), 4453: forget_room(host_type(), muc_host(), RoomName). 4454: 4455: can_found_in_db_when_stopped(Config) -> 4456: RoomName = fresh_room_name(), 4457: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4458: {ok, _, Pid} = given_fresh_room_is_hibernated( 4459: Alice, RoomName, [{persistentroom, true}]), 4460: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4461: {ok, _} = rpc(mim(), mod_muc, restore_room, [host_type(), muc_host(), RoomName]) 4462: end), 4463: 4464: destroy_room(muc_host(), RoomName), 4465: forget_room(host_type(), muc_host(), RoomName). 4466: 4467: deep_hibernation_metrics_are_updated(Config) -> 4468: RoomName = fresh_room_name(), 4469: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 4470: {ok, _, Pid} = given_fresh_room_is_hibernated( 4471: Alice, RoomName, [{persistentroom, true}]), 4472: true = wait_for_room_to_be_stopped(Pid, timer:seconds(8)), 4473: DeepHibernations = get_spiral_metric_count(global, [mod_muc, deep_hibernations]), 4474: true = DeepHibernations > 0, 4475: 4476: Unavailable = escalus:wait_for_stanza(Alice), 4477: escalus:assert(is_presence_with_type, [<<"unavailable">>], Unavailable), 4478: 4479: escalus:send(Bob, stanza_join_room(RoomName, <<"bob">>)), 4480: escalus:wait_for_stanzas(Bob, 2), 4481: 4482: Recreations = get_spiral_metric_count(global, [mod_muc, process_recreations]), 4483: true = Recreations > 0 4484: 4485: end), 4486: 4487: destroy_room(muc_host(), RoomName), 4488: forget_room(host_type(), muc_host(), RoomName). 4489: 4490: get_spiral_metric_count(Host, MetricName) -> 4491: Result = rpc(mim(), mongoose_metrics, get_metric_value, [Host, MetricName]), 4492: {ok, [{count, Count}, {one, _}]} = Result, 4493: Count. 4494: 4495: given_fresh_room_is_hibernated(Owner, RoomName, Opts) -> 4496: {ok, _, RoomPid} = Result = given_fresh_room_for_user(Owner, RoomName, Opts), 4497: wait_for_hibernation(RoomPid), 4498: Result. 4499: 4500: given_fresh_room_for_user(Owner, RoomName, Opts) -> 4501: RoomJID = rpc(mim(), jid, make, [RoomName, muc_host(), <<>>]), 4502: ct:log("RoomJID ~p", [RoomJID]), 4503: Nick = escalus_utils:get_username(Owner), 4504: JoinRoom = stanza_join_room(RoomName, Nick), 4505: escalus:send(Owner, JoinRoom), 4506: escalus:wait_for_stanzas(Owner, 2), 4507: maybe_configure(Owner, RoomName, Opts), 4508: {ok, Pid} = rpc(mim(), mod_muc, room_jid_to_pid, [RoomJID]), 4509: {ok, RoomJID, Pid}. 4510: 4511: maybe_configure(_, _, []) -> 4512: ok; 4513: maybe_configure(Owner, RoomName, Opts) -> 4514: Request = 4515: case proplists:get_value(instant, Opts, false) of 4516: true -> 4517: stanza_instant_room(RoomName); 4518: false -> 4519: Cfg = [opt_to_room_config(Opt) || Opt <- Opts], 4520: stanza_configuration_form(RoomName, lists:flatten(Cfg)) 4521: end, 4522: Result = escalus:send_iq_and_wait_for_result(Owner, Request), 4523: escalus:assert(is_stanza_from, [room_address(RoomName)], Result), 4524: maybe_set_subject(proplists:get_value(subject, Opts), Owner, RoomName). 4525: 4526: opt_to_room_config({Name, Value}) when is_atom(Value) -> 4527: NameBin = atom_to_binary(Name, utf8), 4528: OptionName = <<"muc#roomconfig_", NameBin/binary>>, 4529: BinValue = boolean_to_binary(Value), 4530: #{var => OptionName, values => [BinValue], type => <<"boolean">>}; 4531: opt_to_room_config(_) -> []. 4532: 4533: boolean_to_binary(true) -> <<"1">>; 4534: boolean_to_binary(false) -> <<"0">>. 4535: 4536: maybe_set_subject(undefined, _, _) -> 4537: ok; 4538: maybe_set_subject(Subject, Owner, RoomName) -> 4539: S = stanza_room_subject(RoomName, Subject), 4540: escalus:send(Owner, S), 4541: escalus:wait_for_stanza(Owner), 4542: ok. 4543: 4544: leave_room(RoomName, User) -> 4545: S = stanza_to_room(escalus_stanza:presence(<<"unavailable">>), RoomName, 4546: escalus_utils:get_username(User)), 4547: escalus:send(User, S), 4548: escalus:wait_for_stanza(User). 4549: 4550: given_fresh_room_with_participants_is_hibernated(Owner, RoomName, Opts, Participant) -> 4551: {ok, _, Pid} = Result = given_fresh_room_is_hibernated(Owner, RoomName, Opts), 4552: Nick = escalus_utils:get_username(Participant), 4553: JoinRoom = stanza_join_room(RoomName, Nick), 4554: escalus:send(Participant, JoinRoom), 4555: escalus:wait_for_stanzas(Participant, 3), 4556: escalus:wait_for_stanza(Owner), 4557: wait_for_hibernation(Pid), 4558: Result. 4559: 4560: given_fresh_room_with_messages_is_hibernated(Owner, RoomName, Opts, Participant) -> 4561: {ok, _, Pid} = Result = 4562: given_fresh_room_with_participants_is_hibernated(Owner, RoomName, Opts, Participant), 4563: RoomAddr = room_address(RoomName), 4564: MessageBin = <<"Restorable message">>, 4565: Message = escalus_stanza:groupchat_to(RoomAddr, MessageBin), 4566: escalus:send(Owner, Message), 4567: escalus:assert(is_groupchat_message, [MessageBin], escalus:wait_for_stanza(Participant)), 4568: escalus:assert(is_groupchat_message, [MessageBin], escalus:wait_for_stanza(Owner)), 4569: wait_for_hibernation(Pid), 4570: %% Archiving is an async operation, so ensure that the message is actually stored 4571: case mongoose_helper:is_rdbms_enabled(host_type()) of 4572: true -> 4573: mam_helper:wait_for_room_archive_size(muc_host(), RoomName, 1); 4574: false -> 4575: skip 4576: end, 4577: {MessageBin, Result}. 4578: 4579: forget_room(HostType, MUCHost, RoomName) -> 4580: ok = rpc(mim(), mod_muc, forget_room, [HostType, MUCHost, RoomName]). 4581: 4582: wait_for_room_to_be_stopped(Pid, Timeout) -> 4583: Ref = erlang:monitor(process, Pid), 4584: receive 4585: {'DOWN', Ref, _Type, Pid, _Info} -> 4586: true 4587: after Timeout -> 4588: false 4589: end. 4590: 4591: wait_for_hibernation(Pid) -> 4592: mongoose_helper:wait_until(fun() -> process_current_function(Pid) end, 4593: {current_function, {erlang, hibernate, 3}}, 4594: #{name => is_hibernated}). 4595: 4596: process_current_function(Pid) -> 4597: rpc(mim(), erlang, process_info, [Pid, current_function]). 4598: 4599: wait_for_mam_result(RoomName, Client, Msg) -> 4600: Props = [{mam_ns, mam_helper:mam_ns_binary_v04()}, 4601: {data_form, true}], 4602: QueryStanza = mam_helper:stanza_archive_request(Props, <<"q1">>), 4603: escalus:send(Client, stanza_to_room(QueryStanza, RoomName)), 4604: S = escalus:wait_for_stanza(Client, ?WAIT_TIMEOUT), 4605: M = exml_query:path(S, [{element, <<"result">>}, 4606: {element, <<"forwarded">>}, 4607: {element, <<"message">>}]), 4608: 4609: escalus:assert(is_groupchat_message, [Msg], M), 4610: escalus:wait_for_stanza(Client). 4611: 4612: %% @doc Based on examples from http://xmpp.org/extensions/xep-0059.html 4613: %% @end 4614: %% <iq type='get' from='stpeter@jabber.org/roundabout' 4615: %% to='conference.jabber.org' id='ex2'> 4616: %% <query xmlns='http://jabber.org/protocol/disco#items'> 4617: %% <set xmlns='http://jabber.org/protocol/rsm'> 4618: %% <max>20</max> 4619: %% </set> 4620: %% </query> 4621: %% </iq> 4622: stanza_room_list_request(_QueryId, RSM) -> 4623: escalus_stanza:iq(muc_host(), <<"get">>, [#xmlel{ 4624: name = <<"query">>, 4625: attrs = [{<<"xmlns">>, 4626: <<"http://jabber.org/protocol/disco#items">>}], 4627: children = skip_undefined([maybe_rsm_elem(RSM)]) 4628: }]). 4629: 4630: maybe_rsm_elem(undefined) -> 4631: undefined; 4632: maybe_rsm_elem(#rsm_in{max=Max, direction=Direction, id=Id, index=Index}) -> 4633: #xmlel{name = <<"set">>, 4634: attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/rsm">>}], 4635: children = skip_undefined([ 4636: maybe_rsm_max(Max), 4637: maybe_rsm_index(Index), 4638: maybe_rsm_direction(Direction, Id)])}. 4639: 4640: rsm_id_children(undefined) -> []; 4641: rsm_id_children(Id) -> [#xmlcdata{content = Id}]. 4642: 4643: maybe_rsm_direction(undefined, undefined) -> 4644: undefined; 4645: maybe_rsm_direction(Direction, Id) -> 4646: #xmlel{ 4647: name = atom_to_binary(Direction, latin1), 4648: children = rsm_id_children(Id)}. 4649: 4650: maybe_rsm_index(undefined) -> 4651: undefined; 4652: maybe_rsm_index(Index) when is_integer(Index) -> 4653: #xmlel{ 4654: name = <<"index">>, 4655: children = [#xmlcdata{content = integer_to_list(Index)}]}. 4656: 4657: maybe_rsm_max(undefined) -> 4658: undefined; 4659: maybe_rsm_max(Max) when is_integer(Max) -> 4660: #xmlel{ 4661: name = <<"max">>, 4662: children = [#xmlcdata{content = integer_to_list(Max)}]}. 4663: 4664: skip_undefined(Xs) -> 4665: [X || X <- Xs, X =/= undefined]. 4666: 4667: i2b(X) when is_integer(X) -> 4668: list_to_binary(integer_to_list(X)). 4669: 4670: wait_room_range(Client, FromN, ToN) -> 4671: wait_room_range(Client, 15, FromN-1, FromN, ToN). 4672: 4673: wait_room_range(Client, TotalCount, Offset, FromN, ToN) -> 4674: IQ = escalus:wait_for_stanza(Client), 4675: Out = parse_result_iq(IQ), 4676: try 4677: ?assert_equal(i2b(TotalCount), Out#rsm_out.count), 4678: ?assert_equal(i2b(Offset), Out#rsm_out.index), 4679: ?assert_equal(generate_room_name(FromN), Out#rsm_out.first), 4680: ?assert_equal(generate_room_name(ToN), Out#rsm_out.last), 4681: ?assert_equal(generate_room_addrs(FromN, ToN), room_jids(Out)), 4682: ok 4683: catch Class:Reason:StackTrace -> 4684: ct:pal("IQ: ~p~nOut: ~p~n", [IQ, Out]), 4685: erlang:raise(Class, Reason, StackTrace) 4686: end. 4687: 4688: wait_empty_rset(Client, TotalCount) -> 4689: IQ = escalus:wait_for_stanza(Client), 4690: Out = parse_result_iq(IQ), 4691: try 4692: ?assert_equal(i2b(TotalCount), Out#rsm_out.count), 4693: ?assert_equal([], room_jids(Out)), 4694: ok 4695: catch Class:Reason:StackTrace -> 4696: ct:pal("IQ: ~p~nOut: ~p~n", [IQ, Out]), 4697: erlang:raise(Class, Reason, StackTrace) 4698: end. 4699: 4700: room_jids(#rsm_out{items=Items}) -> 4701: [exml_query:attr(Item, <<"jid">>) || Item <- Items]. 4702: 4703: parse_result_iq(#xmlel{name = <<"iq">>, children = [Query]}) -> 4704: parse_result_query(Query). 4705: 4706: parse_result_query(#xmlel{name = <<"query">>, children = Children}) -> 4707: %% rot1 4708: [Set|Items_r] = lists:reverse(Children), 4709: Items = lists:reverse(Items_r), 4710: First = exml_query:path(Set, [{element, <<"first">>}, cdata]), 4711: Index = exml_query:path(Set, [{element, <<"first">>}, 4712: {attr, <<"index">>}]), 4713: Last = exml_query:path(Set, [{element, <<"last">>}, cdata]), 4714: Count = exml_query:path(Set, [{element, <<"count">>}, cdata]), 4715: #rsm_out{items = Items, 4716: first = First, 4717: index = Index, 4718: last = Last, 4719: count = Count}. 4720: 4721: create_already_registered_room(Config) -> 4722: Room = fresh_room_name(), 4723: Host = muc_host(), 4724: %% Start a room 4725: [Alice | _] = ?config(escalus_users, Config), 4726: 4727: %% Function has been mecked to register the room before it is started 4728: start_room(Config, Alice, Room, <<"aliceroom">>, default), 4729: %% Read the room 4730: RoomJID = mongoose_helper:make_jid(Room, Host, <<>>), 4731: {ok, Pid} = rpc(mim(), mod_muc, room_jid_to_pid, [RoomJID]), 4732: %% Check that the stored pid is the same as the mecked pid 4733: ?assert_equal(?FAKEPID, Pid). 4734: 4735: check_presence_route_to_offline_room(Config) -> 4736: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4737: Room = fresh_room_name(), 4738: %% Send a presence to a nonexistent room 4739: escalus:send(Alice, stanza_groupchat_enter_room_no_nick(Room)), 4740: 4741: %% Check that we receive the mecked pid instead of a real one 4742: ?assertReceivedMatch(?FAKEPID, 3000) 4743: end). 4744: 4745: check_message_route_to_offline_room(Config) -> 4746: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 4747: Room = fresh_room_name(), 4748: Host = muc_host(), 4749: ok = rpc(mim(), mod_muc, store_room, [host_type(), Host, Room, []]), 4750: 4751: %% Send a message to an offline permanent room 4752: escalus:send(Alice, stanza_room_subject(Room, <<"Subject line">>)), 4753: 4754: %% Check that we receive the mecked pid instead of a real one 4755: ?assertReceivedMatch(?FAKEPID, 3000) 4756: end). 4757: 4758: %%-------------------------------------------------------------------- 4759: %% Helpers 4760: %%-------------------------------------------------------------------- 4761: 4762: nick(User) -> escalus_utils:get_username(User). 4763: 4764: populate_room_with_users(Users, Config) -> 4765: Room = ?config(room, Config), 4766: lists:foldl(fun(User, AlreadyInRoom) -> 4767: enter_room(Room, User, AlreadyInRoom), 4768: [User | AlreadyInRoom] 4769: end, [], Users). 4770: 4771: enter_room(Room, User, AlreadyInRoom) -> 4772: EnterRoomStanza = stanza_muc_enter_room(Room, escalus_utils:get_username(User)), 4773: escalus:send(User, EnterRoomStanza), 4774: 4775: lists:foreach(fun(UserInRoom) -> 4776: % for every user in the room, receive presence 4777: is_presence_with_affiliation(escalus:wait_for_stanza(User), <<"none">>), 4778: % every user in the room receives presence from User 4779: Pres = escalus:wait_for_stanza(UserInRoom), 4780: is_presence_with_affiliation(Pres, <<"none">>), 4781: is_presence_from(User, Room, Pres) 4782: end, 4783: AlreadyInRoom), 4784: 4785: Presence = escalus:wait_for_stanza(User), 4786: is_presence_with_affiliation(Presence, <<"none">>), 4787: is_self_presence(User, Room, Presence), 4788: is_subject_message(escalus:wait_for_stanza(User)). 4789: 4790: is_history_message_correct(Room, SenderNick,Type, Text, ReceivedMessage) -> 4791: %error_logger:info_msg("tested message: ~n~p~n", [ReceivedMessage]), 4792: escalus_pred:is_message(ReceivedMessage), 4793: exml_query:path(ReceivedMessage, [{element, <<"delay">>}, {attr, <<"stamp">>}]), 4794: FromDelay = room_address(Room), 4795: FromDelay = exml_query:path(ReceivedMessage, [{element, <<"delay">>}, {attr, <<"from">>}]), 4796: From = room_address(Room, SenderNick), 4797: From = exml_query:attr(ReceivedMessage, <<"from">>), 4798: Type = exml_query:attr(ReceivedMessage, <<"type">>), 4799: Content = exml_query:path(ReceivedMessage, [{element, <<"body">>}, cdata]), 4800: Text = Content. 4801: 4802: is_non_anonymous_history_message_correct(Room, SenderNick,Type, Text, ReceivedMessage) -> 4803: %error_logger:info_msg("tested message: ~n~p~n", [ReceivedMessage]), 4804: escalus_pred:is_message(ReceivedMessage), 4805: exml_query:path(ReceivedMessage, [{element, <<"delay">>}, {attr, <<"stamp">>}]), 4806: FromDelay = room_address(Room), 4807: FromDelay = exml_query:path(ReceivedMessage, [{element, <<"delay">>}, {attr, <<"from">>}]), 4808: From = room_address(Room, SenderNick), 4809: From = exml_query:attr(ReceivedMessage, <<"from">>), 4810: Type = exml_query:attr(ReceivedMessage, <<"type">>), 4811: Content = exml_query:path(ReceivedMessage, [{element, <<"body">>}, cdata]), 4812: Text = Content, 4813: <<"http://jabber.org/protocol/address">> = exml:path(ReceivedMessage, [{element, <<"addresses">>}, {attr, <<"xmlns">>}]), 4814: <<"oform">> = exml:path(ReceivedMessage, [{element, <<"addresses">>},{element, <<"address">>}, {attr, <<"type">>}]), 4815: JID = escalus_utils:get_jid(SenderNick), 4816: JID = exml:path(ReceivedMessage, [{element, <<"addresses">>},{element, <<"address">>}, {attr, <<"jid">>}]). 4817: 4818: is_self_presence(User, Room, Presence) -> 4819: has_status_codes(Presence, [<<"110">>]), 4820: escalus_pred:is_presence(Presence), 4821: From = room_address(Room, escalus_utils:get_username(User)), 4822: From = exml_query:attr(Presence, <<"from">>). 4823: 4824: is_presence_from(User, Room, Presence) -> 4825: escalus_pred:is_presence(Presence), 4826: From = room_address(Room, escalus_utils:get_username(User)), 4827: From = exml_query:attr(Presence, <<"from">>). 4828: 4829: %does not check the jid - the user might not be entitled to receive it. 4830: is_availability_status_notification_correct(Room, SenderNick, NewStatus, ReceivedMessage) -> 4831: escalus_pred:is_presence(ReceivedMessage), 4832: From = room_address(Room, SenderNick), 4833: From = exml_query:attr(ReceivedMessage, <<"from">>), 4834: NewStatus = exml_query:path(ReceivedMessage, [{element, <<"status">>}, cdata]), 4835: <<"xa">> = exml_query:path(ReceivedMessage, [{element, <<"show">>}, cdata]). 4836: 4837: is_item_list_empty(#xmlel{children = [Query]}) -> 4838: Query#xmlel.children == []. 4839: 4840: assert_is_message_correct(Room, SenderNick, Type, Text, ReceivedMessage) -> 4841: escalus_pred:is_message(ReceivedMessage), 4842: From = room_address(Room, SenderNick), 4843: From = exml_query:attr(ReceivedMessage, <<"from">>), 4844: Type = exml_query:attr(ReceivedMessage, <<"type">>), 4845: Body = #xmlel{name = <<"body">>, children = [#xmlcdata{content=Text}]}, 4846: Body = exml_query:subelement(ReceivedMessage, <<"body">>). 4847: 4848: assert_is_exit_message_correct(LeavingUser,Affiliation,Room, Message) -> 4849: escalus_pred:is_presence_with_type(<<"unavailable">>, Message), 4850: is_presence_with_affiliation(Message, Affiliation), 4851: From = room_address(Room, escalus_utils:get_username(LeavingUser)), 4852: From = exml_query:attr(Message, <<"from">>). 4853: 4854: is_exit_message_with_status_correct(LeavingUser,Affiliation,Room,Status, Message) -> 4855: escalus_pred:is_presence_with_type(<<"unavailable">>, Message), 4856: is_presence_with_affiliation(Message, Affiliation), 4857: From = room_address(Room, escalus_utils:get_username(LeavingUser)), 4858: From = exml_query:attr(Message, <<"from">>), 4859: Status = exml_query:path(Message, [{element,<<"status">>}, cdata]). 4860: 4861: is_nick_unavailable_correct(Room, OldNick, NewNick, ReceivedMessage) -> 4862: %error_logger:info_msg("tested message: ~n~p~n", [ReceivedMessage]), 4863: escalus_pred:is_message(ReceivedMessage), 4864: From = room_address(Room, OldNick), 4865: From = exml_query:attr(ReceivedMessage, <<"from">>), 4866: has_status_codes(ReceivedMessage, [<<"303">>]), 4867: NewNick = exml_query:path(ReceivedMessage, [{element, <<"x">>}, {element, <<"item">>},{attr, <<"nick">>}]). 4868: 4869: is_nick_update_correct(Room,NewNick, ReceivedMessage) -> 4870: %error_logger:info_msg("tested message: ~n~p~n", [ReceivedMessage]), 4871: escalus_pred:is_message(ReceivedMessage), 4872: From = room_address(Room,NewNick), 4873: From = exml_query:attr(ReceivedMessage, <<"from">>). 4874: 4875: print_next_message(User) -> 4876: error_logger:info_msg("~p messaege, ~n~p~n", [User, escalus:wait_for_stanza(User)]). 4877: 4878: print(Element) -> 4879: error_logger:info_msg("~n~p~n", [Element]). 4880: 4881: %Basic MUC protocol 4882: stanza_groupchat_enter_room(Room, Nick) -> 4883: stanza_to_room( 4884: escalus_stanza:presence(<<"available">>, 4885: [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), 4886: Room, Nick). 4887: 4888: 4889: stanza_groupchat_enter_room_no_nick(Room) -> 4890: stanza_to_room( 4891: escalus_stanza:presence(<<"available">>, 4892: [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}]}]), 4893: Room). 4894: 4895: stanza_muc_enter_password_protected_room(Room, Nick, Password) -> 4896: stanza_to_room( 4897: escalus_stanza:presence(<<"available">>, 4898: [#xmlel{name = <<"x">>, attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}], 4899: children = [#xmlel{name = <<"password">>, children = [#xmlcdata{content=[Password]}]} ]}]), 4900: Room, Nick). 4901: 4902: stanza_change_nick(Room, NewNick) -> 4903: stanza_to_room(escalus_stanza:presence(<<"available">>), Room, NewNick). 4904: 4905: start_rsm_rooms(Config, User, Nick) -> 4906: From = generate_rpc_jid(User), 4907: [muc_helper:create_instant_room(generate_room_name(N), From, Nick, []) 4908: || N <- lists:seq(1, 15)], 4909: Config. 4910: 4911: destroy_rsm_rooms(Config) -> 4912: [destroy_room(muc_host(), generate_room_name(N)) 4913: || N <- lists:seq(1, 15)], 4914: Config. 4915: 4916: generate_room_name(N) when is_integer(N) -> 4917: list_to_binary(io_lib:format("room~2..0B", [N])). 4918: 4919: generate_room_addr(N) -> 4920: room_address(generate_room_name(N)). 4921: 4922: generate_room_addrs(FromN, ToN) -> 4923: [generate_room_addr(N) || N <- lists:seq(FromN, ToN)]. 4924: 4925: %%-------------------------------------------------------------------- 4926: %% Helpers (stanzas) 4927: %%-------------------------------------------------------------------- 4928: 4929: stanza_message_to_room(Room, Payload) -> 4930: stanza_to_room(#xmlel{name = <<"message">>, children = Payload}, Room). 4931: 4932: stanza_private_muc_message(To, Msg) -> 4933: #xmlel{name = <<"message">>, 4934: attrs = [{<<"to">>, To}, {<<"type">>, <<"chat">>}], 4935: children = [#xmlel{name = <<"body">>, 4936: children = [#xmlcdata{content = Msg}]}, 4937: #xmlel{name = <<"x">>, 4938: attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc#user">>}]}]}. 4939: 4940: stanza_change_availability(NewStatus, Room, Nick) -> 4941: stanza_to_room( 4942: escalus_stanza:presence( <<"available">>, 4943: [ 4944: #xmlel{ name = <<"show">>, children=[ #xmlcdata{content=[<<"xa">>]}]}, 4945: #xmlel{ name = <<"status">>, children=[ #xmlcdata{content=[NewStatus]}]} 4946: ]), 4947: Room, Nick). 4948: 4949: stanza_muc_enter_room_history_setting(Room, Nick, Setting, Value) -> 4950: stanza_to_room( 4951: escalus_stanza:presence( <<"available">>, 4952: [#xmlel{ name = <<"x">>, 4953: attrs = [{<<"xmlns">>, <<"http://jabber.org/protocol/muc">>}], 4954: children = [#xmlel{name= <<"history">>, attrs=[{Setting, Value}]}] }]), 4955: Room, Nick). 4956: 4957: stanza_room_subject(Room, Subject) -> 4958: stanza_to_room(#xmlel{name = <<"message">>, 4959: attrs = [{<<"type">>,<<"groupchat">>}], 4960: children = [#xmlel{ 4961: name = <<"subject">>, 4962: children = [#xmlcdata{content = Subject}] 4963: }] 4964: }, Room). 4965: 4966: stanza_direct_invitation(Room, Inviter, Invited) -> 4967: #xmlel{ 4968: name = <<"message">>, 4969: attrs = [ 4970: {<<"from">>, escalus_utils:get_jid(Inviter)}, 4971: {<<"to">>, escalus_utils:get_short_jid(Invited)} 4972: ], 4973: children = [#xmlel{ 4974: name = <<"x">>, 4975: attrs = [ 4976: {<<"xmlns">>, ?NS_JABBER_X_CONF}, 4977: {<<"jid">>, room_address(Room)} 4978: ] 4979: }] 4980: }. 4981: 4982: stanza_mediated_invitation(Room, Invited) -> 4983: stanza_mediated_invitation_multi(Room, [Invited]). 4984: 4985: stanza_mediated_invitation_multi(Room, AllInvited) -> 4986: Payload = [ #xmlel{name = <<"invite">>, 4987: attrs = [{<<"to">>, escalus_utils:get_short_jid(Invited)}]} 4988: || Invited <- AllInvited ], 4989: stanza_to_room(#xmlel{name = <<"message">>, 4990: children = [ #xmlel{ 4991: name = <<"x">>, 4992: attrs = [{<<"xmlns">>, ?NS_MUC_USER}], 4993: children = Payload } 4994: ]}, Room). 4995: 4996: stanza_mediated_invitation_decline(Room,Sender) -> 4997: Payload = [ #xmlel{name = <<"decline">>, 4998: attrs = [{<<"to">>, escalus_utils:get_short_jid(Sender)}]} ], 4999: stanza_to_room(#xmlel{name = <<"message">>, 5000: children = [ #xmlel{ 5001: name = <<"x">>, 5002: attrs = [{<<"xmlns">>, ?NS_MUC_USER}], 5003: children = Payload } 5004: ]}, Room). 5005: 5006: stanza_set_roles(Room, List) -> 5007: Payload = lists:map(fun({Nick, Role}) -> 5008: #xmlel{name = <<"item">>, 5009: attrs = [{<<"nick">>, Nick}, {<<"role">>, Role}]}; 5010: ({Nick, Role, Reason}) -> 5011: #xmlel{name = <<"item">>, 5012: attrs = [{<<"nick">>, Nick}, {<<"role">>, Role}], 5013: children = [#xmlel{ 5014: name = <<"reason">>, 5015: children = [#xmlcdata{content = Reason}]} 5016: ]} 5017: end, List), 5018: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_ADMIN, Payload), Room). 5019: 5020: stanza_set_affiliations(Room, List) -> 5021: Payload = lists:map(fun({JID, Affiliation}) -> 5022: #xmlel{name = <<"item">>, 5023: attrs = [{<<"jid">>, JID}, {<<"affiliation">>, Affiliation}]}; 5024: ({JID, Affiliation, Reason}) -> 5025: #xmlel{name = <<"item">>, 5026: attrs = [{<<"jid">>, JID}, {<<"affiliation">>, Affiliation}], 5027: children = [#xmlel{ 5028: name = <<"reason">>, 5029: children = [#xmlcdata{content = Reason}]} 5030: ]} 5031: end, List), 5032: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_ADMIN, Payload), Room). 5033: 5034: stanza_role_list_request(Room, Role) -> 5035: Payload = [ #xmlel{name = <<"item">>, 5036: attrs = [{<<"role">>, Role}]} ], 5037: stanza_to_room(escalus_stanza:iq_get(?NS_MUC_ADMIN, Payload), Room). 5038: 5039: stanza_form_request(Room) -> 5040: Payload = [], 5041: stanza_to_room(escalus_stanza:iq_get(?NS_MUC_OWNER, Payload), Room). 5042: 5043: stanza_affiliation_list_request(Room, Affiliation) -> 5044: Payload = [ #xmlel{name = <<"item">>, 5045: attrs = [{<<"affiliation">>, Affiliation}]} ], 5046: stanza_to_room(escalus_stanza:iq_get(?NS_MUC_ADMIN, Payload), Room). 5047: 5048: stanza_ban_list_request(Room) -> 5049: stanza_affiliation_list_request(Room, <<"outcast">>). 5050: 5051: stanza_ban_user(User, Room) -> 5052: stanza_set_affiliations(Room, [{escalus_utils:get_short_jid(User), <<"outcast">>}]). 5053: 5054: stanza_ban_user(User, Room, Reason) -> 5055: stanza_set_affiliations(Room, [{escalus_utils:get_short_jid(User), <<"outcast">>, Reason}]). 5056: 5057: stanza_join_room(Room, Nick) -> 5058: stanza_to_room(#xmlel{name = <<"presence">>, children = 5059: [#xmlel{ 5060: name = <<"x">>, 5061: attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/muc">>}] 5062: }] 5063: },Room, Nick). 5064: 5065: %% stanza with multiple x subelements - empathy send additional x's 5066: stanza_join_room_many_x_elements(Room, Nick) -> 5067: stanza_to_room(#xmlel{name = <<"presence">>, children = 5068: [#xmlel{ 5069: name = <<"x">>, 5070: attrs = [{<<"xmlns">>,<<"vcard-temp:x:update">>}] 5071: }, 5072: #xmlel{ 5073: name = <<"x">>, 5074: attrs = [{<<"xmlns">>,<<"http://jabber.org/protocol/muc">>}] 5075: }] 5076: }, Room, Nick). 5077: 5078: stanza_voice_request_form(Room) -> 5079: Fields = [#{var => <<"muc#role">>, values => [<<"participant">>], type => <<"list-single">>}], 5080: stanza_message_to_room(Room, [form_helper:form(#{fields => Fields, ns => ?NS_MUC_REQUEST})]). 5081: 5082: stanza_voice_request_approval(Room, JID, Nick, Approved) -> 5083: Fields = [#{var => <<"muc#role">>, values => [<<"participant">>], type => <<"list-single">>}, 5084: #{var => <<"muc#jid">>, values => [JID], type => <<"jid-single">>}, 5085: #{var => <<"muc#roomnick">>, values => [Nick], type => <<"text-single">>}, 5086: #{var => <<"muc#request_allow">>, values => [atom_to_binary(Approved)], 5087: type => <<"boolean">>}], 5088: stanza_message_to_room(Room, [form_helper:form(#{fields => Fields, ns => ?NS_MUC_REQUEST})]). 5089: 5090: stanza_voice_request_approval_nonick(Room, JID) -> 5091: Fields = [#{var => <<"muc#role">>, values => [<<"participant">>], type => <<"list-single">>}, 5092: #{var => <<"muc#jid">>, values => [JID], type => <<"jid-single">>}, 5093: #{var => <<"muc#request_allow">>, values => [<<"true">>], type => <<"boolean">>}], 5094: stanza_message_to_room(Room, [form_helper:form(#{fields => Fields, ns => ?NS_MUC_REQUEST})]). 5095: 5096: stanza_configuration_form(Room, Fields) -> 5097: Form = form_helper:form(#{fields => Fields, ns => ?NS_MUC_ROOMCONFIG}), 5098: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_OWNER, [Form]), Room). 5099: 5100: stanza_cancel(Room) -> 5101: Payload = [form_helper:form(#{type => <<"cancel">>})], 5102: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_OWNER, Payload), Room). 5103: 5104: stanza_instant_room(Room) -> 5105: X = form_helper:form(#{}), 5106: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_OWNER, [X]), Room). 5107: 5108: stanza_configuration_form_request(Room) -> 5109: stanza_to_room(escalus_stanza:iq_get(?NS_MUC_OWNER, []), Room). 5110: 5111: stanza_destroy_room(Room) -> 5112: Payload = [ #xmlel{name = <<"destroy">>} ], 5113: stanza_to_room(escalus_stanza:iq_set(?NS_MUC_OWNER, Payload), Room). 5114: 5115: stanza_enter_room(Room, Nick) -> 5116: stanza_to_room(#xmlel{name = <<"presence">>}, Room, Nick). 5117: 5118: stanza_get_rooms() -> 5119: %% <iq from='hag66@shakespeare.lit/pda' 5120: %% id='zb8q41f4' 5121: %% to='chat.shakespeare.lit' 5122: %% type='get'> 5123: %% <query xmlns='http://jabber.org/protocol/disco#items'/> 5124: %% </iq> 5125: escalus_stanza:setattr(escalus_stanza:iq_get(?NS_DISCO_ITEMS, []), <<"to">>, 5126: muc_host()). 5127: 5128: 5129: stanza_get_services(_Config) -> 5130: %% <iq from='hag66@shakespeare.lit/pda' 5131: %% id='h7ns81g' 5132: %% to='shakespeare.lit' 5133: %% type='get'> 5134: %% <query xmlns='http://jabber.org/protocol/disco#items'/> 5135: %% </iq> 5136: escalus_stanza:setattr(escalus_stanza:iq_get(?NS_DISCO_ITEMS, []), <<"to">>, 5137: domain()). 5138: 5139: get_nick_form_iq() -> 5140: GetIQ = escalus_stanza:iq_get(<<"jabber:iq:register">>, []), 5141: escalus_stanza:to(GetIQ, muc_host()). 5142: 5143: remove_nick_form_iq() -> 5144: NS = <<"jabber:iq:register">>, 5145: RemoveEl = #xmlel{name = <<"remove">>}, 5146: SetIQ = escalus_stanza:iq_set(NS, [RemoveEl]), 5147: escalus_stanza:to(SetIQ, muc_host()). 5148: 5149: unset_nick(User) -> 5150: escalus:send_iq_and_wait_for_result(User, remove_nick_form_iq()). 5151: 5152: get_nick(User) -> 5153: ResultIQ = escalus:send_iq_and_wait_for_result(User, get_nick_form_iq()), 5154: true = form_has_field(<<"nick">>, ResultIQ), 5155: form_field_value(<<"nick">>, ResultIQ). 5156: 5157: %%-------------------------------------------------------------------- 5158: %% Helpers (assertions) 5159: %%-------------------------------------------------------------------- 5160: 5161: invite_has_reason(Stanza) -> 5162: exml_query:path(Stanza, [{element, <<"x">>}, {element, <<"invite">>}, 5163: {element, <<"reason">>}, cdata]) =/= undefined. 5164: 5165: has_reason(Stanza) -> 5166: exml_query:path(Stanza, [{element, <<"x">>}, {element, <<"item">>}, 5167: {element, <<"reason">>}]) =/= undefined. 5168: 5169: is_message_form(Stanza) -> 5170: exml_query:path(Stanza,[{element,<<"x">>}, 5171: {attr, <<"xmlns">>}]) =:= ?NS_DATA_FORMS. 5172: 5173: is_form(Stanza) -> 5174: exml_query:path(Stanza,[{element, <<"query">>}, {element,<<"x">>}, 5175: {attr, <<"xmlns">>}]) =:= ?NS_DATA_FORMS. 5176: 5177: form_has_field(VarName, Stanza) -> 5178: Path = [{element, <<"query">>}, 5179: {element, <<"x">>}, 5180: {element, <<"field">>}, 5181: {attr, <<"var">>}], 5182: Vars = exml_query:paths(Stanza, Path), 5183: lists:member(VarName, Vars). 5184: 5185: form_field_value(VarName, Stanza) -> 5186: Path = [{element, <<"query">>}, 5187: {element, <<"x">>}, 5188: {element, <<"field">>}], 5189: Fields = exml_query:paths(Stanza, Path), 5190: hd([exml_query:path(Field, [{element, <<"value">>}, cdata]) 5191: || Field <- Fields, 5192: exml_query:attr(Field, <<"var">>) == VarName]). 5193: 5194: is_groupchat_message(Stanza) -> 5195: escalus_pred:is_message(Stanza) andalso 5196: escalus_pred:has_type(<<"groupchat">>, Stanza). 5197: 5198: is_subject_message(Stanza) -> 5199: is_groupchat_message(Stanza) andalso 5200: exml_query:subelement(Stanza, <<"subject">>) /= undefined. 5201: 5202: is_subject_message(Stanza, Subject) -> 5203: is_groupchat_message(Stanza) andalso 5204: exml_query:path(Stanza, [{element,<<"subject">>},cdata]) == Subject. 5205: 5206: is_unavailable_presence(Stanza, Status) -> 5207: escalus_pred:is_presence_with_type(<<"unavailable">>,Stanza) andalso 5208: is_presence_with_status_code(Stanza, Status). 5209: 5210: is_membership_presence(Stanza, Affiliation, Role) -> 5211: is_presence_with_affiliation(Stanza, Affiliation) andalso 5212: is_presence_with_role(Stanza, Role). 5213: 5214: is_invitation(Stanza) -> 5215: escalus:assert(is_message, Stanza), 5216: #xmlel{} = exml_query:path(Stanza, [{element, <<"x">>}, {element, <<"invite">>}]). 5217: 5218: is_invitation_decline(Stanza) -> 5219: escalus:assert(is_message, Stanza), 5220: #xmlel{} = exml_query:path(Stanza, [{element, <<"x">>}, {element, <<"decline">>}]). 5221: 5222: is_direct_invitation(Stanza) -> 5223: escalus:assert(is_message, Stanza), 5224: #xmlel{} = exml_query:path(Stanza, [{element_with_ns, <<"x">>, ?NS_JABBER_X_CONF}]). 5225: 5226: is_presence_with_role(Stanza, Role) -> 5227: is_with_role(exml_query:subelement(Stanza, <<"x">>), Role). 5228: 5229: is_iq_with_role(Stanza, Role) -> 5230: is_with_role(exml_query:subelement(Stanza, <<"query">>), Role). 5231: 5232: is_with_role(Stanza, Role) -> 5233: Items = exml_query:subelements(Stanza, <<"item">>), 5234: lists:any(fun(Item) -> 5235: exml_query:attr(Item, <<"role">>) =:= Role 5236: end, Items). 5237: 5238: is_presence_with_nick(Stanza, Nick) -> 5239: escalus_pred:is_presence(Stanza) andalso 5240: exml_query:path(Stanza,[{element, <<"x">>}, 5241: {element, <<"item">>}, {attribute, <<"nick">>}]) == Nick. 5242: 5243: is_presence_with_affiliation(Stanza, Affiliation) -> 5244: is_affiliation(exml_query:subelement(Stanza, <<"x">>), Affiliation). 5245: 5246: is_iq_with_affiliation(Stanza, Affiliation) -> 5247: is_affiliation(exml_query:subelement(Stanza, <<"query">>), Affiliation). 5248: 5249: is_affiliation(Stanza, Affiliation) -> 5250: Items = exml_query:subelements(Stanza, <<"item">>), 5251: lists:any(fun(Item) -> 5252: exml_query:attr(Item, <<"affiliation">>) =:= Affiliation 5253: end, Items). 5254: 5255: is_presence_with_jid(Stanza, User) -> 5256: is_jid(exml_query:subelement(Stanza, <<"x">>), User). 5257: 5258: is_presence_with_full_jid(Stanza, User) -> 5259: is_full_jid(exml_query:subelement(Stanza, <<"x">>), User). 5260: 5261: is_iq_with_jid(Stanza, User) -> 5262: is_jid(exml_query:subelement(Stanza, <<"query">>), User). 5263: 5264: is_full_jid(Stanza, User) -> 5265: Item = exml_query:subelement(Stanza, <<"item">>), 5266: JID = escalus_utils:get_jid(User), 5267: JID = exml_query:attr(Item, <<"jid">>). 5268: 5269: is_jid(Stanza, User) -> 5270: Items = exml_query:subelements(Stanza, <<"item">>), 5271: JID = escalus_utils:get_jid(User), 5272: lists:any(fun(Item) -> exml_query:attr(Item, <<"jid">>) =:= JID end, Items). 5273: 5274: is_presence_with_short_jid(Stanza, User) -> 5275: is_short_jid(exml_query:subelement(Stanza, <<"x">>), User). 5276: 5277: is_iq_with_short_jid(Stanza, User) -> 5278: is_short_jid(exml_query:subelement(Stanza, <<"query">>), User). 5279: 5280: is_short_jid(Stanza, User) -> 5281: Items = exml_query:subelements(Stanza, <<"item">>), 5282: JID = escalus_utils:jid_to_lower(escalus_utils:get_short_jid(User)), 5283: lists:any(fun(Item) -> escalus_utils:jid_to_lower(exml_query:attr(Item, <<"jid">>)) =:= JID end, Items). 5284: 5285: is_presence_with_status_code(Presence, Code) -> 5286: escalus:assert(is_presence, Presence), 5287: Code == exml_query:path(Presence, [{element, <<"x">>}, {element, <<"status">>}, 5288: {attr, <<"code">>}]). 5289: 5290: is_message_with_status_code(Message, Code) -> 5291: escalus_pred:is_message(Message) andalso 5292: Code == exml_query:path(Message, [{element, <<"x">>}, {element, <<"status">>}, 5293: {attr, <<"code">>}]). 5294: 5295: has_x_elem(Message) -> 5296: exml_query:path(Message, [{element, <<"x">>}]) =/= undefined. 5297: 5298: has_status_codes(Stanza, CodeList) -> 5299: StatusList = exml_query:paths(Stanza, [{element, <<"x">>},{element, <<"status">>}]), 5300: StanzaCodes = lists:map(fun(Status) -> 5301: exml_query:attr(Status, <<"code">>) 5302: end, StatusList), 5303: true = lists:all(fun (Code) -> 5304: lists:member(Code, StanzaCodes) 5305: end, CodeList). 5306: 5307: 5308: has_feature(Stanza, Feature) -> 5309: Features = exml_query:paths(Stanza, [{element, <<"query">>}, 5310: {element, <<"feature">>}]), 5311: true = lists:any(fun(Item) -> 5312: exml_query:attr(Item, <<"var">>) == Feature 5313: end, 5314: Features). 5315: 5316: was_destroy_presented(#xmlel{children = [Items]} = Presence) -> 5317: #xmlel{} = exml_query:subelement(Items, <<"destroy">>), 5318: <<"unavailable">> = exml_query:attr(Presence, <<"type">>). 5319: 5320: was_room_destroyed(Query) -> 5321: timer:sleep(?WAIT_TIME), 5322: <<"result">> = exml_query:attr(Query, <<"type">>). 5323: 5324: was_room_created(Stanza) -> 5325: timer:sleep(?WAIT_TIME), 5326: has_status_codes(Stanza, [<<"201">>, <<"110">>]), 5327: [<<"owner">>] = exml_query:paths(Stanza, [{element, <<"x">>}, 5328: {element, <<"item">>}, 5329: {attr, <<"affiliation">>}]), 5330: [<<"moderator">>] = exml_query:paths(Stanza, [{element, <<"x">>}, 5331: {element, <<"item">>}, 5332: {attr, <<"role">>}]). 5333: 5334: has_room(JID, #xmlel{children = [ #xmlel{children = Rooms} ]}) -> 5335: %% <iq from='chat.shakespeare.lit' 5336: %% id='zb8q41f4' 5337: %% to='hag66@shakespeare.lit/pda' 5338: %% type='result'> 5339: %% <query xmlns='http://jabber.org/protocol/disco#items'> 5340: %% <item jid='heath@chat.shakespeare.lit' 5341: %% name='A Lonely Heath'/> 5342: %% <item jid='coven@chat.shakespeare.lit' 5343: %% name='A Dark Cave'/> 5344: %% <item jid='forres@chat.shakespeare.lit' 5345: %% name='The Palace'/> 5346: %% <item jid='inverness@chat.shakespeare.lit' 5347: %% name='Macbeth's Castle'/> 5348: %% </query> 5349: %% </iq> 5350: 5351: RoomPred = fun(Item) -> 5352: exml_query:attr(Item, <<"jid">>) == JID 5353: end, 5354: lists:any(RoomPred, Rooms). 5355: 5356: count_rooms(#xmlel{children = [ #xmlel{children = Rooms} ]}, N) -> 5357: ?assert_equal(N, length(Rooms)). 5358: 5359: has_muc(#xmlel{children = [ #xmlel{children = Services} ]}) -> 5360: %% should be along the lines of (taken straight from the XEP): 5361: %% <iq from='shakespeare.lit' 5362: %% id='h7ns81g' 5363: %% to='hag66@shakespeare.lit/pda' 5364: %% type='result'> 5365: %% <query xmlns='http://jabber.org/protocol/disco#items'> 5366: %% <item jid='chat.shakespeare.lit' 5367: %% name='Chatroom Service'/> 5368: %% </query> 5369: %% </iq> 5370: 5371: %% is like this: 5372: %% {xmlel,<<"iq">>, 5373: %% [{<<"from">>,<<"localhost">>}, 5374: %% {<<"to">>,<<"alice@localhost/res1">>}, 5375: %% {<<"id">>,<<"a5eb1dc70826598893b15f1936b18a34">>}, 5376: %% {<<"type">>,<<"result">>}], 5377: %% [{xmlel,<<"query">>, 5378: %% [{<<"xmlns">>, 5379: %% <<"http://jabber.org/protocol/disco#items">>}], 5380: %% [{xmlel,<<"item">>, 5381: %% [{<<"jid">>,<<"vjud.localhost">>}], 5382: %% []}, 5383: %% {xmlel,<<"item">>, 5384: %% [{<<"jid">>,<<"pubsub.localhost">>}], 5385: %% []}, 5386: %% {xmlel,<<"item">>, 5387: %% [{<<"jid">>,<<"muc.localhost">>}], 5388: %% []}, 5389: %% {xmlel,<<"item">>, 5390: %% [{<<"jid">>,<<"irc.localhost">>}], 5391: %% []}]}]} 5392: %% how to obtaing output like the above? simply put this in the test case: 5393: %% S = escalus:wait_for_stanza(Alice), 5394: %% error_logger:info_msg("~p~n", [S]), 5395: IsMUC = fun(Item) -> 5396: exml_query:attr(Item, <<"jid">>) == muc_host() 5397: end, 5398: lists:any(IsMUC, Services). 5399: 5400: is_room_locked(Stanza) -> 5401: escalus_pred:is_presence(Stanza) 5402: andalso 5403: escalus_pred:is_error(<<"cancel">>, <<"item-not-found">>, Stanza). 5404: 5405: fresh_nick_name(Prefix) -> 5406: <<Prefix/binary, (fresh_nick_name())/binary>>. 5407: 5408: fresh_nick_name() -> 5409: fresh_room_name(base16:encode(crypto:strong_rand_bytes(5))).