1: -module(xep_0352_csi_SUITE). 2: 3: -include_lib("exml/include/exml.hrl"). 4: -include_lib("escalus/include/escalus.hrl"). 5: 6: -compile([export_all, nowarn_export_all]). 7: 8: -import(domain_helper, [host_type/0]). 9: -import(config_parser_helper, [default_mod_config/1, mod_config/2]). 10: 11: -define(CSI_BUFFER_MAX, 10). 12: 13: all() -> 14: [{group, basic}]. 15: 16: 17: groups() -> 18: [{basic, [parallel, shuffle], all_tests()}]. 19: 20: all_tests() -> 21: [ 22: server_announces_csi, 23: alice_is_inactive_and_no_stanza_arrived, 24: alice_gets_msgs_after_activate, 25: alice_gets_msgs_after_activate_in_order, 26: alice_gets_message_after_buffer_overflow, 27: alice_gets_buffered_messages_after_reconnection_with_sm, 28: alice_gets_buffered_messages_after_stream_resumption, 29: bob_gets_msgs_from_inactive_alice, 30: alice_is_inactive_but_sends_sm_req_and_recives_ack 31: ]. 32: 33: suite() -> 34: escalus:suite(). 35: 36: init_per_suite(Config) -> 37: NewConfig = dynamic_modules:save_modules(host_type(), Config), 38: dynamic_modules:ensure_modules( 39: host_type(), [{mod_offline, default_mod_config(mod_offline)}, 40: {mod_csi, mod_config(mod_csi, #{buffer_max => ?CSI_BUFFER_MAX})}]), 41: [{escalus_user_db, {module, escalus_ejabberd}} | escalus:init_per_suite(NewConfig)]. 42: 43: end_per_suite(Config) -> 44: escalus_fresh:clean(), 45: dynamic_modules:restore_modules(Config), 46: escalus:end_per_suite(Config). 47: 48: init_per_group(_, Config) -> 49: escalus_users:update_userspec(Config, alice, stream_management, true). 50: 51: end_per_group(_Group, Config) -> 52: Config. 53: 54: init_per_testcase(CaseName, Config) -> 55: escalus:init_per_testcase(CaseName, Config). 56: 57: end_per_testcase(CaseName, Config) -> 58: escalus:end_per_testcase(CaseName, Config). 59: 60: server_announces_csi(Config) -> 61: NewConfig = escalus_fresh:create_users(Config, [{alice, 1}]), 62: Spec = escalus_users:get_userspec(NewConfig, alice), 63: Steps = [start_stream, 64: stream_features, 65: maybe_use_ssl, 66: authenticate, 67: bind, 68: session], 69: {ok, _Client, Features} = escalus_connection:start(Spec, Steps), 70: true = proplists:get_value(client_state_indication, Features). 71: 72: alice_is_inactive_and_no_stanza_arrived(Config) -> 73: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 74: given_client_is_inactive_and_messages_sent(Alice, Bob, 1), 75: 76: escalus_assert:has_no_stanzas(Alice) 77: end). 78: 79: alice_gets_msgs_after_activate(Config) -> 80: alice_gets_msgs_after_activate(Config, 1). 81: 82: alice_gets_msgs_after_activate_in_order(Config) -> 83: alice_gets_msgs_after_activate(Config, 3). 84: 85: alice_gets_msgs_after_activate(Config, N) -> 86: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 87: %%Given 88: Msgs = given_client_is_inactive_and_messages_sent(Alice, Bob, N), 89: 90: %%When client becomes active again 91: escalus:send(Alice, csi_stanza(<<"active">>)), 92: 93: then_client_receives_message(Alice, Msgs) 94: end). 95: 96: alice_gets_buffered_messages_after_reconnection_with_sm(Config) -> 97: NewConfig = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 98: AliceSpec = escalus_users:get_userspec(NewConfig, alice), 99: BobSpec = escalus_users:get_userspec(NewConfig, bob), 100: {ok, Alice0 = #client{props = AliceProps}, _} = escalus_connection:start(AliceSpec), 101: JID = make_jid_from_spec(AliceProps), 102: Alice = Alice0#client{jid = JID}, 103: {ok, Bob, _} = escalus_connection:start(BobSpec), 104: 105: given_client_is_inactive(Alice), 106: 107: MsgsToAlice = given_client_is_inactive_and_messages_sent(Alice, Bob, 5), 108: 109: %% then Alice disconnects 110: 111: escalus_connection:kill(Alice), 112: 113: {ok, Alice2, _} = escalus_connection:start(AliceSpec), 114: 115: escalus_connection:send(Alice2, escalus_stanza:presence(<<"available">>)), 116: 117: then_client_receives_message(Alice2, MsgsToAlice), 118: 119: ok. 120: 121: alice_gets_buffered_messages_after_stream_resumption(Config) -> 122: ConnSteps = [start_stream, 123: stream_features, 124: authenticate, 125: bind, 126: session, 127: stream_resumption], 128: NewConfig = escalus_fresh:create_users(Config, [{alice, 1}, {bob, 1}]), 129: AliceSpec = escalus_users:get_userspec(NewConfig, alice), 130: BobSpec = escalus_users:get_userspec(NewConfig, bob), 131: {ok, Alice0 = #client{props = AliceProps}, _} = escalus_connection:start(AliceSpec, 132: ConnSteps), 133: JID = make_jid_from_spec(AliceProps), 134: Alice = Alice0#client{jid = JID}, 135: 136: escalus_connection:send(Alice, escalus_stanza:presence(<<"available">>)), 137: escalus:wait_for_stanza(Alice), 138: {ok, Bob, _} = escalus_connection:start(BobSpec), 139: 140: given_client_is_inactive(Alice), 141: 142: MsgsToAlice = given_client_is_inactive_and_messages_sent(Alice, Bob, 5), 143: 144: %% then Alice disconnects 145: 146: escalus_connection:kill(Alice), 147: 148: SMID = proplists:get_value(smid, AliceProps), 149: ResumeSession = [start_stream, 150: stream_features, 151: authenticate, 152: mk_resume_stream(SMID, 1)], 153: 154: {ok, Alice2, _} = escalus_connection:start(AliceSpec, ResumeSession), 155: 156: escalus_connection:send(Alice2, escalus_stanza:presence(<<"available">>)), 157: 158: then_client_receives_message(Alice2, MsgsToAlice), 159: 160: ok. 161: 162: make_jid_from_spec(AliceProps) -> 163: AliceUsername = proplists:get_value(username, AliceProps), 164: AliceServer = proplists:get_value(server, AliceProps), 165: <<AliceUsername/binary, "@", AliceServer/binary>>. 166: 167: mk_resume_stream(SMID, PrevH) -> 168: fun (Conn = #client{props = Props}, Features) -> 169: escalus_connection:send(Conn, escalus_stanza:resume(SMID, PrevH)), 170: Resumed = escalus_connection:get_stanza(Conn, get_resumed), 171: true = escalus_pred:is_sm_resumed(SMID, Resumed), 172: {Conn#client{props = [{smid, SMID} | Props]}, Features} 173: end. 174: 175: alice_gets_message_after_buffer_overflow(Config) -> 176: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 177: Msgs = given_client_is_inactive_and_messages_sent(Alice, Bob, ?CSI_BUFFER_MAX+5), 178: 179: {Flushed, Awaiting} = lists:split(?CSI_BUFFER_MAX+1, Msgs), 180: 181: then_client_receives_message(Alice, Flushed), 182: %% and no other stanza 183: escalus_assert:has_no_stanzas(Alice), 184: %% Alice activates 185: escalus:send(Alice, csi_stanza(<<"active">>)), 186: %% ands gets remaining stanzas 187: then_client_receives_message(Alice, Awaiting) 188: end). 189: 190: bob_gets_msgs_from_inactive_alice(Config) -> 191: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 192: given_client_is_inactive_but_sends_messages(Alice, Bob, 1), 193: 194: escalus:assert(is_chat_message, escalus:wait_for_stanza(Bob)) 195: end). 196: 197: alice_is_inactive_but_sends_sm_req_and_recives_ack(Config) -> 198: escalus:fresh_story(Config, [{alice,1}], fun(Alice) -> 199: given_client_is_inactive(Alice), 200: 201: escalus:send(Alice, escalus_stanza:sm_request()), 202: 203: escalus:assert(is_sm_ack, escalus:wait_for_stanza(Alice)) 204: 205: end). 206: 207: given_client_is_inactive_but_sends_messages(Alice, Bob, N) -> 208: %%Given 209: MsgsToAlice = given_client_is_inactive_and_messages_sent(Alice, Bob, N), 210: 211: MsgsToBob = gen_msgs(<<"Hi, Bob">>, N), 212: send_msgs(Alice, Bob, MsgsToBob), 213: timer:sleep(1), 214: {MsgsToAlice, MsgsToBob}. 215: 216: 217: then_client_receives_message(Alice, Msgs) -> 218: [escalus:assert(is_chat_message, [Msg], escalus:wait_for_stanza(Alice)) || 219: Msg <- Msgs]. 220: 221: 222: given_client_is_inactive_and_messages_sent(Alice, Bob, N) -> 223: %%Given 224: given_client_is_inactive(Alice), 225: 226: timer:sleep(1000), 227: 228: %%When 229: Msgs = gen_msgs(<<"Hi, Alice">>, N), 230: send_msgs(Bob, Alice, Msgs), 231: timer:sleep(timer:seconds(1)), 232: Msgs. 233: 234: send_msgs(From, To, Msgs) -> 235: [escalus:send(From, escalus_stanza:chat_to(To, Msg)) || 236: Msg <- Msgs]. 237: 238: 239: gen_msgs(Prefix, N) -> 240: [<<Prefix/binary, (integer_to_binary(I))/binary>> || I <- lists:seq(1, N)]. 241: 242: given_client_is_inactive(Alice) -> 243: escalus:send(Alice, csi_stanza(<<"inactive">>)). 244: 245: csi_stanza(Name) -> 246: #xmlel{name = Name, 247: attrs = [{<<"xmlns">>, <<"urn:xmpp:csi:0">>}]}.