1: -module(rest_client_SUITE).
    2: -compile([export_all, nowarn_export_all]).
    3: 
    4: -include_lib("escalus/include/escalus.hrl").
    5: -include_lib("eunit/include/eunit.hrl").
    6: -include_lib("eunit/include/eunit.hrl").
    7: -include_lib("common_test/include/ct.hrl").
    8: 
    9: -import(rest_helper,
   10:         [decode_maplist/1,
   11:          gett/3,
   12:          post/4,
   13:          putt/4,
   14:          delete/3,
   15:          delete/4]
   16:          ).
   17: 
   18: -import(domain_helper, [host_type/0]).
   19: 
   20: -define(PRT(X, Y), ct:pal("~p: ~p", [X, Y])).
   21: -define(OK, {<<"200">>, <<"OK">>}).
   22: -define(CREATED, {<<"201">>, <<"Created">>}).
   23: -define(NOCONTENT, {<<"204">>, <<"No Content">>}).
   24: -define(ERROR, {<<"500">>, _}).
   25: -define(NOT_FOUND, {<<"404">>, _}).
   26: -define(NOT_IMPLEMENTED, {<<"501">>, _}).
   27: -define(UNAUTHORIZED, {<<"401">>, <<"Unauthorized">>}).
   28: 
   29: %% --------------------------------------------------------------------
   30: %% Common Test stuff
   31: %% --------------------------------------------------------------------
   32: 
   33: all() ->
   34:     [{group, messages},
   35:      {group, muc},
   36:      {group, muc_config},
   37:      {group, roster},
   38:      {group, messages_with_props},
   39:      {group, security}].
   40: 
   41: groups() ->
   42:     G = [{messages_with_props, [parallel], message_with_props_test_cases()},
   43:          {messages_with_thread, [parallel], message_with_thread_test_cases()},
   44:          {messages, [parallel], message_test_cases()},
   45:          {muc, [pararell], muc_test_cases()},
   46:          {muc_config, [], muc_config_cases()},
   47:          {roster, [parallel], roster_test_cases()},
   48:          {security, [], security_test_cases()}],
   49:     ct_helper:repeat_all_until_all_ok(G).
   50: 
   51: message_test_cases() ->
   52:     [msg_is_sent_and_delivered_over_xmpp,
   53:      msg_is_sent_and_delivered_over_sse,
   54:      all_messages_are_archived,
   55:      messages_with_user_are_archived,
   56:      messages_can_be_paginated].
   57: 
   58: muc_test_cases() ->
   59:      [room_is_created,
   60:       room_is_created_with_given_identifier,
   61:       user_is_invited_to_a_room,
   62:       user_is_removed_from_a_room,
   63:       rooms_can_be_listed,
   64:       owner_can_leave_a_room_and_auto_select_owner,
   65:       user_can_leave_a_room,
   66:       invitation_to_room_is_forbidden_for_non_memeber,
   67:       msg_is_sent_and_delivered_in_room,
   68:       sending_message_with_wrong_body_results_in_bad_request,
   69:       sending_message_with_no_body_results_in_bad_request,
   70:       sending_markable_message_with_no_body_results_in_bad_request,
   71:       sending_message_not_in_JSON_results_in_bad_request,
   72:       sending_message_by_not_room_member_results_in_forbidden,
   73:       messages_are_archived_in_room,
   74:       chat_markers_are_archived_in_room,
   75:       markable_property_is_archived_in_room,
   76:       only_room_participant_can_read_messages,
   77:       messages_can_be_paginated_in_room,
   78:       room_msg_is_sent_and_delivered_over_sse,
   79:       aff_change_msg_is_delivered_over_sse,
   80:       room_is_created_with_given_jid,
   81:       room_is_not_created_with_jid_not_matching_hostname,
   82:       room_can_be_fetched_by_jid,
   83:       messages_can_be_sent_and_fetched_by_room_jid,
   84:       user_can_be_added_and_removed_by_room_jid
   85:      ].
   86: 
   87: muc_config_cases() ->
   88:     [
   89:       config_can_be_changed_by_owner,
   90:       config_cannot_be_changed_by_member,
   91:       config_can_be_changed_by_all
   92:     ].
   93: 
   94: roster_test_cases() ->
   95:     [add_contact_and_invite,
   96:      add_contact_and_be_invited,
   97:      add_and_remove,
   98:      add_and_remove_some_contacts_properly,
   99:      add_and_remove_some_contacts_with_nonexisting,
  100:      break_stuff].
  101: 
  102: message_with_props_test_cases() ->
  103:     [
  104:      msg_with_props_is_sent_and_delivered_over_xmpp,
  105:      msg_with_props_can_be_parsed,
  106:      msg_with_malformed_props_can_be_parsed,
  107:      msg_with_malformed_props_is_sent_and_delivered_over_xmpp
  108:      ].
  109: 
  110: message_with_thread_test_cases() ->
  111:     [msg_with_thread_is_sent_and_delivered_over_xmpp,
  112:      msg_with_thread_can_be_parsed,
  113:      msg_with_thread_and_parent_is_sent_and_delivered_over_xmpp,
  114:      msg_with_thread_and_parent_can_be_parse,
  115:      msg_without_thread_can_be_parsed,
  116:      msg_without_thread_is_sent_and_delivered_over_xmpp].
  117: 
  118: security_test_cases() ->
  119:     [
  120:      default_http_server_name_is_returned_if_not_changed,
  121:      non_default_http_server_name_is_returned_if_configured
  122:     ].
  123: 
  124: init_per_suite(Config) ->
  125:     Config1 = init_modules(Config),
  126:     [{muc_light_host, muc_light_helper:muc_host()}
  127:      | escalus:init_per_suite(Config1)].
  128: 
  129: end_per_suite(Config) ->
  130:     escalus_fresh:clean(),
  131:     dynamic_modules:restore_modules(Config),
  132:     escalus:end_per_suite(Config).
  133: 
  134: init_modules(Config) ->
  135:     HostType = host_type(),
  136:     Config1 = dynamic_modules:save_modules(HostType, Config),
  137:     Config2 = rest_helper:maybe_enable_mam(mam_helper:backend(), HostType, Config1),
  138:     dynamic_modules:ensure_modules(HostType, required_modules(suite)),
  139:     Config2.
  140: 
  141: init_per_group(_GN, C) ->
  142:     C.
  143: 
  144: end_per_group(_GN, C) ->
  145:     C.
  146: 
  147: init_per_testcase(config_can_be_changed_by_all = TC, Config) ->
  148:     HostType = host_type(),
  149:     DefaultConfig = dynamic_modules:save_modules(HostType, Config),
  150:     dynamic_modules:ensure_modules(HostType, required_modules(TC)),
  151:     escalus:init_per_testcase(config_can_be_changed_by_all, DefaultConfig);
  152: init_per_testcase(TC, Config) ->
  153:     MAMTestCases = [all_messages_are_archived,
  154:                     messages_with_user_are_archived,
  155:                     messages_can_be_paginated,
  156:                     messages_are_archived_in_room,
  157:                     chat_markers_are_archived_in_room,
  158:                     markable_property_is_archived_in_room,
  159:                     only_room_participant_can_read_messages,
  160:                     messages_can_be_paginated_in_room,
  161:                     messages_can_be_sent_and_fetched_by_room_jid,
  162:                     msg_with_props_is_sent_and_delivered_over_xmpp,
  163:                     msg_with_props_can_be_parsed,
  164:                     msg_with_malformed_props_can_be_parsed,
  165:                     msg_with_malformed_props_is_sent_and_delivered_over_xmpp,
  166:                     msg_with_thread_is_sent_and_delivered_over_xmpp,
  167:                     msg_with_thread_can_be_parse,
  168:                     msg_with_thread_and_parent_is_sent_and_delivered_over_xmpp,
  169:                     msg_with_thread_and_parent_can_be_parse,
  170:                     msg_without_thread_can_be_parsed,
  171:                     msg_without_thread_is_sent_and_delivered_over_xmpp
  172:                    ],
  173:     rest_helper:maybe_skip_mam_test_cases(TC, MAMTestCases, Config).
  174: 
  175: end_per_testcase(config_can_be_changed_by_all, Config) ->
  176:     dynamic_modules:restore_modules(Config),
  177:     escalus:end_per_testcase(config_can_be_changed_by_all, Config);
  178: end_per_testcase(TC, C) ->
  179:     escalus:end_per_testcase(TC, C).
  180: 
  181: %% Module configuration - set up per suite and for special test cases
  182: %% TODO: include MAM configuration here
  183: 
  184: required_modules(SuiteOrTC) ->
  185:     [{mod_muc_light, common_muc_light_opts() ++ muc_light_opts(SuiteOrTC)}].
  186: 
  187: muc_light_opts(config_can_be_changed_by_all) ->
  188:     [{all_can_configure, true}];
  189: muc_light_opts(suite) ->
  190:     [].
  191: 
  192: common_muc_light_opts() ->
  193:     MucPattern = distributed_helper:subhost_pattern(muc_light_helper:muc_host_pattern()),
  194:     [{host, MucPattern},
  195:      {rooms_in_rosters, true}].
  196: 
  197: %% --------------------------------------------------------------------
  198: %% Test cases
  199: %% --------------------------------------------------------------------
  200: 
  201: msg_is_sent_and_delivered_over_xmpp(Config) ->
  202:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  203:         M = send_message(alice, Alice, Bob),
  204:         Msg = escalus:wait_for_stanza(Bob),
  205:         escalus:assert(is_chat_message, [maps:get(body, M)], Msg)
  206:     end).
  207: 
  208: msg_is_sent_and_delivered_over_sse(ConfigIn) ->
  209:     Config = escalus_fresh:create_users(ConfigIn, [{alice, 1}, {bob, 1}]),
  210:     Bob = escalus_users:get_userspec(Config, bob),
  211:     Alice = escalus_users:get_userspec(Config, alice),
  212: 
  213:     Conn = connect_to_sse({alice, Alice}),
  214:     M = send_message(bob, Bob, Alice),
  215: 
  216:     Event = wait_for_event(Conn),
  217:     Data = jiffy:decode(maps:get(data, Event), [return_maps]),
  218: 
  219:     assert_json_message(M, Data),
  220: 
  221:     stop_sse(Conn).
  222: 
  223: room_msg_is_sent_and_delivered_over_sse(ConfigIn) ->
  224:     Config = escalus_fresh:create_users(ConfigIn, [{alice, 1}, {bob, 1}]),
  225:     Bob = escalus_users:get_userspec(Config, bob),
  226:     Alice = escalus_users:get_userspec(Config, alice),
  227:     RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  228:     RoomInfo = get_room_info({alice, Alice}, RoomID),
  229:     true = is_participant(Bob, <<"member">>, RoomInfo),
  230:     Conn = connect_to_sse({bob, Bob}),
  231:     Message = given_message_sent_to_room(RoomID, {alice, Alice}),
  232:     Event = wait_for_event(Conn),
  233:     Data = jiffy:decode(maps:get(data, Event), [return_maps]),
  234:     assert_json_room_sse_message(Message#{room => RoomID, type => <<"message">>},
  235:                                  Data),
  236:     stop_sse(Conn).
  237: 
  238: aff_change_msg_is_delivered_over_sse(ConfigIn) ->
  239:     Config = escalus_fresh:create_users(ConfigIn, [{alice, 1}, {bob, 1}]),
  240:     Bob = escalus_users:get_userspec(Config, bob),
  241:     Alice = escalus_users:get_userspec(Config, alice),
  242:     RoomID = given_new_room({alice, Alice}),
  243:     Conn = connect_to_sse({bob, Bob}),
  244:     given_user_invited({alice, Alice}, RoomID, Bob),
  245:     Event = wait_for_event(Conn),
  246:     Data = jiffy:decode(maps:get(data, Event), [return_maps]),
  247:     BobJID = user_jid(Bob),
  248:     RoomJID = room_jid(RoomID, Config),
  249:     assert_json_room_sse_message(#{room => RoomID,
  250:                                    from => RoomJID,
  251:                                    type => <<"affiliation">>,
  252:                                    user => BobJID},
  253:                                  Data),
  254:     stop_sse(Conn).
  255: 
  256: all_messages_are_archived(Config) ->
  257:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) ->
  258:         Sent = [M1 | _] = send_messages(Config, Alice, Bob, Kate),
  259:         AliceJID = maps:get(to, M1),
  260:         AliceCreds = {AliceJID, user_password(alice)},
  261:         GetPath = lists:flatten("/messages/"),
  262:         {{<<"200">>, <<"OK">>}, Msgs} = rest_helper:gett(client, GetPath, AliceCreds),
  263:         Received = [_Msg1, _Msg2, _Msg3] = rest_helper:decode_maplist(Msgs),
  264:         assert_messages(Sent, Received)
  265: 
  266:     end).
  267: 
  268: messages_with_user_are_archived(Config) ->
  269:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) ->
  270:         [M1, _M2, M3] = send_messages(Config, Alice, Bob, Kate),
  271:         AliceJID = maps:get(to, M1),
  272:         KateJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Kate)),
  273:         AliceCreds = {AliceJID, user_password(alice)},
  274:         GetPath = lists:flatten(["/messages/", binary_to_list(KateJID)]),
  275:         {{<<"200">>, <<"OK">>}, Msgs} = rest_helper:gett(client, GetPath, AliceCreds),
  276:         Recv = [_Msg2] = rest_helper:decode_maplist(Msgs),
  277:         assert_messages([M3], Recv)
  278: 
  279:     end).
  280: 
  281: messages_can_be_paginated(Config) ->
  282:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  283:         AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  284:         BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  285:         rest_helper:fill_archive(Alice, Bob),
  286:         mam_helper:maybe_wait_for_archive(Config),
  287:         AliceCreds = {AliceJID, user_password(alice)},
  288:         % recent msgs with a limit
  289:         M1 = get_messages(AliceCreds, BobJID, 10),
  290:         6 = length(M1),
  291:         M2 = get_messages(AliceCreds, BobJID, 3),
  292:         3 = length(M2),
  293:         % older messages - earlier then the previous midnight
  294:         PriorTo = rest_helper:make_timestamp(-1, {0, 0, 1}),
  295:         M3 = get_messages(AliceCreds, BobJID, PriorTo, 10),
  296:         4 = length(M3),
  297:         [Oldest|_] = M3,
  298:         <<"A">> = maps:get(body, Oldest),
  299:         % same with limit
  300:         M4 = get_messages(AliceCreds, BobJID, PriorTo, 2),
  301:         2 = length(M4),
  302:         [Oldest2|_] = M4,
  303:         <<"B">> = maps:get(body, Oldest2)
  304:     end).
  305: 
  306: room_is_created(Config) ->
  307:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  308:         RoomID = given_new_room({alice, Alice}),
  309:         RoomInfo = get_room_info({alice, Alice}, RoomID),
  310:         assert_room_info(Alice, RoomInfo)
  311:     end).
  312: 
  313: room_is_created_with_given_identifier(Config) ->
  314:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  315:         GivenRoomID = muc_helper:fresh_room_name(),
  316:         GivenRoomID = given_new_room({alice, Alice}, GivenRoomID),
  317:         RoomInfo = get_room_info({alice, Alice}, GivenRoomID),
  318:         assert_room_info(Alice, RoomInfo)
  319:     end).
  320: 
  321: config_can_be_changed_by_owner(Config) ->
  322:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  323:         RoomID = muc_helper:fresh_room_name(),
  324:         RoomJID = room_jid(RoomID, Config),
  325:         RoomID = given_new_room({alice, Alice}, RoomJID, <<"old_name">>),
  326:         RoomInfo = get_room_info({alice, Alice}, RoomID),
  327:         assert_property_value(<<"name">>, <<"old_name">>, RoomInfo),
  328: 
  329:         {{<<"204">>,<<"No Content">>},<<>>} =
  330:             when_config_change({alice, Alice}, RoomJID, <<"new_name">>, <<"new_subject">>),
  331:         NewRoomInfo = get_room_info({alice, Alice}, RoomID),
  332:         assert_property_value(<<"name">>, <<"new_name">>, NewRoomInfo),
  333:         assert_property_value(<<"subject">>, <<"new_subject">>, NewRoomInfo)
  334:     end).
  335: 
  336: config_cannot_be_changed_by_member(Config) ->
  337:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  338:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  339:         RoomJID = room_jid(RoomID, Config),
  340:         {{<<"403">>,<<"Forbidden">>},<<>>} =
  341:             when_config_change({bob, Bob}, RoomJID, <<"other_name">>, <<"other_subject">>),
  342:         NewRoomInfo = get_room_info({bob, Bob}, RoomID),
  343:         assert_property_value(<<"name">>,<<"new_room_name">>, NewRoomInfo)
  344:     end).
  345: 
  346: config_can_be_changed_by_all(Config) ->
  347:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  348:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  349:         RoomJID = room_jid(RoomID, Config),
  350:         RoomInfo = get_room_info({alice, Alice}, RoomID),
  351:         assert_property_value(<<"name">>,<<"new_room_name">>,RoomInfo),
  352:         {{<<"204">>,<<"No Content">>},<<>>} =
  353:             when_config_change({bob, Bob}, RoomJID, <<"other_name">>, <<"other_subject">>),
  354:         NewRoomInfo = get_room_info({alice, Alice}, RoomID),
  355:         assert_property_value(<<"name">>,<<"other_name">>,NewRoomInfo)
  356:     end).
  357: 
  358: rooms_can_be_listed(Config) ->
  359:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  360:         [] = get_my_rooms({alice, Alice}),
  361:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  362:         [{Room}] = get_my_rooms({alice, Alice}),
  363:         RoomMap = maps:from_list(Room),
  364:         RoomID = maps:get(<<"id">>, RoomMap),
  365:         true = maps:is_key(<<"name">>, RoomMap),
  366:         true = maps:is_key(<<"subject">>, RoomMap),
  367:         [{Room}] = get_my_rooms({bob, Bob})
  368:     end).
  369: 
  370: user_is_invited_to_a_room(Config) ->
  371:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  372:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  373:         RoomInfo = get_room_info({alice, Alice}, RoomID),
  374:         true = is_participant(Bob, <<"member">>, RoomInfo),
  375:         IQ = escalus_stanza:iq_get(<<"urn:xmpp:muclight:0#affiliations">>, []),
  376:         RoomJID = room_jid(RoomID, Config),
  377:         escalus:send(Alice, escalus_stanza:to(IQ, RoomJID)),
  378:         escalus:assert(is_iq_result, [IQ], escalus:wait_for_stanza(Alice))
  379: 
  380:     end).
  381: 
  382: user_is_removed_from_a_room(Config) ->
  383:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  384:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  385:         {{<<"204">>, _}, _} = remove_user_from_a_room({alice, Alice}, RoomID, Bob),
  386:         Stanza = escalus:wait_for_stanza(Bob),
  387:         assert_aff_change_stanza(Stanza, Bob, <<"none">>)
  388:     end).
  389: 
  390: owner_can_leave_a_room_and_auto_select_owner(Config) ->
  391:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  392:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  393:         {{<<"204">>, _}, _} = remove_user_from_a_room({alice, Alice}, RoomID, Alice),
  394:         Stanza = escalus:wait_for_stanza(Bob),
  395:         assert_aff_change_stanza(Stanza, Alice, <<"none">>),
  396:         assert_aff_change_stanza(Stanza, Bob, <<"owner">>)
  397:     end).
  398: 
  399: user_can_leave_a_room(Config) ->
  400:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  401:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  402:         {{<<"204">>, _}, _} = remove_user_from_a_room({bob, Bob}, RoomID, Bob),
  403:         Stanza = escalus:wait_for_stanza(Bob),
  404:         assert_aff_change_stanza(Stanza, Bob, <<"none">>)
  405:     end).
  406: 
  407: invitation_to_room_is_forbidden_for_non_memeber(Config) ->
  408:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  409:         RoomID = given_new_room({alice, Alice}),
  410:         {{<<"403">>, <<"Forbidden">>}, _ } = invite_to_room({bob, Bob}, RoomID,
  411:                                                             <<"auser@domain.com">>)
  412:     end).
  413: 
  414: msg_is_sent_and_delivered_in_room(Config) ->
  415:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  416:         given_new_room_with_users_and_msgs({alice, Alice}, [{bob, Bob}])
  417:     end).
  418: 
  419: 
  420: sending_message_by_not_room_member_results_in_forbidden(Config) ->
  421:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  422:         Sender = {alice, Alice},
  423:         RoomID = given_new_room_with_users(Sender, []),
  424:         Result = given_message_sent_to_room(RoomID, {bob, Bob}, #{body => <<"Hello, I'm not member">>}),
  425:         ?assertMatch({{<<"403">>, <<"Forbidden">>}, _}, Result)
  426: 
  427:     end).
  428: 
  429: sending_message_with_wrong_body_results_in_bad_request(Config) ->
  430:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  431:         Sender = {alice, Alice},
  432:         RoomID = given_new_room_with_users(Sender, []),
  433:         Result = given_message_sent_to_room(RoomID, Sender, #{body => #{nested => <<"structure">>}}),
  434:         ?assertMatch({{<<"400">>, <<"Bad Request">>}, <<"Invalid body, it must be a string">>}, Result)
  435:     end).
  436: 
  437: sending_message_with_no_body_results_in_bad_request(Config) ->
  438:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  439:         Sender = {alice, Alice},
  440:         RoomID = given_new_room_with_users(Sender, []),
  441:         Result = given_message_sent_to_room(RoomID, Sender, #{no_body => <<"This should be in body element">>}),
  442:         ?assertMatch({{<<"400">>, <<"Bad Request">>}, <<"No valid message elements">>}, Result)
  443:     end).
  444: 
  445: sending_markable_message_with_no_body_results_in_bad_request(Config) ->
  446:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  447:         Sender = {alice, Alice},
  448:         RoomID = given_new_room_with_users(Sender, []),
  449:         Result = given_message_sent_to_room(RoomID, Sender, #{markable => true}),
  450:         ?assertMatch({{<<"400">>, <<"Bad Request">>}, <<"No valid message elements">>}, Result)
  451:     end).
  452: 
  453: sending_message_not_in_JSON_results_in_bad_request(Config) ->
  454:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  455:         Sender = {alice, Alice},
  456:         RoomID = given_new_room_with_users(Sender, []),
  457:         Result = given_message_sent_to_room(RoomID, Sender, <<"This is not JSON object">>),
  458:         ?assertMatch({{<<"400">>, <<"Bad Request">>}, <<"Request body is not a valid JSON">>}, Result)
  459:     end).
  460: 
  461: messages_are_archived_in_room(Config) ->
  462:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  463:         {RoomID, _Msgs} = given_new_room_with_users_and_msgs({alice, Alice}, [{bob, Bob}]),
  464:         mam_helper:maybe_wait_for_archive(Config),
  465:         {{<<"200">>, <<"OK">>}, Result} = get_room_messages({alice, Alice}, RoomID),
  466:         [Aff, _Msg1, _Msg2] = rest_helper:decode_maplist(Result),
  467:         %% The oldest message is aff change
  468:         <<"affiliation">> = maps:get(type, Aff),
  469:         <<"member">> = maps:get(affiliation, Aff),
  470:         BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  471:         BobJID = maps:get(user, Aff)
  472:     end).
  473: 
  474: chat_markers_are_archived_in_room(Config) ->
  475:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  476:         % GIVEN 3 different chat markers that are sent via HTTP and received via XMPP
  477:         MarkedID = <<"RagnarokIsComing">>,
  478:         MarkerTypes = [<<"received">>, <<"displayed">>, <<"acknowledged">>],
  479:         Markers = [#{ chat_marker => #{ type => Type, id => MarkedID } } || Type <- MarkerTypes ],
  480:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  481:         lists:foreach(fun(Marker) ->
  482:                               {{<<"200">>, <<"OK">>}, {_Result}} =
  483:                               given_message_sent_to_room(RoomID, {bob, Bob}, Marker),
  484:                               [ escalus:wait_for_stanza(Client) || Client <- [Alice, Bob] ]
  485:                       end, Markers),
  486:         mam_helper:maybe_wait_for_archive(Config),
  487: 
  488:         % WHEN an archive is queried via HTTP
  489:         {{<<"200">>, <<"OK">>}, Result} = get_room_messages({alice, Alice}, RoomID),
  490: 
  491:         % THEN these markers are retrieved and in proper order and with valid payload
  492:         % (we discard remaining msg fields, they are tested by other cases)
  493:         [_Aff | ReceivedMarkers] = rest_helper:decode_maplist(Result),
  494:         Markers = [ maps:with([chat_marker], RecvMarker) || RecvMarker <- ReceivedMarkers ]
  495:     end).
  496: 
  497: % Combo test case which verifies both the translation of "markable" element
  498: % (JSON -> XML -> JSON) and if it's preserved properly in the archive
  499: markable_property_is_archived_in_room(Config) ->
  500:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  501:         % GIVEN a markable message is sent in the room
  502:         MarkableMsg = #{ markable => true, body => <<"Floor is lava!">> },
  503:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  504:         {{<<"200">>, <<"OK">>}, {_Result}}
  505:         = given_message_sent_to_room(RoomID, {bob, Bob}, MarkableMsg),
  506:         [ escalus:wait_for_stanza(Client) || Client <- [Alice, Bob] ],
  507:         mam_helper:maybe_wait_for_archive(Config),
  508: 
  509:         % WHEN an archive is queried via HTTP
  510:         {{<<"200">>, <<"OK">>}, Result} = get_room_messages({alice, Alice}, RoomID),
  511: 
  512:         % THEN the retrieved message has markable property
  513:         [_Aff, Msg] = rest_helper:decode_maplist(Result),
  514:         true = maps:get(markable, Msg, undefined)
  515:     end).
  516: 
  517: only_room_participant_can_read_messages(Config) ->
  518:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  519:         RoomID = given_new_room({alice, Alice}),
  520:         {{<<"403">>, <<"Forbidden">>}, _} = get_room_messages({bob, Bob}, RoomID),
  521:         ok
  522:     end).
  523: 
  524: get_room_messages(Caller, RoomID) ->
  525:     Path = <<"/rooms/", RoomID/binary, "/messages">>,
  526:     Creds = credentials(Caller),
  527:     rest_helper:gett(client, Path, Creds).
  528: 
  529: messages_can_be_paginated_in_room(Config) ->
  530:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  531:         RoomID = given_new_room_with_users({alice, Alice}, [{bob, Bob}]),
  532:         %% GenMsgs1 is older than GenMsgs2
  533:         %% One message is already in the archive
  534:         [GenMsgs1, GenMsgs2 | _] = rest_helper:fill_room_archive(RoomID, [Alice, Bob], 1),
  535:         mam_helper:maybe_wait_for_archive(Config),
  536:         Msgs10 = get_room_messages({alice, Alice}, RoomID, 10),
  537:         Msgs10Len = length(Msgs10),
  538:         true = Msgs10Len > 0 andalso Msgs10Len =< 10,
  539:         Msgs3 = get_room_messages({alice, Alice}, RoomID, 3),
  540:         [_, _, _] = Msgs3,
  541:         {_, Time} = calendar:now_to_datetime(os:timestamp()),
  542:         PriorTo = rest_helper:make_timestamp(-1, Time) - timer:seconds(10),
  543:         [OldestMsg1 | _] = get_room_messages({alice, Alice}, RoomID, 4, PriorTo),
  544:         assert_room_messages(OldestMsg1, hd(lists:keysort(1, GenMsgs1))),
  545:         [OldestMsg2 | _] = get_room_messages({alice, Alice}, RoomID, 2, PriorTo),
  546:         assert_room_messages(OldestMsg2, hd(lists:keysort(1, GenMsgs2)))
  547:     end).
  548: 
  549: room_is_created_with_given_jid(Config) ->
  550:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  551:         RoomID = muc_helper:fresh_room_name(),
  552:         RoomJID = room_jid(RoomID, Config),
  553:         RoomID = given_new_room({alice, Alice}, RoomJID),
  554:         RoomInfo = get_room_info({alice, Alice}, RoomID),
  555:         assert_room_info(Alice, RoomInfo)
  556:     end).
  557: 
  558: room_is_not_created_with_jid_not_matching_hostname(Config) ->
  559:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  560:         RoomID = muc_helper:fresh_room_name(),
  561:         RoomJID = <<RoomID/binary, "@muclight.wrongdomain">>,
  562:         Creds = credentials({alice, Alice}),
  563:         {{Status, _}, _} = create_room_with_id_request(Creds,
  564:                                                        <<"some_name">>,
  565:                                                        <<"some subject">>,
  566:                                                        RoomJID),
  567:         ?assertEqual(<<"400">>, Status)
  568:     end).
  569: 
  570: room_can_be_fetched_by_jid(Config) ->
  571:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  572:         RoomID = muc_helper:fresh_room_name(),
  573:         RoomJID = room_jid(RoomID, Config),
  574:         RoomID = given_new_room({alice, Alice}, RoomJID),
  575:         RoomInfo = get_room_info({alice, Alice}, RoomJID),
  576:         assert_room_info(Alice, RoomInfo)
  577:     end).
  578: 
  579: messages_can_be_sent_and_fetched_by_room_jid(Config) ->
  580:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, _Bob) ->
  581:         RoomID = given_new_room({alice, Alice}),
  582:         RoomJID = room_jid(RoomID, Config),
  583:         given_message_sent_to_room(RoomJID, {alice, Alice}),
  584:         mam_helper:maybe_wait_for_archive(Config),
  585:         [_] = get_room_messages({alice, Alice}, RoomJID, 10)
  586:     end).
  587: 
  588: user_can_be_added_and_removed_by_room_jid(Config) ->
  589:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  590:         RoomID = given_new_room({alice, Alice}),
  591:         RoomJID = room_jid(RoomID, Config),
  592:         given_user_invited({alice, Alice}, RoomJID, Bob),
  593:         {{Status, _}, _} = remove_user_from_a_room({alice, Alice}, RoomJID, Bob),
  594:         ?assertEqual(<<"204">>, Status)
  595:     end).
  596: 
  597: msg_with_props_is_sent_and_delivered_over_xmpp(Config) ->
  598:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  599:         BobJID = user_jid(Bob),
  600:         MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  601:         M1 = rest_helper:make_msg_stanza_with_props(BobJID,MsgID),
  602: 
  603:         escalus:send(Alice, M1),
  604: 
  605:         M2 = escalus:wait_for_stanza(Bob),
  606:         escalus:assert(is_message, M2)
  607:     end).
  608: 
  609: msg_with_props_can_be_parsed(Config) ->
  610:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  611:         AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  612:         BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  613:         MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  614:         M1 = rest_helper:make_msg_stanza_with_props(BobJID,MsgID),
  615: 
  616:         escalus:send(Alice, M1),
  617: 
  618:         escalus:wait_for_stanza(Bob),
  619:         mam_helper:wait_for_archive_size(Bob, 1),
  620:         mam_helper:wait_for_archive_size(Alice, 1),
  621: 
  622:         AliceCreds = {AliceJID, user_password(alice)},
  623: 
  624:         % recent msgs with a limit
  625:         M2 = get_messages_with_props(AliceCreds, BobJID, 1),
  626: 
  627:         [{MsgWithProps} | _] = M2,
  628: 
  629:         Data = maps:from_list(MsgWithProps),
  630: 
  631:         #{<<"properties">> := {Props},
  632:           <<"id">> := ReceivedMsgID} = Data,
  633: 
  634:         %we are expecting two properties:"some_string" and "some_number" for this test message
  635:         %test message defined in rest_helper:make_msg_stanza_with_props
  636:         2 = length(Props),
  637:         ReceivedMsgID = MsgID
  638: 
  639:     end).
  640: 
  641: msg_with_malformed_props_is_sent_and_delivered_over_xmpp(Config) ->
  642:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  643:         BobJID = user_jid(Bob),
  644:         MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  645: 
  646:         M1 = rest_helper:make_malformed_msg_stanza_with_props(BobJID, MsgID),
  647: 
  648:         escalus:send(Alice, M1),
  649: 
  650:         M2 = escalus:wait_for_stanza(Bob),
  651:         escalus:assert(is_message, M2)
  652:     end).
  653: 
  654: msg_with_malformed_props_can_be_parsed(Config) ->
  655:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  656:         AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  657:         AliceCreds = {AliceJID, user_password(alice)},
  658:         BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  659:         MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  660: 
  661:         M1 = rest_helper:make_malformed_msg_stanza_with_props(BobJID,MsgID),
  662:         escalus:send(Alice, M1),
  663: 
  664:         escalus:wait_for_stanza(Bob),
  665:         mam_helper:wait_for_archive_size(Bob, 1),
  666:         mam_helper:wait_for_archive_size(Alice, 1),
  667: 
  668:         % recent msgs with a limit
  669:         M2 = get_messages_with_props(AliceCreds, BobJID, 1),
  670:         [_Msg] = rest_helper:decode_maplist(M2),
  671: 
  672:         MsgID = maps:get(id, _Msg)
  673: 
  674:     end).
  675: 
  676: msg_with_thread_is_sent_and_delivered_over_xmpp(Config) ->
  677:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  678: 				BobJID = user_jid(Bob),
  679: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  680: 				ThreadID = base16:encode(crypto:strong_rand_bytes(5)),
  681: 				M1 = rest_helper:make_msg_stanza_with_thread(BobJID, MsgID, ThreadID),
  682: 				escalus:send(Alice, M1),
  683: 				M2 = escalus:wait_for_stanza(Bob),
  684: 				escalus:assert(is_message, M2)
  685: 		end).
  686: 
  687: msg_with_thread_can_be_parsed(Config) ->
  688:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  689: 				AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  690: 				BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  691: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  692: 				ThreadID = base16:encode(crypto:strong_rand_bytes(5)),
  693: 				M1 = rest_helper:make_msg_stanza_with_thread(BobJID, MsgID, ThreadID),
  694: 				escalus:send(Alice, M1),
  695: 				escalus:wait_for_stanza(Bob),
  696: 				mam_helper:wait_for_archive_size(Bob, 1),
  697: 				mam_helper:wait_for_archive_size(Alice, 1),
  698: 				AliceCreds = {AliceJID, user_password(alice)},
  699: 				% recent msgs with a limit
  700: 				M2 = get_messages_with_props(AliceCreds, BobJID, 1),
  701: 				[{MsgWithProps} | _] = M2,
  702: 				Data = maps:from_list(MsgWithProps),
  703: 				#{<<"thread">> := ReceivedThreadID,
  704: 				  <<"id">> := ReceivedMsgID} = Data,
  705: 				%we are expecting thread and parent thread for this test message
  706: 				%test message defined in rest_helper:make_msg_stanza_with_thread
  707: 				ReceivedThreadID = ThreadID,
  708: 				ReceivedMsgID = MsgID
  709: 		end).
  710: 
  711: msg_with_thread_and_parent_is_sent_and_delivered_over_xmpp(Config) ->
  712:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  713: 				BobJID = user_jid(Bob),
  714: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  715: 				ThreadID = base16:encode(crypto:strong_rand_bytes(5)),
  716: 				ThreadParentID = base16:encode(crypto:strong_rand_bytes(5)),
  717: 				M1 = rest_helper:make_msg_stanza_with_thread_and_parent(BobJID, MsgID, ThreadID, ThreadParentID),
  718: 				escalus:send(Alice, M1),
  719: 				M2 = escalus:wait_for_stanza(Bob),
  720: 				escalus:assert(is_message, M2)
  721: 		end).
  722: 
  723: msg_with_thread_and_parent_can_be_parsed(Config) ->
  724:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  725: 				AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  726: 				BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  727: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  728: 				ThreadID = base16:encode(crypto:strong_rand_bytes(5)),
  729: 				ThreadParentID = base16:encode(crypto:strong_rand_bytes(5)),
  730: 				M1 = rest_helper:make_msg_stanza_with_thread_and_parent(BobJID, MsgID, ThreadID, ThreadParentID),
  731: 				escalus:send(Alice, M1),
  732: 				escalus:wait_for_stanza(Bob),
  733: 				mam_helper:wait_for_archive_size(Bob, 1),
  734: 				mam_helper:wait_for_archive_size(Alice, 1),
  735: 				AliceCreds = {AliceJID, user_password(alice)},
  736: 				% recent msgs with a limit
  737: 				M2 = get_messages_with_props(AliceCreds, BobJID, 1),
  738: 				[{MsgWithProps} | _] = M2,
  739: 				Data = maps:from_list(MsgWithProps),
  740: 				#{<<"thread">> := ReceivedThreadID,
  741: 				  <<"parent">> := ReceivedThreadParentID,
  742: 				  <<"id">> := ReceivedMsgID} = Data,
  743: 				%we are expecting thread and parent thread for this test message
  744: 				%test message defined in rest_helper:make_msg_stanza_with_thread
  745: 				ReceivedThreadID = ThreadID,
  746: 				ReceivedThreadParentID = ThreadParentID,
  747: 				ReceivedMsgID = MsgID
  748: 		end).
  749: 
  750: msg_without_thread_is_sent_and_delivered_over_xmpp(Config) ->
  751:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  752: 				BobJID = user_jid(Bob),
  753: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  754: 				M1 = rest_helper:make_msg_stanza_without_thread(BobJID, MsgID),
  755: 				escalus:send(Alice, M1),
  756: 				M2 = escalus:wait_for_stanza(Bob),
  757: 				escalus:assert(is_message, M2)
  758: 		end).
  759: 
  760: msg_without_thread_can_be_parsed(Config) ->
  761:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun (Alice, Bob) ->
  762: 				AliceJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Alice)),
  763: 				AliceCreds = {AliceJID, user_password(alice)},
  764: 				BobJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Bob)),
  765: 				MsgID = base16:encode(crypto:strong_rand_bytes(5)),
  766: 				M1 = rest_helper:make_msg_stanza_without_thread(BobJID, MsgID),
  767: 				escalus:send(Alice, M1),
  768: 				escalus:wait_for_stanza(Bob),
  769: 				mam_helper:wait_for_archive_size(Bob, 1),
  770: 				mam_helper:wait_for_archive_size(Alice, 1),
  771: 				% recent msgs with a limit
  772: 				M2 = get_messages_with_props(AliceCreds, BobJID, 1),
  773: 				[_Msg] = rest_helper:decode_maplist(M2),
  774: 				MsgID = maps:get(id, _Msg)
  775: 		end).
  776: 
  777: assert_room_messages(RecvMsg, {_ID, _GenFrom, GenMsg}) ->
  778:     escalus:assert(is_chat_message, [maps:get(body, RecvMsg)], GenMsg),
  779:     ok.
  780: 
  781: get_room_info(User, RoomID) ->
  782:     Creds = credentials(User),
  783:     {{<<"200">>, <<"OK">>}, {Result}} = rest_helper:gett(client, <<"/rooms/", RoomID/binary>>,
  784:                                                          Creds),
  785:     Result.
  786: 
  787: given_new_room_with_users_and_msgs(Owner, Users) ->
  788:     RoomID = given_new_room_with_users(Owner, Users),
  789:     Msgs = [given_message_sent_to_room(RoomID, Sender) || Sender <- [Owner | Users]],
  790:     wait_for_room_msgs(Msgs, [Owner | Users]),
  791:     {RoomID, Msgs}.
  792: 
  793: wait_for_room_msgs([], _) ->
  794:     ok;
  795: wait_for_room_msgs([Msg | Rest], Users) ->
  796:     [wait_for_room_msg(Msg, User) || {_, User} <- Users],
  797:     wait_for_room_msgs(Rest, Users).
  798: 
  799: wait_for_room_msg(Msg, User) ->
  800:     Stanza = escalus:wait_for_stanza(User),
  801:     escalus:assert(is_groupchat_message, [maps:get(body, Msg)], Stanza).
  802: 
  803: given_message_sent_to_room(RoomID, Sender) ->
  804:     Body = #{body => <<"Hi all!">>},
  805:     HTTPResult = given_message_sent_to_room(RoomID, Sender, Body),
  806:     {{<<"200">>, <<"OK">>}, {Result}} = HTTPResult,
  807:     MsgId = proplists:get_value(<<"id">>, Result),
  808:     true = is_binary(MsgId),
  809:     {UserJID, _} = credentials(Sender),
  810: 
  811:     Body#{id => MsgId, from => UserJID}.
  812: 
  813: given_message_sent_to_room(RoomID, Sender, Body) ->
  814:     Creds = credentials(Sender),
  815:     Path = <<"/rooms/", RoomID/binary, "/messages">>,
  816:     rest_helper:post(client, Path, Body, Creds).
  817: 
  818: given_new_room_with_users(Owner, Users) ->
  819:     RoomID = given_new_room(Owner),
  820:     [given_user_invited(Owner, RoomID, User) || {_, User} <- Users],
  821:     RoomID.
  822: 
  823: given_new_room(Owner) ->
  824:     Creds = credentials(Owner),
  825:     RoomName = <<"new_room_name">>,
  826:     create_room(Creds, RoomName, <<"This room subject">>).
  827: 
  828: given_new_room(Owner, RoomID) ->
  829:     Creds = credentials(Owner),
  830:     RoomName = <<"new_room_name">>,
  831:     create_room_with_id(Creds, RoomName, <<"This room subject">>, RoomID).
  832: 
  833: given_new_room(Owner, RoomID, RoomName) ->
  834:     Creds = credentials(Owner),
  835:     create_room_with_id(Creds, RoomName, <<"This room subject">>, RoomID).
  836: 
  837: given_user_invited({_, Inviter} = Owner, RoomID, Invitee) ->
  838:     JID = user_jid(Invitee),
  839:     {{<<"204">>, <<"No Content">>}, _} = invite_to_room(Owner, RoomID, JID),
  840:     maybe_wait_for_aff_stanza(Invitee, Invitee),
  841:     maybe_wait_for_aff_stanza(Inviter, Invitee).
  842: 
  843: when_config_change(User, RoomID, NewName, NewSubject) ->
  844:     Creds = credentials(User),
  845:     Config = #{name => NewName, subject => NewSubject},
  846:     Path = <<"/rooms/", RoomID/binary, "/config">>,
  847:     putt(client, Path, Config, Creds).
  848: 
  849: maybe_wait_for_aff_stanza(#client{} = Client, Invitee) ->
  850:     Stanza = escalus:wait_for_stanza(Client),
  851:     assert_aff_change_stanza(Stanza, Invitee, <<"member">>);
  852: maybe_wait_for_aff_stanza(_, _) ->
  853:     ok.
  854: 
  855: invite_to_room(Inviter, RoomID, Invitee) ->
  856:     Body = #{user => Invitee},
  857:     Creds = credentials(Inviter),
  858:     rest_helper:post(client, <<"/rooms/", RoomID/binary, "/users">>, Body, Creds).
  859: 
  860: remove_user_from_a_room(Inviter, RoomID, Invitee) ->
  861:     JID = escalus_utils:jid_to_lower(escalus_client:short_jid(Invitee)),
  862:     Creds = credentials(Inviter),
  863:     Path = <<"/rooms/", RoomID/binary, "/users/", JID/binary>>,
  864:     rest_helper:delete(client, Path, Creds).
  865: 
  866: credentials({User, ClientOrSpec}) ->
  867:     {user_jid(ClientOrSpec), user_password(User)}.
  868: 
  869: user_jid(#client{} = UserClient) ->
  870:     escalus_utils:jid_to_lower(escalus_client:short_jid(UserClient));
  871: user_jid(Spec) ->
  872:     U = proplists:get_value(username, Spec),
  873:     S = proplists:get_value(server, Spec),
  874:     escalus_utils:jid_to_lower(<<U/binary, $@, S/binary>>).
  875: 
  876: user_password(User) ->
  877:     [{User, Props}] = escalus:get_users([User]),
  878:     proplists:get_value(password, Props).
  879: 
  880: send_message(User, From, To) ->
  881:     AliceJID = user_jid(From),
  882:     BobJID = user_jid(To),
  883:     M = #{to => BobJID, body => <<"hello, ", BobJID/binary, " it's me">>},
  884:     Cred = credentials({User, From}),
  885:     {{<<"200">>, <<"OK">>}, {Result}} = post(client, <<"/messages">>, M, Cred),
  886:     ID = proplists:get_value(<<"id">>, Result),
  887:     M#{id => ID, from => AliceJID}.
  888: 
  889: get_messages(MeCreds, Other, Count) ->
  890:     GetPath = lists:flatten(["/messages/",
  891:                              binary_to_list(Other),
  892:                              "?limit=", integer_to_list(Count)]),
  893:     get_messages(GetPath, MeCreds).
  894: 
  895: get_messages(Path, Creds) ->
  896:     {{<<"200">>, <<"OK">>}, Msgs} = rest_helper:gett(client, Path, Creds),
  897:     rest_helper:decode_maplist(Msgs).
  898: 
  899: get_messages(MeCreds, Other, Before, Count) ->
  900:     GetPath = lists:flatten(["/messages/",
  901:                              binary_to_list(Other),
  902:                              "?before=", integer_to_list(Before),
  903:                              "&limit=", integer_to_list(Count)]),
  904:     get_messages(GetPath, MeCreds).
  905: 
  906: get_messages_with_props(MeCreds, Other, Count) ->
  907:     GetPath = lists:flatten(["/messages/",
  908:                              binary_to_list(Other),
  909:                              "?limit=", integer_to_list(Count)]),
  910:     get_messages_with_props(GetPath, MeCreds).
  911: 
  912: get_messages_with_props(Path, Creds) ->
  913:     {{<<"200">>, <<"OK">>}, Msgs} = rest_helper:gett(client, Path, Creds),
  914:     Msgs.
  915: 
  916: get_messages_with_props(MeCreds, Other, Before, Count) ->
  917:     GetPath = lists:flatten(["/messages/",
  918:                              binary_to_list(Other),
  919:                              "?before=", integer_to_list(Before),
  920:                              "&limit=", integer_to_list(Count)]),
  921:     get_messages_with_props(GetPath, MeCreds).
  922: 
  923: get_room_messages(Client, RoomID, Count) ->
  924:     get_room_messages(Client, RoomID, Count, undefined).
  925: 
  926: get_room_messages(Client, RoomID, Count, Before) ->
  927:     Creds = credentials(Client),
  928:     BasePathList = ["/rooms/", RoomID, "/messages?limit=", integer_to_binary(Count)],
  929:     PathList = BasePathList ++ [["&before=", integer_to_binary(Before)] || Before /= undefined],
  930:     Path = erlang:iolist_to_binary(PathList),
  931:     get_messages(Path, Creds).
  932: 
  933: create_room({_AliceJID, _} = Creds, RoomName, Subject) ->
  934:     Room = #{name => RoomName,
  935:              subject => Subject},
  936:     {{<<"200">>, <<"OK">>}, {Result}} = rest_helper:post(client, <<"/rooms">>, Room, Creds),
  937:     proplists:get_value(<<"id">>, Result).
  938: 
  939: create_room_with_id({_AliceJID, _} = Creds, RoomName, Subject, RoomID) ->
  940:     Res = create_room_with_id_request(Creds, RoomName, Subject, RoomID),
  941:     case Res of
  942:         {{<<"201">>, <<"Created">>}, {Result}} ->
  943:             proplists:get_value(<<"id">>, Result);
  944:         _ ->
  945:             ct:fail(#{issue => create_room_with_id_failed,
  946:                       result => Res,
  947:                       creds => Creds,
  948:                       room_name => RoomName,
  949:                       subject => Subject,
  950:                       room_id => RoomID})
  951:     end.
  952: 
  953: create_room_with_id_request(Creds, RoomName, Subject, RoomID) ->
  954:     Room = #{name => RoomName,
  955:              subject => Subject},
  956:     Path = <<"/rooms/", RoomID/binary>>,
  957:     putt(client, Path, Room, Creds).
  958: 
  959: get_my_rooms(User) ->
  960:     Creds = credentials(User),
  961:     {{<<"200">>, <<"OK">>}, Rooms} = rest_helper:gett(client, <<"/rooms">>, Creds),
  962:     Rooms.
  963: 
  964: assert_messages([], []) ->
  965:     ok;
  966: assert_messages([SentMsg | SentRest], [RecvMsg | RecvRest]) ->
  967:     FromJID = maps:get(from, SentMsg),
  968:     FromJID = maps:get(from, RecvMsg),
  969:     MsgId = maps:get(id, SentMsg),
  970:     MsgId = maps:get(id, RecvMsg), %checks if there is an ID
  971:     _ = maps:get(timestamp, RecvMsg), %checks if there ia timestamp
  972:     MsgBody = maps:get(body, SentMsg),
  973:     MsgBody = maps:get(body, RecvMsg),
  974:     assert_messages(SentRest, RecvRest);
  975: assert_messages(_Sent, _Recv) ->
  976:     ct:fail("Send and Recv messages are not equal").
  977: 
  978: send_messages(Config, Alice, Bob, Kate) ->
  979:     M1 = send_message(bob, Bob, Alice),
  980:     M2 = send_message(alice, Alice, Bob),
  981:     M3 = send_message(kate, Kate, Alice),
  982:     mam_helper:maybe_wait_for_archive(Config),
  983:     [M1, M2, M3].
  984: 
  985: assert_aff_change_stanza(Stanza, Target, Change) ->
  986:     TargetJID = escalus_utils:jid_to_lower(escalus_client:short_jid(Target)),
  987:     ID = exml_query:attr(Stanza, <<"id">>),
  988:     true = is_binary(ID) andalso ID /= <<>>,
  989:     Users = exml_query:paths(Stanza, [{element, <<"x">>}, {element, <<"user">>}]),
  990:     [User] = [User || User <- Users, TargetJID == exml_query:cdata(User)],
  991:     Change = exml_query:attr(User, <<"affiliation">>),
  992:     TargetJID = exml_query:cdata(User).
  993: 
  994: assert_room_info(Owner, RoomInfo) ->
  995:     true = is_property_present(<<"subject">>, RoomInfo),
  996:     true = is_property_present(<<"name">>, RoomInfo),
  997:     true = is_property_present(<<"participants">>, RoomInfo),
  998:     true = is_participant(Owner, <<"owner">>, RoomInfo).
  999: 
 1000: is_property_present(Name, Proplist) ->
 1001:     Val = proplists:get_value(Name, Proplist),
 1002:     Val /= undefined.
 1003: 
 1004: assert_property_value(Name, Value, Proplist) ->
 1005:     Val = proplists:get_value(Name, Proplist),
 1006:     ?assertEqual(Value, Val).
 1007: 
 1008: is_participant(User, Role, RoomInfo) ->
 1009:     Participants = proplists:get_value(<<"participants">>, RoomInfo),
 1010:     JID = user_jid(User),
 1011:     Fun = fun({Props}) ->
 1012:                   UserJID = proplists:get_value(<<"user">>, Props),
 1013:                   UserRole = proplists:get_value(<<"role">>, Props),
 1014:                   UserJID == JID andalso UserRole == Role
 1015:           end,
 1016:     lists:any(Fun, Participants).
 1017: 
 1018: connect_to_sse(User) ->
 1019:     Port = ct:get_config({hosts, mim, http_api_client_endpoint_port}),
 1020:     {Username, Password} = credentials(User),
 1021:     Base64 = base64:encode(binary_to_list(Username) ++ [$: | binary_to_list(Password)]),
 1022:     Headers = [{<<"authorization">>, <<"basic ", Base64/binary>>},
 1023:                {<<"host">>, <<"localhost">>},
 1024:                {<<"accept">>, <<"text/event-stream">>}],
 1025:     {ok, ConnPid} = gun:open("localhost", Port, #{
 1026:         transport => tls,
 1027:         protocols => [http],
 1028:         http_opts => #{content_handlers => [gun_sse_h, gun_data_h]}
 1029:     }),
 1030:     {ok, _} = gun:await_up(ConnPid),
 1031:     StreamRef = gun:get(ConnPid, "/api/sse", Headers),
 1032:     #{pid => ConnPid, stream_ref => StreamRef}.
 1033: 
 1034: wait_for_event(#{pid := Pid, stream_ref := StreamRef} = Opts) ->
 1035:     case gun:await(Pid, StreamRef) of
 1036:         {response, nofin, _Status, _} ->
 1037:             wait_for_event(Opts);
 1038:         {sse, #{data := [Response]}} ->
 1039:           Opts#{data => Response};
 1040:         Error ->
 1041:             Error
 1042:     end.
 1043: 
 1044: stop_sse(#{pid := Pid}) ->
 1045:     gun:close(Pid).
 1046: 
 1047: assert_json_message(Sent, Received) ->
 1048:     #{<<"body">> := Body,
 1049:       <<"to">> := To,
 1050:       <<"from">> := From,
 1051:       <<"id">> := Id} = Received,
 1052: 
 1053:     Body = maps:get(body, Sent),
 1054:     To = maps:get(to, Sent),
 1055:     From = maps:get(from, Sent),
 1056:     Id = maps:get(id, Sent).
 1057: 
 1058: assert_json_room_sse_message(Expected, Received) ->
 1059:     #{<<"from">> := From,
 1060:       <<"room">> := Room,
 1061:       <<"id">> := _Id,
 1062:       <<"type">> := Type} = Received,
 1063: 
 1064:     Room = maps:get(room, Expected),
 1065:     Type = maps:get(type, Expected),
 1066:     From = maps:get(from, Expected),
 1067:     case Type of
 1068:         <<"message">> ->
 1069:             Body = maps:get(<<"body">>, Received),
 1070:             Body = maps:get(body, Expected);
 1071:         _ ->
 1072:             User = maps:get(<<"user">>, Received),
 1073:             User = maps:get(user, Expected)
 1074:     end.
 1075: 
 1076: 
 1077: add_contact_and_invite(Config) ->
 1078:     escalus:fresh_story(
 1079:         Config, [{alice, 1}, {bob, 1}],
 1080:         fun(Alice, Bob) ->
 1081:             AliceJID = escalus_utils:jid_to_lower(
 1082:                             escalus_client:short_jid(Alice)),
 1083:             BCred = credentials({bob, Bob}),
 1084:             % bob has empty roster
 1085:             {?OK, R} = gett(client, "/contacts", BCred),
 1086:             Res = decode_maplist(R),
 1087:             [] = Res,
 1088:             % adds Alice
 1089:             add_contact_check_roster_push(Alice, {bob, Bob}),
 1090:             % and she is in his roster, with empty status
 1091:             {?OK, R2} = gett(client, "/contacts", BCred),
 1092:             Result = decode_maplist(R2),
 1093:             [Res2] = Result,
 1094:             #{jid := AliceJID, subscription := <<"none">>,
 1095:               ask := <<"none">>} = Res2,
 1096:             % he invites her
 1097:             PutPath = lists:flatten(["/contacts/", binary_to_list(AliceJID)]),
 1098:             {?NOCONTENT, _} = putt(client, PutPath,
 1099:                                    #{action => <<"invite">>},
 1100:                                    BCred),
 1101:             % another roster push
 1102:             Push2 = escalus:wait_for_stanza(Bob),
 1103:             escalus:assert(is_roster_set, Push2),
 1104:             ct:log("Push2: ~p", [Push2]),
 1105:             % she receives  a subscription request
 1106:             Sub = escalus:wait_for_stanza(Alice),
 1107:             escalus:assert(is_presence_with_type, [<<"subscribe">>], Sub),
 1108:             % in his roster she has a changed 'ask' status
 1109:             {?OK, R3} = gett(client, "/contacts", BCred),
 1110:             Result3 = decode_maplist(R3),
 1111:             [Res3] = Result3,
 1112:             #{jid := AliceJID, subscription := <<"none">>,
 1113:               ask := <<"out">>} = Res3,
 1114:             % adds him to her contacts
 1115:             escalus:send(Alice, escalus_stanza:roster_add_contact(Bob,
 1116:                          [], <<"Bob">>)),
 1117:             PushReqB = escalus:wait_for_stanza(Alice),
 1118:             escalus:assert(is_roster_set, PushReqB),
 1119:             escalus:send(Alice, escalus_stanza:iq_result(PushReqB)),
 1120:             escalus:assert(is_iq_result, escalus:wait_for_stanza(Alice)),
 1121:             %% Alice sends subscribed presence
 1122:             escalus:send(Alice,
 1123:                          escalus_stanza:presence_direct(
 1124:                              escalus_client:short_jid(Bob),
 1125:                              <<"subscribed">>)),
 1126:             %% Wait for push before trying to query endpoint
 1127:             %% If we just call endpoint,
 1128:             %% the "subscribed" stanza can not yet be processed.
 1129:             Push3 = escalus:wait_for_stanza(Bob),
 1130:             ct:log("Push3 ~p", [Push3]),
 1131:             escalus:assert(is_roster_set, Push3),
 1132: 
 1133:             % now check Bob's roster
 1134:             {?OK, R4} = gett(client, "/contacts", BCred),
 1135:             Result4 = decode_maplist(R4),
 1136:             [Res4] = Result4,
 1137:             #{jid := AliceJID, subscription := <<"to">>,
 1138:                 ask := <<"none">>} = Res4,
 1139:             ok
 1140:         end
 1141:     ),
 1142:     ok.
 1143: 
 1144: add_contact_and_be_invited(Config) ->
 1145:     escalus:fresh_story(
 1146:         Config, [{alice, 1}, {bob, 1}],
 1147:         fun(Alice, Bob) ->
 1148:             AliceJID = escalus_utils:jid_to_lower(
 1149:                 escalus_client:short_jid(Alice)),
 1150:             BCred = credentials({bob, Bob}),
 1151:             % bob has empty roster
 1152:             {?OK, R} = gett(client, "/contacts", BCred),
 1153:             Res = decode_maplist(R),
 1154:             [] = Res,
 1155:             % adds Alice
 1156:             add_contact_check_roster_push(Alice, {bob, Bob}),
 1157:             % and she is in his roster, with empty status
 1158:             {?OK, R2} = gett(client, "/contacts", BCred),
 1159:             Result = decode_maplist(R2),
 1160:             [Res2] = Result,
 1161:             #{jid := AliceJID, subscription := <<"none">>,
 1162:               ask := <<"none">>} = Res2,
 1163:             %% she adds him and invites
 1164:             escalus:send(Alice, escalus_stanza:roster_add_contact(Bob,
 1165:                          [],
 1166:                          <<"Bobek">>)),
 1167:             escalus:assert_many([is_roster_set, is_iq_result],
 1168:                                 escalus:wait_for_stanzas(Alice, 2)),
 1169:             escalus:send(Alice,
 1170:                          escalus_stanza:presence_direct(
 1171:                              escalus_client:short_jid(Bob),
 1172:                              <<"subscribe">>)),
 1173:             escalus:assert(is_roster_set, escalus:wait_for_stanza(Alice)),
 1174:             escalus:assert(is_presence_with_type, [<<"subscribe">>],
 1175:                            escalus:wait_for_stanza(Bob)),
 1176:             % now check Bob's roster, and it is the same...
 1177:             {?OK, R4} = gett(client, "/contacts", BCred),
 1178:             [Res4] = decode_maplist(R4),
 1179:             #{jid := AliceJID, subscription := <<"none">>,
 1180:                 ask := <<"in">>} = Res4,
 1181:             % because although it is stated in RFC3921, 8.2.6 that {none, in}
 1182:             % should be hidden from user, we changed it in REST API
 1183:             % he accepts
 1184:             PutPath = lists:flatten(["/contacts/", binary_to_list(AliceJID)]),
 1185:             {?NOCONTENT, _} = putt(client, PutPath,
 1186:                                    #{action => <<"accept">>},
 1187:                                    BCred),
 1188:             escalus:assert(is_roster_set, escalus:wait_for_stanza(Bob)),
 1189:             IsSub = fun(S) ->
 1190:                         escalus_pred:is_presence_with_type(<<"subscribed">>, S)
 1191:                     end,
 1192:             escalus:assert_many([is_roster_set, IsSub,
 1193:                                  is_presence],
 1194:                                 escalus:wait_for_stanzas(Alice, 3)),
 1195:             ok
 1196:         end
 1197:     ),
 1198:     ok.
 1199: 
 1200: is_subscription_remove(User) ->
 1201:     IsSubscriptionRemove = fun(El) ->
 1202:                 Sub = exml_query:paths(El, [{element, <<"query">>},
 1203:                                             {element, <<"item">>},
 1204:                                             {attr, <<"subscription">>}]),
 1205:                 Sub == [<<"remove">>]
 1206:                 end,
 1207:     escalus:assert(IsSubscriptionRemove, escalus:wait_for_stanza(User)).
 1208: 
 1209: 
 1210: 
 1211: add_and_remove(Config) ->
 1212:     escalus:fresh_story(
 1213:         Config, [{alice, 1}, {bob, 1}],
 1214:         fun(Alice, Bob) ->
 1215:             AliceJID = escalus_utils:jid_to_lower(
 1216:                 escalus_client:short_jid(Alice)),
 1217:             BCred = credentials({bob, Bob}),
 1218:             % adds Alice
 1219:             add_contact_check_roster_push(Alice, {bob, Bob}),
 1220:             % Check if Contact is in Bob's roster
 1221:             {?OK, R2} = gett(client, "/contacts", BCred),
 1222:             Result = decode_maplist(R2),
 1223:             [Res2] = Result,
 1224:             #{jid := AliceJID, subscription := <<"none">>,
 1225:               ask := <<"none">>} = Res2,
 1226:             % delete user
 1227:             DelPath = lists:flatten(["/contacts/", binary_to_list(AliceJID)]),
 1228:             {?NOCONTENT, _} = delete(client, DelPath, BCred),
 1229:             % Bob's roster is empty again
 1230:             {?OK, R3} = gett(client, "/contacts", BCred),
 1231:             [] = decode_maplist(R3),
 1232:             is_subscription_remove(Bob),
 1233:             ok
 1234:         end
 1235:     ),
 1236:     ok.
 1237: 
 1238: 
 1239: add_and_remove_some_contacts_properly(Config) ->
 1240:     escalus:fresh_story(
 1241:         Config, [{alice, 1}, {bob, 1}, {kate, 1}, {mike, 1}],
 1242:         fun(Alice, Bob, Kate, Mike) ->
 1243:             BCred = credentials({bob, Bob}),
 1244:             % adds all the other users
 1245:             lists:foreach(fun(AddContact) ->
 1246:                                   add_contact_check_roster_push(AddContact, {bob, Bob}) end,
 1247:                          [Alice, Kate, Mike]),
 1248:             AliceJID = escalus_utils:jid_to_lower(
 1249:                 escalus_client:short_jid(Alice)),
 1250:             KateJID = escalus_utils:jid_to_lower(
 1251:                 escalus_client:short_jid(Kate)),
 1252:             MikeJID = escalus_utils:jid_to_lower(
 1253:                 escalus_client:short_jid(Mike)),
 1254:             _AliceContact = create_contact(AliceJID),
 1255:             _KateContact = create_contact(KateJID),
 1256:             MikeContact = create_contact(MikeJID),
 1257:             % delete Alice and Kate
 1258:             Body = jiffy:encode(#{<<"to_delete">> => [AliceJID, KateJID]}),
 1259:             {?OK, {[{<<"not_deleted">>,[]}]}} = delete(client, "/contacts", BCred, Body),
 1260:             % Bob's roster consists now of only Mike
 1261:             {?OK, R4} = gett(client, "/contacts", BCred),
 1262:             [MikeContact] = decode_maplist(R4),
 1263:             is_subscription_remove(Bob),
 1264:             ok
 1265:         end
 1266:     ),
 1267:     ok.
 1268: 
 1269: 
 1270: add_and_remove_some_contacts_with_nonexisting(Config) ->
 1271:     escalus:fresh_story(
 1272:         Config, [{alice, 1}, {bob, 1}, {kate, 1}, {mike, 1}],
 1273:         fun(Alice, Bob, Kate, Mike) ->
 1274:             BCred = credentials({bob, Bob}),
 1275:             % adds all the other users
 1276:             lists:foreach(fun(AddContact) ->
 1277:                                   add_contact_check_roster_push(AddContact, {bob, Bob}) end,
 1278:                          [Alice, Kate]),
 1279:             AliceJID = escalus_utils:jid_to_lower(
 1280:                 escalus_client:short_jid(Alice)),
 1281:             KateJID = escalus_utils:jid_to_lower(
 1282:                 escalus_client:short_jid(Kate)),
 1283:             MikeJID = escalus_utils:jid_to_lower(
 1284:                 escalus_client:short_jid(Mike)),
 1285:             _AliceContact = create_contact(AliceJID),
 1286:             _KateContact = create_contact(KateJID),
 1287:             _MikeContact = create_contact(MikeJID),
 1288:             % delete Alice, Kate and Mike (who is absent)
 1289:             Body = jiffy:encode(#{<<"to_delete">> => [AliceJID, KateJID, MikeJID]}),
 1290:             {?OK, {[{<<"not_deleted">>,[MikeJID]}]}} = delete(client, "/contacts", BCred, Body),
 1291:             % Bob's roster is empty now
 1292:             {?OK, R4} = gett(client, "/contacts", BCred),
 1293:             [] = decode_maplist(R4),
 1294:             is_subscription_remove(Bob),
 1295:             ok
 1296:         end
 1297:     ),
 1298:     ok.
 1299: 
 1300: create_contact(JID) ->
 1301:     #{jid => JID, subscription => <<"none">>,
 1302:                              ask => <<"none">>}.
 1303: 
 1304: add_contact_check_roster_push(Contact, {_, RosterOwnerSpec} = RosterOwner) ->
 1305:     ContactJID = escalus_utils:jid_to_lower(
 1306:                 escalus_client:short_jid(Contact)),
 1307:     RosterOwnerCreds = credentials(RosterOwner),
 1308:     {?NOCONTENT, _} = post(client, <<"/contacts">>, #{jid => ContactJID},
 1309:                             RosterOwnerCreds),
 1310:     Push = escalus:wait_for_stanza(RosterOwnerSpec),
 1311:     escalus:assert(is_roster_set, Push),
 1312:     ok.
 1313: 
 1314: 
 1315: break_stuff(Config) ->
 1316:     escalus:fresh_story(
 1317:         Config, [{alice, 1}, {bob, 1}],
 1318:         fun(Alice, Bob) ->
 1319:             AliceJID = escalus_utils:jid_to_lower(
 1320:                 escalus_client:short_jid(Alice)),
 1321:             BCred = credentials({bob, Bob}),
 1322:             AddContact = #{jid => AliceJID},
 1323:             {?NOCONTENT, _} = post(client, <<"/contacts">>, AddContact,
 1324:                 BCred),
 1325:             PutPath = lists:flatten(["/contacts/", binary_to_list(AliceJID)]),
 1326:             {?NOT_IMPLEMENTED, _} = putt(client, PutPath,
 1327:                                          #{action => <<"nosuchaction">>},
 1328:                                          BCred),
 1329:             BadPutPath = "/contacts/zorro@localhost",
 1330:             {?NOT_FOUND, _} = putt(client, BadPutPath,
 1331:                                    #{action => <<"invite">>},
 1332:                                    BCred),
 1333:             BadGetPath = "/contacts/zorro@localhost",
 1334:             {?NOT_FOUND, _} = gett(client, BadGetPath, BCred),
 1335:             ok
 1336:         end
 1337:     ),
 1338:     ok.
 1339: 
 1340: -spec room_jid(RoomID :: binary(), Config :: list()) -> RoomJID :: binary().
 1341: room_jid(RoomID, Config) ->
 1342:     MUCLightHost = config_to_muc_host(Config),
 1343:     <<RoomID/binary, "@", MUCLightHost/binary>>.
 1344: 
 1345: default_http_server_name_is_returned_if_not_changed(_Config) ->
 1346:     %% GIVEN MIM1 uses default name
 1347:     verify_server_name_in_header(distributed_helper:mim(), <<"Cowboy">>).
 1348: 
 1349: non_default_http_server_name_is_returned_if_configured(_Config) ->
 1350:     %% GIVEN MIM2 uses name "Classified"
 1351:     verify_server_name_in_header(distributed_helper:mim2(), <<"Classified">>).
 1352: 
 1353: verify_server_name_in_header(Server, ExpectedName) ->
 1354:     % WHEN unathenticated user makes a request to nonexistent path
 1355:     ReqParams = #{
 1356:       role => client,
 1357:       method => <<"GET">>,
 1358:       path => "/contacts/zorro@localhost",
 1359:       body => <<>>,
 1360:       return_headers => true,
 1361:       server => Server
 1362:      },
 1363:     {?UNAUTHORIZED, Headers2, _} = rest_helper:make_request(ReqParams),
 1364:     % THEN expected server name is returned
 1365:     ExpectedName = proplists:get_value(<<"server">>, Headers2).
 1366: 
 1367: config_to_muc_host(Config) ->
 1368:     ?config(muc_light_host, Config).