1: -module(inbox_SUITE). 2: -compile([export_all, nowarn_export_all]). 3: 4: -include_lib("common_test/include/ct.hrl"). 5: -include_lib("eunit/include/eunit.hrl"). 6: -include_lib("escalus/include/escalus_xmlns.hrl"). 7: -include_lib("exml/include/exml.hrl"). 8: -include_lib("jid/include/jid.hrl"). 9: -include_lib("inbox.hrl"). 10: 11: %% tests 12: -import(muc_light_helper, [room_bin_jid/1]). 13: -import(inbox_helper, [ 14: inbox_modules/0, 15: muclight_modules/0, 16: inbox_opts/0, 17: muc_domain/0, 18: parse_form_iq/1, 19: check_inbox/2, check_inbox/3, 20: check_inbox/4, 21: clear_inbox_all/0, 22: given_conversations_between/2, 23: assert_invalid_inbox_form_value_error/3, 24: assert_invalid_reset_inbox/4, 25: extract_user_specs/1 26: ]). 27: 28: -define(ROOM3, <<"testroom3">>). 29: -define(ROOM4, <<"testroom4">>). 30: 31: %%-------------------------------------------------------------------- 32: %% Suite configuration 33: %%-------------------------------------------------------------------- 34: 35: all() -> 36: inbox_helper:skip_or_run_inbox_tests(tests()). 37: 38: tests() -> 39: [ 40: {group, regular}, 41: {group, async_pools} 42: ]. 43: 44: groups() -> 45: Gs = [ 46: {generic, [], 47: [ 48: disco_service, 49: returns_valid_form, 50: returns_error_when_first_bad_form_field_encountered, 51: returns_error_when_bad_form_field_start_sent, 52: returns_error_when_bad_form_field_end_sent, 53: returns_error_when_bad_form_field_order_sent, 54: returns_error_when_bad_form_field_hidden_read_sent, 55: returns_error_when_bad_reset_field_jid, 56: returns_error_when_no_reset_field_jid, 57: returns_error_when_unknown_field_sent 58: ]}, 59: {limit_result, [], 60: [ 61: inbox_result_cannot_exceed_configured_limit, 62: should_apply_lower_limit_when_both_provided 63: ]}, 64: {one_to_one, [], 65: [ 66: user_has_empty_inbox, 67: msg_sent_stored_in_inbox, 68: msg_sent_stored_in_inbox_iq_id_as_queryid_fallback, 69: msg_sent_stored_in_inbox_queryid, 70: msg_with_no_store_is_not_stored_in_inbox, 71: msg_with_store_hint_is_always_stored, 72: carbons_are_not_stored, 73: user_has_two_conversations, 74: msg_sent_to_offline_user, 75: msg_sent_to_not_existing_user, 76: user_has_two_unread_messages, 77: other_resources_do_not_interfere, 78: reset_unread_counter_with_reset_chat_marker, 79: reset_unread_counter_with_reset_stanza, 80: try_to_reset_unread_counter_with_bad_marker, 81: non_reset_marker_should_not_affect_inbox, 82: user_has_only_unread_messages_or_only_read, 83: reset_unread_counter_and_show_only_unread, 84: check_total_unread_count_and_active_conv_count, 85: check_total_unread_count_when_there_are_no_active_conversations, 86: total_unread_count_and_active_convs_are_zero_at_no_activity 87: ]}, 88: {muclight, [], 89: [ 90: simple_groupchat_stored_in_all_inbox, 91: advanced_groupchat_stored_in_all_inbox, 92: groupchat_markers_one_reset, 93: non_reset_marker_should_not_affect_muclight_inbox, 94: groupchat_reset_stanza_resets_inbox, 95: create_groupchat, 96: leave_and_remove_conversation, 97: groupchat_markers_one_reset_room_created, 98: groupchat_markers_all_reset_room_created, 99: inbox_does_not_trigger_does_user_exist 100: ]}, 101: {muclight_config, [sequence], 102: [ 103: create_groupchat_no_affiliation_stored, 104: leave_and_store_conversation, 105: no_aff_stored_and_remove_on_kicked, 106: no_stored_and_remain_after_kicked, 107: system_message_is_correctly_avoided 108: ]}, 109: {muc, [], 110: [ 111: simple_groupchat_stored_in_all_inbox_muc, 112: simple_groupchat_stored_in_offline_users_inbox_muc, 113: unread_count_is_the_same_after_going_online_again, 114: unread_count_is_reset_after_sending_chatmarker, 115: non_reset_marker_should_not_affect_muc_inbox, 116: unread_count_is_reset_after_sending_reset_stanza, 117: private_messages_are_handled_as_one2one 118: ]}, 119: {timestamps, [], 120: [ 121: timestamp_is_updated_on_new_message, 122: order_by_timestamp_ascending, 123: get_by_timestamp_range, 124: get_with_start_timestamp, 125: get_with_end_timestamp 126: ]}, 127: {bin, [], 128: [ 129: timeout_cleaner_flush_all, 130: rest_api_bin_flush_all, 131: rest_api_bin_flush_all_errors, 132: rest_api_bin_flush_user, 133: rest_api_bin_flush_user_errors, 134: xmpp_bin_flush, 135: bin_is_not_included_by_default 136: ]}, 137: {regular, [], test_groups()}, 138: {async_pools, [], [{group, bin} | test_groups()]} 139: ], 140: inbox_helper:maybe_run_in_parallel(Gs). 141: 142: test_groups() -> 143: [ 144: {group, generic}, 145: {group, limit_result}, 146: {group, one_to_one}, 147: {group, muclight}, 148: {group, muclight_config}, 149: {group, muc}, 150: {group, timestamps} 151: ]. 152: 153: suite() -> 154: escalus:suite(). 155: 156: %%-------------------------------------------------------------------- 157: %% Init & teardown 158: %%-------------------------------------------------------------------- 159: 160: init_per_suite(Config) -> 161: mongoose_helper:inject_module(?MODULE), 162: escalus:init_per_suite(Config). 163: 164: end_per_suite(Config) -> 165: escalus:end_per_suite(Config). 166: 167: init_per_group(GroupName, Config) when GroupName =:= regular; GroupName =:= async_pools -> 168: HostType = domain_helper:host_type(), 169: SecHostType = domain_helper:secondary_host_type(), 170: Config1 = dynamic_modules:save_modules(HostType, Config), 171: Config2 = dynamic_modules:save_modules(SecHostType, Config1), 172: InboxOptions = inbox_helper:inbox_opts(GroupName), 173: Backend = mongoose_helper:mnesia_or_rdbms_backend(), 174: ModOffline = config_parser_helper:mod_config(mod_offline, #{backend => Backend}), 175: ok = dynamic_modules:ensure_modules(HostType, 176: inbox_helper:inbox_modules(GroupName) 177: ++ inbox_helper:muclight_modules() 178: ++ [{mod_offline, ModOffline}]), 179: ok = dynamic_modules:ensure_modules(SecHostType, 180: [{mod_inbox, InboxOptions#{aff_changes := false}}]), 181: [{inbox_opts, InboxOptions} | Config2]; 182: 183: init_per_group(muclight, Config) -> 184: ok = dynamic_modules:ensure_modules(domain_helper:host_type(), muclight_modules()), 185: inbox_helper:reload_inbox_option(Config, groupchat, [muclight]); 186: init_per_group(muclight_config, Config) -> 187: ok = dynamic_modules:ensure_modules(domain_helper:host_type(), muclight_modules()), 188: Config1 = inbox_helper:reload_inbox_option(Config, groupchat, [muclight]), 189: escalus:create_users(Config1, escalus:get_users([alice, alice_bis, bob, kate, mike])); 190: init_per_group(muc, Config) -> 191: muc_helper:load_muc(), 192: inbox_helper:reload_inbox_option(Config, groupchat, [muc]); 193: init_per_group(limit_result, Config) -> 194: OptKey = [{modules, domain_helper:host_type()}, mod_inbox, max_result_limit], 195: mongoose_helper:backup_and_set_config_option(Config, OptKey, 2); 196: init_per_group(_GroupName, Config) -> 197: Config. 198: 199: end_per_group(GroupName, Config) when GroupName =:= regular; GroupName =:= async_pools -> 200: muc_light_helper:clear_db(domain_helper:host_type()), 201: escalus_fresh:clean(), 202: dynamic_modules:restore_modules(Config); 203: end_per_group(muclight_config, Config) -> 204: escalus:delete_users(Config, escalus:get_users([alice, alice_bis, bob, kate, mike])); 205: end_per_group(muc, Config) -> 206: inbox_helper:restore_inbox_option(Config), 207: muc_helper:unload_muc(); 208: end_per_group(limit_result, Config) -> 209: mongoose_helper:restore_config(Config), 210: Config; 211: end_per_group(_GroupName, Config) -> 212: Config. 213: 214: init_per_testcase(timeout_cleaner_flush_all, Config) -> 215: clear_inbox_all(), 216: inbox_helper:reload_inbox_option(Config, [{bin_ttl, 0}, {bin_clean_after, 10}]), 217: escalus:init_per_testcase(timeout_cleaner_flush_all, Config); 218: init_per_testcase(TS, Config) 219: when TS =:= create_groupchat_no_affiliation_stored; 220: TS =:= system_message_is_correctly_avoided -> 221: clear_inbox_all(), 222: inbox_helper:reload_inbox_option(Config, aff_changes, false), 223: escalus:init_per_testcase(TS, Config); 224: init_per_testcase(leave_and_store_conversation, Config) -> 225: clear_inbox_all(), 226: inbox_helper:reload_inbox_option(Config, remove_on_kicked, false), 227: escalus:init_per_testcase(leave_and_store_conversation, Config); 228: init_per_testcase(no_aff_stored_and_remove_on_kicked, Config) -> 229: clear_inbox_all(), 230: muc_light_helper:create_room(?ROOM3, muc_light_helper:muc_host(), alice, [bob, kate], 231: Config, muc_light_helper:ver(1)), 232: inbox_helper:reload_inbox_option(Config, [{remove_on_kicked, true}, {aff_changes, false}]), 233: escalus:init_per_testcase(no_aff_stored_and_remove_on_kicked, Config); 234: init_per_testcase(no_stored_and_remain_after_kicked, Config) -> 235: clear_inbox_all(), 236: muc_light_helper:create_room(?ROOM4, muc_light_helper:muc_host(), alice, [bob, kate], 237: Config, muc_light_helper:ver(1)), 238: inbox_helper:reload_inbox_option(Config, [{remove_on_kicked, false}, {aff_changes, true}]), 239: escalus:init_per_testcase(no_stored_and_remain_after_kicked, Config); 240: init_per_testcase(CaseName, Config) -> 241: escalus:init_per_testcase(CaseName, Config). 242: 243: end_per_testcase(timeout_cleaner_flush_all, Config) -> 244: inbox_helper:restore_inbox_option(Config), 245: escalus:end_per_testcase(timeout_cleaner_flush_all, Config); 246: end_per_testcase(TS, Config) 247: when TS =:= create_groupchat_no_affiliation_stored; 248: TS =:= system_message_is_correctly_avoided -> 249: clear_inbox_all(), 250: inbox_helper:restore_inbox_option(Config), 251: escalus:end_per_testcase(TS, Config); 252: end_per_testcase(leave_and_store_conversation, Config) -> 253: clear_inbox_all(), 254: inbox_helper:restore_inbox_option(Config), 255: escalus:end_per_testcase(leave_and_store_conversation, Config); 256: end_per_testcase(no_aff_stored_and_remove_on_kicked, Config) -> 257: clear_inbox_all(), 258: inbox_helper:restore_inbox_option(Config), 259: escalus:end_per_testcase(no_aff_stored_and_remove_on_kicked, Config); 260: end_per_testcase(no_stored_and_remain_after_kicked, Config) -> 261: clear_inbox_all(), 262: inbox_helper:restore_inbox_option(Config), 263: escalus:end_per_testcase(no_stored_and_remain_after_kicked, Config); 264: end_per_testcase(msg_sent_to_not_existing_user, Config) -> 265: HostType = domain_helper:host_type(), 266: escalus_ejabberd:rpc(mod_inbox_utils, clear_inbox, [HostType, <<"not_existing_user">>,<<"localhost">>]), 267: escalus:end_per_testcase(msg_sent_to_not_existing_user, Config); 268: end_per_testcase(CaseName, Config) -> 269: escalus:end_per_testcase(CaseName, Config). 270: 271: 272: %%-------------------------------------------------------------------- 273: %% Generic Inbox tests 274: %%-------------------------------------------------------------------- 275: 276: disco_service(Config) -> 277: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 278: Server = escalus_client:server(Alice), 279: escalus:send( 280: Alice, escalus_stanza:to(escalus_stanza:iq_get(?NS_DISCO_INFO, []), Server)), 281: Stanza = escalus:wait_for_stanza(Alice), 282: Features = exml_query:paths(Stanza, [{element, <<"query">>}, 283: {element, <<"feature">>}, 284: {attr, <<"var">>}]), 285: ?assertEqual(true, lists:member(inbox_helper:inbox_ns(), Features)) 286: end). 287: 288: returns_valid_form(Config) -> 289: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 290: escalus:send(Alice, inbox_helper:get_inbox_form_stanza()), 291: ResIQ = escalus:wait_for_stanza(Alice), 292: InboxNS = inbox_helper:inbox_ns(), 293: #{ field_count := 7 } = Form = parse_form_iq(ResIQ), 294: #{ <<"FORM_TYPE">> := #{ type := <<"hidden">>, 295: value := InboxNS } } = Form, 296: #{ <<"start">> := #{ type := <<"text-single">> } } = Form, 297: #{ <<"end">> := #{ type := <<"text-single">> } } = Form, 298: #{ <<"archive">> := #{ type := <<"boolean">>, 299: value := <<"false">> } } = Form, 300: #{ <<"box">> := #{ type := <<"list-single">>, 301: value := <<"all">>, 302: options := BoxOptions } } = Form, 303: #{ <<"order">> := #{ type := <<"list-single">>, 304: value := <<"desc">>, 305: options := OrderOptions } } = Form, 306: [<<"asc">>, <<"desc">>] = lists:sort(OrderOptions), 307: [<<"all">>, <<"archive">>, <<"bin">>, <<"inbox">>, <<"other">>] = lists:sort(BoxOptions), 308: #{ <<"hidden_read">> := #{ type := <<"text-single">> } } = Form 309: end). 310: 311: returns_error_when_bad_form_field_order_sent(Config) -> 312: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 313: assert_invalid_inbox_form_value_error(Alice, <<"order">>, <<"invalid">>) 314: end). 315: 316: returns_error_when_bad_form_field_start_sent(Config) -> 317: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 318: assert_invalid_inbox_form_value_error(Alice, <<"start">>, <<"invalid">>) 319: end). 320: 321: returns_error_when_bad_form_field_end_sent(Config) -> 322: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 323: assert_invalid_inbox_form_value_error(Alice, <<"end">>, <<"invalid">>) 324: end). 325: 326: returns_error_when_bad_form_field_hidden_read_sent(Config) -> 327: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 328: assert_invalid_inbox_form_value_error(Alice, <<"hidden_read">>, <<"invalid">>) 329: end). 330: 331: returns_error_when_bad_reset_field_jid(Config) -> 332: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 333: assert_invalid_reset_inbox( 334: Alice, <<"$@/">>, <<"jid">>, <<"invalid-jid">>) 335: end). 336: 337: returns_error_when_no_reset_field_jid(Config) -> 338: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 339: assert_invalid_reset_inbox( 340: Alice, undefined, <<"jid">>, <<"jid-required">>) 341: end). 342: 343: 344: returns_error_when_first_bad_form_field_encountered(Config) -> 345: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 346: Stanza = inbox_helper:make_inbox_stanza(#{<<"start">> => <<"invalid">>, 347: <<"end">> => <<"invalid">>}, false), 348: escalus:send(Alice, Stanza), 349: [ResIQ] = escalus:wait_for_stanzas(Alice, 1), 350: escalus_pred:is_iq_error(ResIQ), 351: ErrorMsg = inbox_helper:get_error_message(ResIQ), 352: inbox_helper:assert_message_content(ErrorMsg, <<"field=end">>, <<"value=invalid">>) 353: end). 354: 355: returns_error_when_unknown_field_sent(Config) -> 356: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 357: Stanza = inbox_helper:make_inbox_stanza(#{<<"unknown_field">> => <<"unknown_field_value">>}, false), 358: escalus:send(Alice, Stanza), 359: [ResIQ] = escalus:wait_for_stanzas(Alice, 1), 360: escalus_pred:is_iq_error(ResIQ), 361: ErrorMsg = inbox_helper:get_error_message(ResIQ), 362: inbox_helper:assert_message_content(ErrorMsg, <<"field=unknown_field">>, <<"value=unknown_field_value">>) 363: end). 364: 365: 366: %%-------------------------------------------------------------------- 367: %% Inbox tests one-to-one 368: %%-------------------------------------------------------------------- 369: 370: user_has_empty_inbox(Config) -> 371: escalus:fresh_story(Config, [{kate, 1}], fun(Kate) -> 372: Stanza = inbox_helper:make_inbox_stanza(), 373: %% Kate logs in for first time and ask for inbox 374: escalus:send(Kate, Stanza), 375: [ResIQ] = escalus:wait_for_stanzas(Kate, 1), 376: true = escalus_pred:is_iq_result(ResIQ), 377: %% Inbox is empty 378: TotalCount = inbox_helper:get_result_el(ResIQ, <<"count">>), 379: 0 = TotalCount 380: end). 381: 382: msg_sent_stored_in_inbox(Config) -> 383: test_msg_stored_in_inbox(Config, undefined). 384: 385: msg_sent_stored_in_inbox_iq_id_as_queryid_fallback(Config) -> 386: test_msg_stored_in_inbox(Config, iq_id). 387: 388: msg_sent_stored_in_inbox_queryid(Config) -> 389: test_msg_stored_in_inbox(Config, queryid). 390: 391: test_msg_stored_in_inbox(Config, QueryId) -> 392: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 393: #{ Alice := AliceConvs, Bob := BobConvs } = given_conversations_between(Alice, [Bob]), 394: %% Both check inbox 395: check_inbox(Alice, AliceConvs, inbox_helper:maybe_make_queryid(QueryId)), 396: check_inbox(Bob, BobConvs, inbox_helper:maybe_make_queryid(QueryId)) 397: end). 398: 399: msg_with_no_store_is_not_stored_in_inbox(Config) -> 400: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 401: %% Alice sends a message to Bob with a no-store hint 402: Body = <<"test">>, 403: Msg1 = escalus_stanza:chat_to(Bob, Body), 404: Msg2 = escalus_stanza:set_id(Msg1, escalus_stanza:id()), 405: Msg3 = mam_helper:add_nostore_hint(Msg2), 406: escalus:send(Alice, Msg3), 407: MsgSent = escalus:wait_for_stanza(Bob), 408: escalus:assert(is_chat_message, MsgSent), 409: %% Bob has no unread messages in conversation with Alice 410: check_inbox(Bob, []), 411: %% Alice has no conv in her inbox either 412: check_inbox(Alice, []) 413: end). 414: 415: msg_with_store_hint_is_always_stored(Config) -> 416: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 417: %% Alice sends a message to Bob with a store hint, that would otherwise be ignored 418: Msg1 = escalus_stanza:to(#xmlel{name = <<"message">>}, Bob), 419: Msg2 = escalus_stanza:set_id(Msg1, escalus_stanza:id()), 420: Msg3 = mam_helper:add_store_hint(Msg2), 421: escalus:send(Alice, Msg3), 422: escalus:wait_for_stanza(Bob), 423: %% Alice and Bob has a body-less message in their inbox 424: check_inbox(Bob, [#conv{unread = 1, from = Alice, to = Bob, content = <<>>}]), 425: check_inbox(Alice, [#conv{unread = 0, from = Alice, to = Bob, content = <<>>}]) 426: end). 427: 428: carbons_are_not_stored(Config) -> 429: escalus:fresh_story(Config, [{alice, 2}, {bob, 2}], fun(Alice1, Alice2, Bob1, Bob2) -> 430: mongoose_helper:enable_carbons([Alice1, Alice2, Bob1, Bob2]), 431: #{ Alice1 := AliceConvs, Bob1 := BobConvs } = given_conversations_between(Alice1, [Bob1]), 432: %% Both check inbox and carbons aren't there 433: check_inbox(Alice1, AliceConvs), 434: check_inbox(Bob1, BobConvs) 435: end). 436: 437: user_has_two_conversations(Config) -> 438: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 439: #{ Alice := AliceConvs, Bob := BobConvs, Kate := KateConvs } = 440: given_conversations_between(Alice, [Bob, Kate]), 441: 442: %% Alice has two conversations in her inbox (no unread messages) 443: check_inbox(Alice, AliceConvs), 444: 445: %% Kate has one conversation with one unread 446: check_inbox(Kate, KateConvs), 447: 448: %% Bob has one conversation with one unread 449: check_inbox(Bob, BobConvs) 450: end). 451: 452: user_has_only_unread_messages_or_only_read(Config) -> 453: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 454: given_conversations_between(Alice, [Bob, Kate]), 455: % Alice has no unread messages, but requests all conversations 456: inbox_helper:get_inbox(Alice, #{ hidden_read => false }, #{count => 2}), 457: 458: % Requests only conversations with unread messages 459: inbox_helper:get_inbox(Alice, #{ hidden_read => true }, #{count => 0}), 460: % Bob has only one, unread message 461: inbox_helper:get_inbox(Bob, #{ hidden_read => true }, #{count => 1}) 462: end). 463: 464: msg_sent_to_offline_user(Config) -> 465: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 466: %% Bob goes offline 467: mongoose_helper:logout_user(Config, Bob), 468: 469: %% Alice sends a message to Bob 470: Msg1 = escalus_stanza:chat_to(Bob, <<"test">>), 471: escalus:send(Alice, Msg1), 472: 473: %% Bob goes online again 474: {_, BobSpecs} = extract_user_specs(Bob), 475: {ok, NewBob} = escalus_client:start(Config, BobSpecs, <<"new-session">>), 476: escalus:send(NewBob, escalus_stanza:presence(<<"available">>)), 477: Stanzas = escalus:wait_for_stanzas(NewBob, 2), 478: 479: escalus_new_assert:mix_match 480: ([is_presence, fun(Stanza) -> escalus_pred:is_chat_message(<<"test">>, Stanza) end], 481: Stanzas), 482: 483: %% Alice has conversation 484: check_inbox(Alice, [#conv{unread = 0, from = Alice, to = Bob, content = <<"test">>}]), 485: 486: %% Both check inbox and has a conversation 487: check_inbox(NewBob, [#conv{unread = 1, from = Alice, to = Bob, content = <<"test">>}]) 488: end). 489: 490: msg_sent_to_not_existing_user(Config) -> 491: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 492: %% Alice sends message to user that doesnt exist 493: Msg1 = escalus_stanza:chat_to(<<"not_existing_user@localhost">>, <<"test2">>), 494: escalus:send(Alice, Msg1), 495: 496: %% Alice receives error 497: ServiceUnavailable = escalus:wait_for_stanza(Alice), 498: escalus_pred:is_error(<<"cancel">>,<<"service-unavailable">>, ServiceUnavailable), 499: 500: %% Alice has this conversation in inbox. 501: check_inbox(Alice,[#conv{unread = 0, 502: from = Alice, 503: to = <<"not_existing_user@localhost">>, 504: content = <<"test2">>}]) 505: end). 506: 507: user_has_two_unread_messages(Config) -> 508: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 509: inbox_helper:send_msg(Kate, Mike, "Hello"), 510: inbox_helper:send_msg(Kate, Mike, "How are you"), 511: %% Mike has two unread messages in conversation with Kate 512: check_inbox(Mike, [#conv{unread = 2, from = Kate, to = Mike, content = <<"How are you">>}]), 513: %% Kate has one conv in her inbox (no unread messages) 514: check_inbox(Kate, [#conv{unread = 0, from = Kate, to = Mike, content = <<"How are you">>}]) 515: end). 516: 517: other_resources_do_not_interfere(Config) -> 518: %% regression test 519: escalus:fresh_story(Config, [{kate, 2}, {mike, 1}], fun(Kate, Kate2, Mike) -> 520: Prio = #xmlel{name = <<"priority">>, children = [#xmlcdata{content = <<"100">>}]}, 521: escalus_client:send(Kate2, escalus_stanza:presence(<<"available">>, [Prio])), 522: escalus_client:wait_for_stanza(Kate), 523: inbox_helper:send_msg(Kate, Mike, "Hello"), 524: inbox_helper:send_msg(Kate, Mike, "How are you"), 525: %% Mike has two unread messages in conversation with Kate 526: check_inbox(Mike, [#conv{unread = 2, from = Kate, to = Mike, content = <<"How are you">>}]), 527: %% Kate has one conv in her inbox (no unread messages) 528: check_inbox(Kate, [#conv{unread = 0, from = Kate, to = Mike, content = <<"How are you">>}]) 529: end). 530: 531: reset_unread_counter_with_reset_chat_marker(Config) -> 532: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 533: Msg = inbox_helper:send_msg(Kate, Mike, <<"Hi mike">>), 534: MsgId = exml_query:attr(Msg, <<"id">>), 535: 536: %% Mike has one unread message 537: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = <<"Hi mike">>}]), 538: ChatMarker = escalus_stanza:chat_marker(Kate, <<"displayed">>, MsgId), 539: %% Mike sends "displayed" chat marker to Kate 540: escalus:send(Mike, ChatMarker), 541: %% Now Mike asks for inbox second time. He has 0 unread messages now 542: check_inbox(Mike, [#conv{unread = 0, from = Kate, to = Mike, content = <<"Hi mike">>}]) 543: end). 544: 545: reset_unread_counter_with_reset_stanza(Config) -> 546: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 547: _Msg = inbox_helper:send_msg(Kate, Mike, <<"Hi mike">>), 548: 549: %% Mike has one unread message 550: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = <<"Hi mike">>}]), 551: %% Mike sends "reset" stanza 552: inbox_helper:reset_inbox(Mike, Kate), 553: %% Now Mike asks for inbox second time. He has 0 unread messages now 554: check_inbox(Mike, [#conv{unread = 0, from = Kate, to = Mike, content = <<"Hi mike">>}]), 555: %% Kate should not be receiving this stanza 556: inbox_helper:assert_has_no_stanzas(Kate) 557: end). 558: 559: reset_unread_counter_and_show_only_unread(Config) -> 560: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}, {alice, 1}], fun(Kate, Mike, Alice) -> 561: Msg = inbox_helper:send_msg(Kate, Mike), 562: MsgId = exml_query:attr(Msg, <<"id">>), 563: inbox_helper:get_inbox(Mike, #{ hidden_read => true }, #{count => 1}), 564: 565: ChatMarker = escalus_stanza:chat_marker(Kate, <<"displayed">>, MsgId), 566: escalus:send(Mike, ChatMarker), 567: 568: inbox_helper:get_inbox(Mike, #{ hidden_read => true }, #{count => 0}), 569: 570: inbox_helper:send_msg(Alice, Mike), 571: % Mike has two conversations, one with unread messages 572: inbox_helper:get_inbox(Mike, #{ hidden_read => true }, #{count => 1}), 573: inbox_helper:get_inbox(Mike, #{ hidden_read => false }, #{count => 2}) 574: end). 575: 576: check_total_unread_count_and_active_conv_count(Config) -> 577: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}, {alice, 1}], fun(Kate, Mike, Alice) -> 578: inbox_helper:send_and_mark_msg(Kate, Mike), 579: inbox_helper:send_msg(Alice, Mike), 580: inbox_helper:send_msg(Alice, Mike), 581: inbox_helper:send_msg(Kate, Mike), 582: inbox_helper:get_inbox(Mike, #{count => 2, unread_messages => 3, active_conversations => 2}) 583: end). 584: 585: check_total_unread_count_when_there_are_no_active_conversations(Config) -> 586: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 587: inbox_helper:send_and_mark_msg(Kate, Mike), 588: inbox_helper:get_inbox(Mike, #{count => 1, unread_messages => 0, active_conversations => 0}) 589: end). 590: 591: total_unread_count_and_active_convs_are_zero_at_no_activity(Config) -> 592: escalus:fresh_story(Config, [{kate, 1}], fun(Kate) -> 593: inbox_helper:get_inbox(Kate, #{count => 0, unread_messages => 0, active_conversations => 0}) 594: end). 595: 596: inbox_result_cannot_exceed_configured_limit(Config) -> 597: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}, {mike, 1}], fun(Alice, Bob, Kate, Mike) -> 598: inbox_helper:send_msg(Alice, Bob), 599: inbox_helper:send_msg(Kate, Bob), 600: inbox_helper:send_msg(Mike, Bob), 601: inbox_helper:get_inbox(Bob, #{count => 2}) 602: end). 603: 604: should_apply_lower_limit_when_both_provided(Config) -> 605: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}, {mike, 1}], fun(Alice, Bob, Kate, Mike) -> 606: inbox_helper:send_msg(Alice, Bob), 607: inbox_helper:send_msg(Kate, Bob), 608: inbox_helper:send_msg(Mike, Bob), 609: inbox_helper:get_inbox(Bob, #{limit => 1}, #{count => 1}) 610: end). 611: 612: try_to_reset_unread_counter_with_bad_marker(Config) -> 613: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 614: Msg1 = escalus_stanza:set_id(escalus_stanza:chat_to(Mike, <<"okey dockey">>), <<"111">>), 615: %% Kate sends message to Mike 616: escalus:send(Kate, Msg1), 617: M1 = escalus:wait_for_stanza(Mike), 618: escalus:assert(is_chat_message, M1), 619: %% Mike has one unread message 620: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = <<"okey dockey">>}]), 621: MsgId = <<"badId">>, 622: ChatMarker = escalus_stanza:chat_marker(Kate, <<"displayed">>, MsgId), 623: %% Mike sends "displayed" chat marker but 'id' field is wrong 624: escalus:send(Mike, ChatMarker), 625: %% Now Mike asks for inbox second time. Unread count should be still the same 626: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = <<"okey dockey">>}]) 627: end). 628: 629: non_reset_marker_should_not_affect_inbox(Config) -> 630: escalus:fresh_story(Config, [{kate, 1}, {mike, 1}], fun(Kate, Mike) -> 631: MsgId = <<"kate_to_mike">>, 632: MsgBody = <<"okey dockey">>, 633: Msg = escalus_stanza:set_id(escalus_stanza:chat_to(Mike, MsgBody), MsgId), 634: %% Kate sends message to Mike 635: escalus:send(Kate, Msg), 636: M1 = escalus:wait_for_stanza(Mike), 637: escalus:assert(is_chat_message, M1), 638: %% Mike has one unread message 639: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = MsgBody}]), 640: ChatMarker = escalus_stanza:chat_marker(Kate, <<"received">>, MsgId), 641: %% Mike sends "received" chat marker, which is not a reset_marker 642: escalus:send(Mike, ChatMarker), 643: CM = escalus:wait_for_stanza(Kate), 644: escalus:assert(is_message, CM), 645: %% Now Mike asks for inbox second time. Unread count should be still the same 646: check_inbox(Mike, [#conv{unread = 1, from = Kate, to = Mike, content = MsgBody}]), 647: check_inbox(Kate, [], #{hidden_read => true}, #{}) 648: end). 649: 650: %%-------------------------------------------------------------------- 651: %% Inbox tests muclight 652: %%-------------------------------------------------------------------- 653: 654: simple_groupchat_stored_in_all_inbox(Config) -> 655: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 656: Msg = <<"Hi Room!">>, 657: Id = <<"MyID">>, 658: Users = [Alice, Bob, Kate], 659: Room = inbox_helper:create_room(Alice, [Bob, Kate]), 660: AliceJid = inbox_helper:to_bare_lower(Alice), 661: KateJid = inbox_helper:to_bare_lower(Kate), 662: BobJid = inbox_helper:to_bare_lower(Bob), 663: RoomJid = room_bin_jid(Room), 664: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 665: Stanza = escalus_stanza:set_id( 666: escalus_stanza:groupchat_to(RoomJid, Msg), Id), 667: %% Alice sends message to a room 668: escalus:send(Alice, Stanza), 669: inbox_helper:wait_for_groupchat_msg(Users), 670: %% Alice has 0 unread messages 671: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 672: %% Bob and Kate have one conv with 1 unread message 673: check_inbox(Bob, [#conv{unread = 1, from = AliceRoomJid, to = BobJid, content = Msg}]), 674: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]) 675: end). 676: 677: advanced_groupchat_stored_in_all_inbox(Config) -> 678: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 679: Msg1 = <<"Hi Room!">>, 680: Msg2 = <<"How are you?">>, 681: Id1 = <<"id-1">>, 682: Id2 = <<"id-2">>, 683: Users = [Alice, Bob, Kate], 684: Room = pubsub_tools:pubsub_node_name(), 685: inbox_helper:create_room_and_check_inbox(Alice, [Bob, Kate], Room), 686: BobJid = inbox_helper:to_bare_lower(Bob), 687: AliceJid = inbox_helper:to_bare_lower(Alice), 688: KateJid = inbox_helper:to_bare_lower(Kate), 689: RoomJid = room_bin_jid(Room), 690: BobRoomJid = <<RoomJid/binary, "/", BobJid/binary>>, 691: Stanza1 = escalus_stanza:set_id( 692: escalus_stanza:groupchat_to(RoomJid, Msg1), Id1), 693: %% Alice sends msg to room 694: escalus:send(Alice, Stanza1), 695: inbox_helper:wait_for_groupchat_msg(Users), 696: %% Bob sends second message 697: Stanza2 = escalus_stanza:set_id( 698: escalus_stanza:groupchat_to(RoomJid, Msg2), Id2), 699: escalus:send(Bob, Stanza2), 700: inbox_helper:wait_for_groupchat_msg(Users), 701: %% Alice have one unread message (from Bob) 702: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg2}]), 703: %% Bob has 0 unread messages because he sent the last message 704: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg2}]), 705: %% Kate has 2 unread messages (from Alice and Bob) 706: check_inbox(Kate, [#conv{unread = 2, from = BobRoomJid, to = KateJid, content = Msg2}]) 707: end). 708: 709: groupchat_markers_one_reset(Config) -> 710: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 711: AliceJid = inbox_helper:to_bare_lower(Alice), 712: BobJid = inbox_helper:to_bare_lower(Bob), 713: KateJid = inbox_helper:to_bare_lower(Kate), 714: Room = inbox_helper:create_room(Alice, [Bob, Kate]), 715: RoomJid = room_bin_jid(Room), 716: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 717: Id = <<"markerId">>, 718: Users = [Alice, Bob, Kate], 719: Stanza1 = escalus_stanza:set_id( 720: escalus_stanza:groupchat_to(RoomJid, <<"marker time!">>), Id), 721: escalus:send(Alice, Stanza1), 722: inbox_helper:wait_for_groupchat_msg(Users), 723: ChatMarkerWOType = escalus_stanza:chat_marker(RoomJid,<<"displayed">>, Id), 724: ChatMarker = escalus_stanza:setattr(ChatMarkerWOType, <<"type">>, <<"groupchat">>), 725: %% User marks last message 726: escalus:send(Bob, ChatMarker), 727: %% participants receive marker 728: muc_helper:foreach_recipient([Alice, Bob, Kate], fun(Marker) -> 729: true = escalus_pred:is_chat_marker(<<"displayed">>, Id, Marker) end), 730: %% Bob has 0 unread messages because he reset his counter 731: check_inbox(Bob, [#conv{unread = 0, from = AliceRoomJid, 732: to = BobJid, content = <<"marker time!">>}]), 733: %% Alice has 0 unread messages because she was the sender 734: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, 735: to = AliceJid, content = <<"marker time!">>}]), 736: %% Kate still has unread message 737: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, 738: to = KateJid, content = <<"marker time!">>}]) 739: end). 740: 741: non_reset_marker_should_not_affect_muclight_inbox(Config) -> 742: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 743: % %% GIVEN 744: AliceJid = inbox_helper:to_bare_lower(Alice), 745: BobJid = inbox_helper:to_bare_lower(Bob), 746: KateJid = inbox_helper:to_bare_lower(Kate), 747: % %% WHEN DONE 748: Id = <<"some_ID">>, 749: Msg = <<"marker time!">>, 750: RoomName = pubsub_tools:pubsub_node_name(), 751: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 752: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 753: % %% AND MARKED WRONG 754: inbox_helper:mark_last_muclight_message(Bob, [Alice, Bob, Kate], <<"received">>), 755: inbox_helper:mark_last_muclight_message(Kate, [Alice, Bob, Kate], <<"acknowledged">>), 756: % %% THEN 757: %% Alice has 0 unread messages because she was the sender 758: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, 759: to = AliceJid, content = Msg}]), 760: %% Bob still has unread message 761: check_inbox(Bob, [#conv{unread = 1, from = AliceRoomJid, 762: to = BobJid, content = Msg}]), 763: %% Kate still has unread message 764: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, 765: to = KateJid, content = Msg}]) 766: end). 767: 768: groupchat_reset_stanza_resets_inbox(Config) -> 769: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 770: % %% WITH 771: Id = <<"some_ID">>, 772: Msg = <<"marker time!">>, 773: RoomName = pubsub_tools:pubsub_node_name(), 774: AliceJid = inbox_helper:to_bare_lower(Alice), 775: BobJid = inbox_helper:to_bare_lower(Bob), 776: KateJid = inbox_helper:to_bare_lower(Kate), 777: % %% WHEN A MESSAGE IS SENT 778: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 779: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 780: % %% AND WHEN SEND RESET FOR ROOM 781: inbox_helper:reset_inbox(Bob, RoomJid), 782: % %% THEN INBOX IS RESET FOR BOB, WITHOUT FORWARDING 783: %% Bob has 0 unread messages because he reset his counter 784: check_inbox(Bob, [#conv{unread = 0, from = AliceRoomJid, 785: to = BobJid, content = <<"marker time!">>}]), 786: %% Alice has 0 unread messages because she was the sender 787: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, 788: to = AliceJid, content = <<"marker time!">>}]), 789: %% Kate still has unread message 790: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, 791: to = KateJid, content = <<"marker time!">>}]), 792: %% And nobody received any other stanza 793: inbox_helper:assert_has_no_stanzas([Alice, Bob, Kate]) 794: end). 795: 796: %% this test combines options: 797: %% ... 798: %%{aff_changes, true}, 799: %%{remove_on_kicked, true}, 800: create_groupchat(Config) -> 801: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 802: RoomName = pubsub_tools:pubsub_node_name(), 803: inbox_helper:create_room_and_check_inbox(Bob, [Alice, Kate], RoomName) 804: end). 805: 806: %% this test combines options: 807: %% ... 808: %%{aff_changes, false}, 809: %%{remove_on_kicked, true}, 810: create_groupchat_no_affiliation_stored(Config) -> 811: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 812: InitOccupants = [{Alice, member}, {Kate, member}], 813: FinalOccupants = [{Bob, owner} | InitOccupants], 814: Msg = <<"Hi all!">>, 815: Users = [Alice, Bob, Kate], 816: InitConfig = [{<<"roomname">>, <<"Bob's room2">>}], 817: RoomNode = <<"bobroom2">>, 818: RoomJid = room_bin_jid(RoomNode), 819: AliceJid = inbox_helper:to_bare_lower(Alice), 820: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 821: BobJid = inbox_helper:to_bare_lower(Bob), 822: KateJid = inbox_helper:to_bare_lower(Kate), 823: %% Bob creates room 824: escalus:send(Bob, muc_light_helper:stanza_create_room(RoomNode, InitConfig, InitOccupants)), 825: muc_light_helper:verify_aff_bcast(FinalOccupants, FinalOccupants), 826: escalus:assert(is_iq_result, escalus:wait_for_stanza(Bob)), 827: %% affiliation change messages are not stored in inbox 828: [ check_inbox(User, []) || User <- Users ], 829: Stanza = escalus_stanza:set_id( 830: escalus_stanza:groupchat_to(RoomJid, Msg), <<"123">>), 831: %% Alice sends a message 832: escalus:send(Alice, Stanza), 833: inbox_helper:wait_for_groupchat_msg(Users), 834: %% Alice has 0 unread because she sent the last message 835: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 836: %% Bob and Kate have one unread message 837: check_inbox(Bob, [#conv{unread = 1, from = AliceRoomJid, to = BobJid, content = Msg}]), 838: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]) 839: end). 840: 841: %% this test combines options: 842: %% ... 843: %%{aff_changes, true}, 844: %%{remove_on_kicked, true}, 845: leave_and_remove_conversation(Config) -> 846: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 847: RoomName = pubsub_tools:pubsub_node_name(), 848: AliceJid = inbox_helper:to_bare_lower(Alice), 849: BobJid = inbox_helper:to_bare_lower(Bob), 850: KateJid = inbox_helper:to_bare_lower(Kate), 851: %% Alice creates a room and send msg 852: Msg = <<"Hi all">>, 853: Id = <<"leave-id">>, 854: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 855: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 856: %% Bob leaves the room 857: muc_light_helper:user_leave(RoomName, Bob, [{Alice, owner}, {Kate, member}]), 858: %% Alice and Kate have one message 859: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 860: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]), 861: %% Bob doesn't have conversation in his inbox 862: check_inbox(Bob, [], #{box => inbox}), 863: if_async_check_bin(Config, Bob, [#conv{unread = 2, from = RoomJid, to = BobJid, 864: verify = fun inbox_helper:verify_is_none_aff_change/2}]) 865: end). 866: 867: %% this test combines options: 868: %% ... 869: %%{aff_changes, true}, 870: %%{remove_on_kicked, false}, 871: leave_and_store_conversation(Config) -> 872: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 873: RoomName = pubsub_tools:pubsub_node_name(), 874: AliceJid = inbox_helper:to_bare_lower(Alice), 875: BobJid = inbox_helper:to_bare_lower(Bob), 876: KateJid = inbox_helper:to_bare_lower(Kate), 877: %% Alice creates a room and send msg 878: Msg = <<"Hi all">>, 879: Id = <<"leave-id">>, 880: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 881: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 882: %% Bob leaves room 883: muc_light_helper:user_leave(RoomName, Bob, [{Alice, owner}, {Kate, member}]), 884: %% Alice and Kate have conversation 885: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 886: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]), 887: %% Bob still has a conversation in inbox. Two unread - first is invitation, 888: %% the second is the leaving affiliation 889: check_inbox(Bob, [#conv{unread = 2, from = RoomJid, to = BobJid, 890: verify = fun inbox_helper:verify_is_none_aff_change/2}]) 891: end). 892: 893: %% this test combines options: 894: %% ... 895: %%{aff_changes, false}, 896: %%{remove_on_kicked, true}, 897: no_aff_stored_and_remove_on_kicked(Config) -> 898: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 899: AliceJid = inbox_helper:to_bare_lower(Alice), 900: BobJid = inbox_helper:to_bare_lower(Bob), 901: KateJid = inbox_helper:to_bare_lower(Kate), 902: RoomJid = room_bin_jid(?ROOM3), 903: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 904: Msg = <<"Hi all">>, 905: Users = [Alice, Bob, Kate], 906: Stanza = escalus_stanza:set_id( 907: escalus_stanza:groupchat_to(RoomJid, Msg), <<"33">>), 908: %% Alice sends a message 909: escalus:send(Alice, Stanza), 910: inbox_helper:wait_for_groupchat_msg(Users), 911: %% Bob leaves the room 912: muc_light_helper:user_leave(?ROOM3, Bob, [{Alice, owner}, {Kate, member}]), 913: %% Alice and Kate have message in groupchats 914: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 915: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]), 916: %% Bob doesnt have a conversation in inbox 917: check_inbox(Bob, [], #{box => inbox}), 918: if_async_check_bin(Config, Bob, [#conv{unread = 1, from = AliceRoomJid, to = BobJid, content = Msg}]) 919: end). 920: 921: %% this test combines options: 922: %% ... 923: %%{aff_changes, true}, 924: %%{remove_on_kicked, false}, 925: no_stored_and_remain_after_kicked(Config) -> 926: escalus:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 927: AliceJid = inbox_helper:to_bare_lower(Alice), 928: KateJid = inbox_helper:to_bare_lower(Kate), 929: BobJid = inbox_helper:to_bare_lower(Bob), 930: RoomJid = room_bin_jid(?ROOM4), 931: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 932: Msg = <<"Hi all">>, 933: Users = [Alice, Bob, Kate], 934: Stanza = escalus_stanza:set_id( 935: escalus_stanza:groupchat_to(RoomJid, Msg), <<"33">>), 936: %% Alice sends a message 937: escalus:send(Alice, Stanza), 938: inbox_helper:wait_for_groupchat_msg(Users), 939: %% Bob leaves the room 940: muc_light_helper:user_leave(?ROOM4, Bob, [{Alice, owner}, {Kate, member}]), 941: %% Alice and Kate have message in groupchats 942: check_inbox(Alice, [#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 943: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]), 944: %% Bob have a conversation in inbox. First unread is message from Alice, the second the affiliation change 945: check_inbox(Bob, [#conv{unread = 2, from = RoomJid, to = BobJid, 946: verify = fun inbox_helper:verify_is_none_aff_change/2}]) 947: end). 948: 949: groupchat_markers_one_reset_room_created(Config) -> 950: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 951: Id = <<"random-id">>, 952: Msg = <<"Welcome guys">>, 953: RoomName = pubsub_tools:pubsub_node_name(), 954: AliceJid = inbox_helper:to_bare_lower(Alice), 955: BobJid = inbox_helper:to_bare_lower(Bob), 956: KateJid = inbox_helper:to_bare_lower(Kate), 957: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 958: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 959: %% Now Bob sends marker 960: inbox_helper:mark_last_muclight_message(Bob, [Alice, Bob, Kate]), 961: %% The crew ask for inbox second time. Only Kate has unread messages 962: check_inbox(Alice,[#conv{unread = 0, from = AliceRoomJid, to = AliceJid, content = Msg}]), 963: check_inbox(Kate, [#conv{unread = 1, from = AliceRoomJid, to = KateJid, content = Msg}]), 964: check_inbox(Bob, [#conv{unread = 0, from = AliceRoomJid, to = BobJid, content = Msg}]) 965: end). 966: 967: groupchat_markers_all_reset_room_created(Config) -> 968: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 969: Id = <<"random-id">>, 970: Msg = <<"Mark me!">>, 971: RoomName = pubsub_tools:pubsub_node_name(), 972: AliceJid = inbox_helper:to_bare_lower(Alice), 973: RoomJid = inbox_helper:create_room_send_msg_check_inbox(Alice, [Bob, Kate], RoomName, Msg, Id), 974: AliceRoomJid = <<RoomJid/binary, "/", AliceJid/binary>>, 975: [inbox_helper:mark_last_muclight_message(U, [Alice, Bob, Kate]) || U <- [Bob, Kate]], 976: inbox_helper:foreach_check_inbox([Bob, Kate, Alice], 0, AliceRoomJid, Msg) 977: end). 978: 979: inbox_does_not_trigger_does_user_exist(Config) -> 980: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 981: Msg = <<"Mark me!">>, 982: RoomName = inbox_helper:create_room(Alice, [Bob, Kate]), 983: RoomJid = room_bin_jid(RoomName), 984: HookHandlerExtra = start_hook_listener(), 985: Stanza = escalus_stanza:groupchat_to(RoomJid, Msg), 986: %% Alice sends message to a room 987: escalus:send(Alice, Stanza), 988: [escalus:wait_for_stanza(User) || User <- [Alice, Bob, Kate]], 989: stop_hook_listener(HookHandlerExtra), 990: verify_hook_listener(RoomName) 991: end). 992: 993: system_message_is_correctly_avoided(Config) -> 994: escalus:story(Config, [{alice, 1}, {alice_bis, 1}, {bob, 1}], fun(Alice, AliceBis, Bob) -> 995: %% Variables 996: Id1 = <<"id-1">>, 997: Id2 = <<"id-2">>, 998: Msg1 = <<"Hi Room!">>, 999: Msg2 = <<"How are you?">>, 1000: Users = [Alice, AliceBis, Bob], 1001: InitOccupants = [{M, member} || M <- [AliceBis, Bob]], 1002: Room = atom_to_binary(?FUNCTION_NAME, utf8), 1003: BobJid = inbox_helper:to_bare_lower(Bob), 1004: AliceJid = inbox_helper:to_bare_lower(Alice), 1005: AliceBisJid = inbox_helper:to_bare_lower(AliceBis), 1006: RoomJid = room_bin_jid(Room), 1007: %% Given a room 1008: muc_light_helper:given_muc_light_room(Room, Alice, InitOccupants), 1009: BobRoomJid = <<RoomJid/binary, "/", BobJid/binary>>, 1010: Stanza1 = escalus_stanza:set_id(escalus_stanza:groupchat_to(RoomJid, Msg1), Id1), 1011: %% Alice sends msg to room 1012: escalus:send(Alice, Stanza1), 1013: inbox_helper:wait_for_groupchat_msg(Users), 1014: %% Bob sends second message 1015: Stanza2 = escalus_stanza:set_id(escalus_stanza:groupchat_to(RoomJid, Msg2), Id2), 1016: escalus:send(Bob, Stanza2), 1017: inbox_helper:wait_for_groupchat_msg(Users), 1018: %% Alice has one unread message (from Bob) 1019: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg2}]), 1020: %% Bob has 0 unread messages because he sent the last message 1021: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg2}]), 1022: %% AliceBis has 2 unread messages (from Alice and Bob) and does not have the affiliation 1023: check_inbox(AliceBis, [#conv{unread = 2, from = BobRoomJid, to = AliceBisJid, content = Msg2}]) 1024: end). 1025: 1026: %%-------------------------------------------------------------------- 1027: %% Classic MUC tests 1028: %%-------------------------------------------------------------------- 1029: 1030: simple_groupchat_stored_in_all_inbox_muc(Config) -> 1031: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1032: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1033: Users = [Alice, Bob, Kate], 1034: Msg = <<"Hi Room!">>, 1035: Id = <<"MyID">>, 1036: Room = ?config(room, RoomConfig), 1037: RoomAddr = muc_helper:room_address(Room), 1038: 1039: inbox_helper:enter_room(Room, Users), 1040: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1041: Stanza = escalus_stanza:set_id( 1042: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1043: escalus:send(Bob, Stanza), 1044: inbox_helper:wait_for_groupchat_msg(Users), 1045: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1046: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1047: %% Bob has 0 unread messages 1048: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1049: #{}, #{case_sensitive => true}), 1050: %% Alice and Kate have one conv with 1 unread message 1051: check_inbox(Alice,[#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1052: #{}, #{case_sensitive => true}), 1053: check_inbox(Kate, [#conv{unread = 1, from = BobRoomJid, to = KateJid, content = Msg}], 1054: #{}, #{case_sensitive => true}) 1055: end). 1056: 1057: simple_groupchat_stored_in_offline_users_inbox_muc(Config) -> 1058: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1059: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1060: Users = [Alice, Bob, Kate], 1061: Msg = <<"Hi Room!">>, 1062: Id = <<"MyID">>, 1063: Room = ?config(room, RoomConfig), 1064: RoomAddr = muc_helper:room_address(Room), 1065: 1066: inbox_helper:enter_room(Room, Users), 1067: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1068: inbox_helper:leave_room(Kate, Room, Users), 1069: Stanza = escalus_stanza:set_id( 1070: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1071: escalus:send(Bob, Stanza), 1072: inbox_helper:wait_for_groupchat_msg(Users -- [Kate]), 1073: 1074: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1075: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1076: %% Bob has 0 unread messages 1077: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1078: #{}, #{case_sensitive => true}), 1079: %% Alice and Kate have one conv with 1 unread message 1080: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1081: #{}, #{case_sensitive => true}), 1082: check_inbox(Kate, [#conv{unread = 1, from = BobRoomJid, to = KateJid, content = Msg}], 1083: #{}, #{case_sensitive => true}) 1084: end). 1085: 1086: 1087: unread_count_is_the_same_after_going_online_again(Config) -> 1088: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1089: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1090: Users = [Alice, Bob, Kate], 1091: Msg = <<"Hi Room!">>, 1092: Id = <<"MyID">>, 1093: Room = ?config(room, RoomConfig), 1094: RoomAddr = muc_helper:room_address(Room), 1095: 1096: inbox_helper:enter_room(Room, Users), 1097: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1098: inbox_helper:leave_room(Kate, Room, Users), 1099: Stanza = escalus_stanza:set_id( 1100: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1101: escalus:send(Bob, Stanza), 1102: inbox_helper:wait_for_groupchat_msg(Users -- [Kate]), 1103: inbox_helper:enter_room(Room, Kate, Users -- [Kate], 1), 1104: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1105: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1106: %% Bob has 0 unread messages 1107: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1108: #{}, #{case_sensitive => true}), 1109: %% Alice and Kate have one conv with 1 unread message 1110: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1111: #{}, #{case_sensitive => true}), 1112: check_inbox(Kate, [#conv{unread = 1, from = BobRoomJid, to = KateJid, content = Msg}], 1113: #{}, #{case_sensitive => true}) 1114: end). 1115: 1116: unread_count_is_reset_after_sending_chatmarker(Config) -> 1117: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1118: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1119: Users = [Alice, Bob, Kate], 1120: Msg = <<"Hi Room!">>, 1121: Id = <<"MyID">>, 1122: Room = ?config(room, RoomConfig), 1123: RoomAddr = muc_helper:room_address(Room), 1124: 1125: inbox_helper:enter_room(Room, Users), 1126: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1127: Stanza = escalus_stanza:set_id( 1128: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1129: escalus:send(Bob, Stanza), 1130: inbox_helper:wait_for_groupchat_msg(Users), 1131: ChatMarkerWOType = escalus_stanza:chat_marker(RoomAddr, <<"displayed">>, Id), 1132: ChatMarker = escalus_stanza:setattr(ChatMarkerWOType, <<"type">>, <<"groupchat">>), 1133: %% User marks last message 1134: escalus:send(Kate, ChatMarker), 1135: inbox_helper:wait_for_groupchat_msg(Users), 1136: 1137: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1138: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1139: %% Bob has 0 unread messages 1140: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1141: #{}, #{case_sensitive => true}), 1142: %% Alice have one conv with 1 unread message 1143: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1144: #{}, #{case_sensitive => true}), 1145: %% Kate has 0 unread messages 1146: check_inbox(Kate, [#conv{unread = 0, from = BobRoomJid, to = KateJid, content = Msg}], 1147: #{}, #{case_sensitive => true}) 1148: end). 1149: 1150: non_reset_marker_should_not_affect_muc_inbox(Config) -> 1151: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1152: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1153: % %% GIVEN 1154: Users = [Alice, Bob, Kate], 1155: Msg = <<"Hi Room!">>, 1156: Id = <<"MyID">>, 1157: Room = ?config(room, RoomConfig), 1158: RoomAddr = muc_helper:room_address(Room), 1159: 1160: % %% WHEN 1161: inbox_helper:enter_room(Room, Users), 1162: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1163: Stanza = escalus_stanza:set_id(escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1164: escalus:send(Bob, Stanza), 1165: inbox_helper:wait_for_groupchat_msg(Users), 1166: % %% AND MARKED WRONG 1167: KateChatMarkerWOType = escalus_stanza:chat_marker(RoomAddr,<<"acknowledged">>, Id), 1168: KateChatMarker = escalus_stanza:setattr(KateChatMarkerWOType, <<"type">>, <<"groupchat">>), 1169: escalus:send(Kate, KateChatMarker), 1170: inbox_helper:wait_for_groupchat_msg(Users), 1171: 1172: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1173: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1174: % %% THEN 1175: %% Bob has 0 unread messages 1176: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1177: #{}, #{case_sensitive => true}), 1178: %% Alice have one conv with 1 unread message 1179: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1180: #{}, #{case_sensitive => true}), 1181: %% Kate has 1 unread messages 1182: check_inbox(Kate, [#conv{unread = 1, from = BobRoomJid, to = KateJid, content = Msg}], 1183: #{}, #{case_sensitive => true}) 1184: end). 1185: 1186: unread_count_is_reset_after_sending_reset_stanza(Config) -> 1187: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1188: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1189: % %% WITH 1190: Users = [Alice, Bob, Kate], 1191: Msg = <<"Hi Room!">>, 1192: Id = <<"MyID">>, 1193: Room = ?config(room, RoomConfig), 1194: RoomAddr = muc_helper:room_address(Room), 1195: % %% PROVIDED 1196: inbox_helper:enter_room(Room, Users), 1197: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1198: % %% WHEN A MESSAGE IS SENT 1199: Stanza = escalus_stanza:set_id( 1200: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1201: escalus:send(Bob, Stanza), 1202: inbox_helper:wait_for_groupchat_msg(Users), 1203: [AliceJid, BobJid, KateJid] = lists:map(fun inbox_helper:to_bare_lower/1, Users), 1204: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1205: %% Make sure Kate gets her inbox updated 1206: check_inbox(Kate, [#conv{unread = 1, from = BobRoomJid, to = KateJid, content = Msg}], 1207: #{}, #{case_sensitive => true}), 1208: % %% AND WHEN SEND RESET FOR ROOM 1209: inbox_helper:reset_inbox(Kate, RoomAddr), 1210: 1211: %% Bob has 0 unread messages 1212: check_inbox(Bob, [#conv{unread = 0, from = BobRoomJid, to = BobJid, content = Msg}], 1213: #{}, #{case_sensitive => true}), 1214: %% Alice have one conv with 1 unread message 1215: check_inbox(Alice, [#conv{unread = 1, from = BobRoomJid, to = AliceJid, content = Msg}], 1216: #{}, #{case_sensitive => true}), 1217: %% Kate has 0 unread messages 1218: check_inbox(Kate, [#conv{unread = 0, from = BobRoomJid, to = KateJid, content = Msg}], 1219: #{}, #{case_sensitive => true}), 1220: inbox_helper:assert_has_no_stanzas([Alice, Bob, Kate]) 1221: end). 1222: 1223: private_messages_are_handled_as_one2one(Config) -> 1224: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1225: RoomConfig = muc_helper:start_room(Config, extract_user_specs(Alice), muc_helper:fresh_room_name(), <<"some_friendly_name">>, default), 1226: Users = [Alice, Bob, Kate], 1227: Msg = <<"Hi Room!">>, 1228: Id = <<"MyID">>, 1229: Room = ?config(room, RoomConfig), 1230: BobRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Bob)), 1231: KateRoomJid = muc_helper:room_address(Room, inbox_helper:nick(Kate)), 1232: 1233: inbox_helper:enter_room(Room, Users), 1234: inbox_helper:make_members(Room, Alice, Users -- [Alice]), 1235: Stanza = escalus_stanza:set_id( 1236: escalus_stanza:chat_to(BobRoomJid, Msg), Id), 1237: escalus:send(Kate, Stanza), 1238: _BobsPrivMsg = escalus:wait_for_stanza(Bob), 1239: 1240: KateJid = inbox_helper:to_bare_lower(Kate), 1241: %% Bob has 1 unread message 1242: check_inbox(Bob, [#conv{unread = 1, from = KateRoomJid, to = BobRoomJid, content = Msg}], 1243: #{}, #{case_sensitive => true}), 1244: %% Alice gets nothing 1245: check_inbox(Alice, []), 1246: %% Kate has 1 conv with 0 unread messages 1247: check_inbox(Kate, [#conv{unread = 0, from = KateJid, to = BobRoomJid, content = Msg}], 1248: #{}, #{case_sensitive => true, check_resource => false}) 1249: end). 1250: 1251: %%-------------------------------------------------------------------- 1252: %% Timestamp-related tests 1253: %%-------------------------------------------------------------------- 1254: 1255: timestamp_is_updated_on_new_message(Config) -> 1256: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1257: Body1 = <<"Hello Bob">>, 1258: Body2 = <<"Are you there?">>, 1259: %% We capture the timestamp after the first message 1260: escalus:send(Alice, escalus_stanza:chat_to(Bob, Body1)), 1261: _M1 = escalus:wait_for_stanza(Bob), 1262: #{respond_messages := [Item1]} 1263: = check_inbox(Bob, [#conv{unread = 1, from = Alice, to = Bob, content = Body1}]), 1264: TStamp1 = inbox_helper:timestamp_from_item(Item1), 1265: %% We capture the timestamp after the second message 1266: escalus:send(Alice, escalus_stanza:chat_to(Bob, Body2)), 1267: _M2 = escalus:wait_for_stanza(Bob), 1268: #{respond_messages := [Item2]} 1269: = check_inbox(Bob, [#conv{unread = 2, from = Alice, to = Bob, content = Body2}]), 1270: TStamp2 = inbox_helper:timestamp_from_item(Item2), 1271: %% Timestamp after second message must be higher 1272: case TStamp2 > TStamp1 of 1273: true -> ok; 1274: false -> error(#{ type => timestamp_is_not_greater, 1275: item1 => Item1, 1276: item2 => Item2, 1277: tstamp1 => TStamp1, 1278: tstamp2 => TStamp2 }) 1279: end 1280: end). 1281: 1282: order_by_timestamp_ascending(Config) -> 1283: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1284: #{ Alice := AliceConvs, Bob := BobConvs, Kate := KateConvs } = 1285: given_conversations_between(Alice, [Bob, Kate]), 1286: 1287: %% Alice has two conversations in her inbox (no unread messages) 1288: %% check_inbox will reverse conversation list automatically 1289: check_inbox(Alice, AliceConvs, #{ order => asc }, #{}), 1290: 1291: %% Kate has one conversation with one unread 1292: check_inbox(Kate, KateConvs), 1293: 1294: %% Bob has one conversation with one unread 1295: check_inbox(Bob, BobConvs) 1296: end). 1297: 1298: get_by_timestamp_range(Config) -> 1299: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1300: #{ Alice := AliceConvs, time_before := TimeBefore } = 1301: given_conversations_between(Alice, [Bob, Kate]), 1302: 1303: ConvWithBob = lists:keyfind(Bob, #conv.to, AliceConvs), 1304: TimeAfterBob = ConvWithBob#conv.time_after, 1305: 1306: %% Between given timestamps we have only one conversation: with Bob 1307: check_inbox(Alice, [ConvWithBob], #{ start => TimeBefore, 'end' => TimeAfterBob }, #{}) 1308: end). 1309: 1310: get_with_start_timestamp(Config) -> 1311: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1312: #{ Alice := AliceConvs } = 1313: given_conversations_between(Alice, [Bob, Kate]), 1314: 1315: ConvWithBob = lists:keyfind(Bob, #conv.to, AliceConvs), 1316: TimeAfterBob = ConvWithBob#conv.time_after, 1317: ConvWithKate = lists:keyfind(Kate, #conv.to, AliceConvs), 1318: 1319: %% After given timestamp we have only one conversation: with Kate 1320: check_inbox(Alice, [ConvWithKate], #{ start => TimeAfterBob }, #{}) 1321: end). 1322: 1323: get_with_end_timestamp(Config) -> 1324: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1325: #{ Alice := AliceConvs } = 1326: given_conversations_between(Alice, [Bob, Kate]), 1327: 1328: ConvWithBob = lists:keyfind(Bob, #conv.to, AliceConvs), 1329: TimeAfterBob = ConvWithBob#conv.time_after, 1330: %% Before given timestamp we have only one conversation: with Bob 1331: %% TODO: Improve this test to store 3+ conversations in Alice's inbox 1332: check_inbox(Alice, [ConvWithBob], #{ 'end' => TimeAfterBob }, #{}) 1333: end). 1334: 1335: 1336: %% Bin flushes tests 1337: bin_is_not_included_by_default(Config) -> 1338: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1339: RoomName = create_room_and_make_users_leave(Alice, Bob, Kate), 1340: RoomJid = room_bin_jid(RoomName), 1341: BobJid = inbox_helper:to_bare_lower(Bob), 1342: Convs = [#conv{unread = 1, from = RoomJid, to = BobJid, 1343: verify = fun inbox_helper:verify_is_none_aff_change/2}], 1344: %% Fetching all does include it 1345: check_inbox(Bob, Convs, #{box => all}), 1346: %% Fetching without explicit box name skips the bin 1347: check_inbox(Bob, [], #{}) 1348: end). 1349: 1350: rest_api_bin_flush_user(Config) -> 1351: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1352: create_room_and_make_users_leave(Alice, Bob, Kate), 1353: %% It is not in his bin anymore after triggering a bin flush 1354: BobName = escalus_utils:get_username(Bob), 1355: BobDomain = escalus_utils:get_server(Bob), 1356: Path = <<"/inbox", "/", (BobDomain)/binary, "/", (BobName)/binary, "/0/bin">>, 1357: {{<<"200">>, <<"OK">>}, NumOfRows} = rest_helper:delete(admin, Path), 1358: ?assertEqual(1, NumOfRows), 1359: check_inbox(Bob, [], #{box => bin}) 1360: end). 1361: 1362: rest_api_bin_flush_user_errors(Config) -> 1363: Config1 = escalus_fresh:create_users(Config, [{alice, 1}]), 1364: User = escalus_users:get_username(Config1, alice), 1365: Domain = escalus_users:get_server(Config1, alice), 1366: {{<<"400">>, <<"Bad Request">>}, <<"Invalid number of days">>} = 1367: rest_helper:delete(admin, <<"/inbox/", Domain/binary, "/", User/binary, "/x/bin">>), 1368: {{<<"400">>, <<"Bad Request">>}, <<"Invalid JID">>} = 1369: rest_helper:delete(admin, <<"/inbox/", Domain/binary, "/@/0/bin">>), 1370: {{<<"404">>, <<"Not Found">>}, <<"Domain not found">>} = 1371: rest_helper:delete(admin, <<"/inbox/baddomain/", User/binary, "/0/bin">>), 1372: {{<<"404">>, <<"Not Found">>}, <<"User baduser@", _/binary>>} = 1373: rest_helper:delete(admin, <<"/inbox/", Domain/binary, "/baduser/0/bin">>). 1374: 1375: rest_api_bin_flush_all(Config) -> 1376: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1377: create_room_and_make_users_leave(Alice, Bob, Kate), 1378: %% It is not in any bin anymore after triggering a bin flush 1379: HostTypePath = uri_string:normalize(#{path => domain_helper:host_type()}), 1380: Path = <<"/inbox/", HostTypePath/binary, "/0/bin">>, 1381: {{<<"200">>, <<"OK">>}, NumOfRows} = rest_helper:delete(admin, Path), 1382: ?assertEqual(2, NumOfRows), 1383: check_inbox(Bob, [], #{box => bin}), 1384: check_inbox(Kate, [], #{box => bin}) 1385: end). 1386: 1387: rest_api_bin_flush_all_errors(_Config) -> 1388: HostTypePath = uri_string:normalize(#{path => domain_helper:host_type()}), 1389: {{<<"400">>, <<"Bad Request">>}, <<"Invalid number of days">>} = 1390: rest_helper:delete(admin, <<"/inbox/", HostTypePath/binary, "/x/bin">>), 1391: {{<<"404">>, <<"Not Found">>}, <<"Host type not found">>} = 1392: rest_helper:delete(admin, <<"/inbox/bad_host_type/0/bin">>). 1393: 1394: timeout_cleaner_flush_all(Config) -> 1395: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1396: create_room_and_make_users_leave(Alice, Bob, Kate), 1397: %% It is eventually not in any bin thanks to the periodic cleanouts 1398: check_inbox(Bob, [], #{box => bin}), 1399: check_inbox(Kate, [], #{box => bin}) 1400: end). 1401: 1402: xmpp_bin_flush(Config) -> 1403: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 1404: create_room_and_make_users_leave(Alice, Bob, Kate), 1405: %% It is eventually not in any bin thanks to the periodic cleanouts 1406: %% Bob requests flush through xmpp 1407: Iq = escalus_stanza:iq(<<"set">>, 1408: [#xmlel{name = <<"empty-bin">>, 1409: attrs = [{<<"xmlns">>, inbox_helper:inbox_ns()}], 1410: children = []}]), 1411: escalus:send(Bob, Iq), 1412: escalus:assert(is_iq_result, [Iq], escalus:wait_for_stanza(Bob)), 1413: check_inbox(Bob, [], #{box => bin}) 1414: end). 1415: 1416: 1417: %% helpers 1418: create_room_and_make_users_leave(Alice, Bob, Kate) -> 1419: RoomName = pubsub_tools:pubsub_node_name(), 1420: inbox_helper:create_room_and_check_inbox(Alice, [Bob, Kate], RoomName), 1421: %% Bob leaves the room 1422: muc_light_helper:user_leave(RoomName, Bob, [{Alice, owner}, {Kate, member}]), 1423: muc_light_helper:user_leave(RoomName, Kate, [{Alice, owner}]), 1424: %% Bob doesn't have conversation in his inbox, nor Kate 1425: check_inbox(Bob, [], #{box => inbox}), 1426: check_inbox(Kate, [], #{box => inbox}), 1427: RoomName. 1428: 1429: if_async_check_bin(Config, Bob, Convs) -> 1430: case maps:get(backend, ?config(inbox_opts, Config), rdbms) of 1431: rdbms -> ok; 1432: rdbms_async -> 1433: check_inbox(Bob, Convs, #{box => bin}) 1434: end. 1435: 1436: start_hook_listener() -> 1437: TestCasePid = self(), 1438: distributed_helper:rpc(distributed_helper:mim(), ?MODULE, rpc_start_hook_handler, [TestCasePid, domain_helper:host_type()]). 1439: 1440: stop_hook_listener(HookExtra) -> 1441: distributed_helper:rpc(distributed_helper:mim(), ?MODULE, rpc_stop_hook_handler, [HookExtra, domain_helper:host_type()]). 1442: 1443: rpc_start_hook_handler(TestCasePid, HostType) -> 1444: Extra = #{test_case_pid => TestCasePid}, 1445: gen_hook:add_handler(does_user_exist, HostType, fun ?MODULE:hook_handler_fn/3, Extra, 1), 1446: Extra. 1447: 1448: rpc_stop_hook_handler(HookExtra, HostType) -> 1449: gen_hook:delete_handler(does_user_exist, HostType, fun ?MODULE:hook_handler_fn/3, HookExtra, 1). 1450: 1451: hook_handler_fn(Acc, 1452: #{jid := User} = _Params, 1453: #{test_case_pid := Pid} = _Extra) -> 1454: Pid ! {input, User#jid.luser}, 1455: {ok, Acc}. 1456: 1457: verify_hook_listener(RoomName) -> 1458: receive 1459: {input, RoomName} -> 1460: ct:fail("does_user_exist was called with a room jid"); 1461: {input, _} -> 1462: verify_hook_listener(RoomName) 1463: after 100 -> 1464: ct:pal("OK") 1465: end.