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