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