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