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