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