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