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