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