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