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