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