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