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