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