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