1: %%%---------------------------------------------------------------------- 2: %%% File : mod_event_pusher_http_SUITE 3: %%% Author : Baibossynv Valery <baibossynov.valery@gmail.com> 4: %%% Purpose : Testing passing via http 5: %%% Created : 16 Dec 2015 by Baibossynv Valery <baibossynov.valery@gmail.com> 6: %%%---------------------------------------------------------------------- 7: 8: -module(mod_event_pusher_http_SUITE). 9: -author("baibossynov.valery@gmail.com"). 10: 11: -compile([export_all, nowarn_export_all]). 12: 13: -include_lib("eunit/include/eunit.hrl"). 14: 15: -define(ETS_TABLE, mod_event_pusher_http). 16: 17: -import(distributed_helper, [mim/0, 18: require_rpc_nodes/1, 19: rpc/4]). 20: 21: -import(push_helper, [http_notifications_port/0, http_notifications_host/0]). 22: 23: -import(domain_helper, [host_type/0]). 24: 25: -import(config_parser_helper, [config/2, mod_config_with_auto_backend/1, mod_event_pusher_http_handler/0]). 26: 27: %%%=================================================================== 28: %%% Suite configuration 29: %%%=================================================================== 30: 31: suite() -> 32: require_rpc_nodes([mim]) ++ escalus:suite(). 33: 34: all() -> 35: [ 36: {group, no_prefix}, 37: {group, with_prefix} 38: ]. 39: 40: all_tests() -> 41: [ 42: simple_message, 43: simple_message_no_listener, 44: simple_message_failing_listener, 45: proper_http_message_encode_decode 46: ]. 47: 48: groups() -> 49: G = [{no_prefix, [sequence], all_tests()}, 50: {with_prefix, [sequence], all_tests()}], 51: ct_helper:repeat_all_until_all_ok(G). 52: 53: init_per_suite(Config0) -> 54: escalus:init_per_suite(Config0). 55: 56: end_per_suite(Config) -> 57: escalus_fresh:clean(), 58: escalus:end_per_suite(Config). 59: 60: init_per_group(no_prefix, Config) -> 61: set_modules(Config, #{}); 62: init_per_group(with_prefix, Config) -> 63: set_modules(Config, #{path => <<"prefix">>}). 64: 65: end_per_group(_GroupName, Config) -> 66: dynamic_modules:restore_modules(Config), 67: ok. 68: 69: init_per_testcase(CaseName, Config) -> 70: create_events_collection(), 71: start_http_listener(CaseName, get_prefix(Config)), 72: start_pool(), 73: escalus:init_per_testcase(CaseName, Config). 74: 75: end_per_testcase(CaseName, Config) -> 76: stop_pool(), 77: stop_http_listener(CaseName), 78: clear_events_collection(), 79: escalus:end_per_testcase(CaseName, Config). 80: 81: %%%=================================================================== 82: %%% offline tests 83: %%%=================================================================== 84: proper_http_message_encode_decode(Config) -> 85: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], 86: fun(Alice, Bob) -> 87: Sender = jid:nameprep(escalus_client:username(Alice)), 88: Receiver = jid:nameprep(escalus_client:username(Bob)), 89: Server = jid:nodeprep(escalus_users:get_host(Config, alice)), 90: Message = <<"Hi Test!&escape=Hello">>, 91: 92: Stanza = escalus_stanza:chat_to(Bob, Message), 93: escalus:send(Alice, Stanza), 94: escalus:wait_for_stanza(Bob), 95: 96: Body = get_http_request(), 97: 98: ExtractedAndDecoded = rpc(mim(), cow_qs, parse_qs, [Body]), 99: ExpectedList = [{<<"author">>,<<Sender/binary>>}, 100: {<<"server">>,<<Server/binary>>}, 101: {<<"receiver">>,<<Receiver/binary>>}, 102: {<<"message">>,<<Message/binary>>}], 103: SortedExtractedAndDecoded = lists:sort(ExtractedAndDecoded), 104: SortedExpectedList = lists:sort(ExpectedList), 105: ?assertEqual(SortedExpectedList, SortedExtractedAndDecoded) 106: end). 107: 108: 109: simple_message(Config) -> 110: %% we expect one notification message 111: do_simple_message(Config, <<"Hi, Simple!">>), 112: %% fail if we didn't receive http notification 113: Body = get_http_request(), 114: {_, _} = binary:match(Body, <<"alice">>), 115: {_, _} = binary:match(Body, <<"Simple">>). 116: 117: simple_message_no_listener(Config) -> 118: do_simple_message(Config, <<"Hi, NoListener!">>). 119: 120: simple_message_failing_listener(Config) -> 121: do_simple_message(Config, <<"Hi, Failing!">>). 122: 123: do_simple_message(Config0, Msg) -> 124: Config = escalus_fresh:create_users(Config0, [{alice, 1}, {bob, 1}]), 125: %% Alice sends a message to Bob, who is offline 126: {ok, Alice} = escalus_client:start(Config, alice, <<"res1">>), 127: escalus:send(Alice, escalus_stanza:presence(<<"available">>)), 128: BobJid = escalus_users:get_jid(Config, bob), 129: Stanza = escalus_stanza:chat_to(BobJid, Msg), 130: escalus:send(Alice, Stanza), 131: escalus_client:stop(Config, Alice), 132: %% Bob logs in 133: {ok, Bob} = escalus_client:start(Config, bob, <<"res1">>), 134: escalus:send(Bob, escalus_stanza:presence(<<"available">>)), 135: %% He receives his initial presence and the message 136: Stanzas = escalus:wait_for_stanzas(Bob, 2), 137: escalus_new_assert:mix_match([is_presence, is_chat(Msg)], Stanzas), 138: escalus_client:stop(Config, Bob). 139: 140: %%%=================================================================== 141: %%% Helpers 142: %%%=================================================================== 143: 144: get_http_request() -> 145: Key = got_http_request, 146: mongoose_helper:wait_until( 147: fun() -> 1 =:= length(ets:lookup(?ETS_TABLE, Key)) end, 148: true, #{name => missing_request}), 149: [Bins] = lists:map(fun({_, El}) -> El end, ets:lookup(?ETS_TABLE, Key)), 150: ets:delete(?ETS_TABLE, Key), 151: Bins. 152: 153: login_send_presence(Config, User) -> 154: Spec = escalus_users:get_userspec(Config, User), 155: {ok, Client} = escalus_client:start(Config, Spec, <<"dummy">>), 156: escalus:send(Client, escalus_stanza:presence(<<"available">>)), 157: Client. 158: 159: is_chat(Content) -> 160: fun(Stanza) -> escalus_pred:is_chat_message(Content, Stanza) end. 161: 162: get_prefix(no_prefix) -> 163: "/"; 164: get_prefix(with_prefix) -> 165: "/prefix"; 166: get_prefix(Config) -> 167: GroupName = proplists:get_value(name, proplists:get_value(tc_group_properties, Config)), 168: get_prefix(GroupName). 169: 170: start_pool() -> 171: PoolOpts = #{strategy => available_worker, workers => 5}, 172: ConnOpts = #{host => http_notifications_host(), request_timeout => 2000}, 173: Pool = config([outgoing_pools, http, http_pool], #{opts => PoolOpts, conn_opts => ConnOpts}), 174: [{ok, _Pid}] = rpc(mim(), mongoose_wpool, start_configured_pools, [[Pool]]). 175: 176: stop_pool() -> 177: rpc(mim(), mongoose_wpool, stop, [http, global, http_pool]). 178: 179: set_modules(Config0, ExtraHandlerOpts) -> 180: Config = dynamic_modules:save_modules(host_type(), Config0), 181: ModOffline = create_offline_config(), 182: Handler = maps:merge(mod_event_pusher_http_handler(), ExtraHandlerOpts), 183: ModOpts = #{http => #{handlers => [Handler]}}, 184: dynamic_modules:ensure_modules(host_type(), [{mod_event_pusher, ModOpts} | ModOffline]), 185: Config. 186: 187: -spec create_offline_config() -> [{mod_offline, gen_mod:module_opts()}]. 188: create_offline_config() -> 189: [{mod_offline, mod_config_with_auto_backend(mod_offline)}]. 190: 191: start_http_listener(simple_message, Prefix) -> 192: http_helper:start(http_notifications_port(), Prefix, fun process_notification/1); 193: start_http_listener(simple_message_no_listener, _) -> 194: ok; 195: start_http_listener(simple_message_failing_listener, Prefix) -> 196: http_helper:start(http_notifications_port(), Prefix, fun(Req) -> Req end); 197: start_http_listener(proper_http_message_encode_decode, Prefix) -> 198: http_helper:start(http_notifications_port(), Prefix, fun process_notification/1). 199: 200: stop_http_listener(simple_message_no_listener) -> 201: ok; 202: stop_http_listener(_) -> 203: http_helper:stop(). 204: 205: process_notification(Req) -> 206: {ok, Body, Req1} = cowboy_req:read_body(Req), 207: Req2 = cowboy_req:reply(200, #{<<"content-type">> => <<"text/plain">>}, <<"OK">>, Req1), 208: Event = {got_http_request, Body}, 209: ets:insert(?ETS_TABLE, Event), 210: Req2. 211: 212: create_events_collection() -> 213: ets:new(?ETS_TABLE, [duplicate_bag, named_table, public]). 214: 215: clear_events_collection() -> 216: ets:delete_all_objects(?ETS_TABLE).