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