1: %%==============================================================================
    2: %% Copyright 2010 Erlang Solutions Ltd.
    3: %%
    4: %% Licensed under the Apache License, Version 2.0 (the "License");
    5: %% you may not use this file except in compliance with the License.
    6: %% You may obtain a copy of the License at
    7: %%
    8: %% http://www.apache.org/licenses/LICENSE-2.0
    9: %%
   10: %% Unless required by applicable law or agreed to in writing, software
   11: %% distributed under the License is distributed on an "AS IS" BASIS,
   12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13: %% See the License for the specific language governing permissions and
   14: %% limitations under the License.
   15: %%==============================================================================
   16: 
   17: -module(acc_e2e_SUITE).
   18: -compile([export_all, nowarn_export_all]).
   19: 
   20: -include_lib("exml/include/exml.hrl").
   21: -include_lib("escalus/include/escalus.hrl").
   22: -include_lib("common_test/include/ct.hrl").
   23: -include_lib("eunit/include/eunit.hrl").
   24: -define(NS_BLOCKING,     <<"urn:xmpp:blocking">>).
   25: 
   26: -define(SLEEP_TIME, 50).
   27: 
   28: -import(distributed_helper, [mim/0,
   29:                              require_rpc_nodes/1,
   30:                              rpc/4]).
   31: 
   32: %%--------------------------------------------------------------------
   33: %% Suite configuration
   34: %%--------------------------------------------------------------------
   35: 
   36: all() ->
   37:     [
   38:         {group, message},
   39:         {group, cache_and_strip}
   40:     ].
   41: 
   42: groups() ->
   43:     G = [
   44:          {message, [], message_test_cases()},
   45:          {cache_and_strip, [], cache_test_cases()}
   46:         ],
   47:     ct_helper:repeat_all_until_all_ok(G).
   48: 
   49: message_test_cases() ->
   50:     [
   51:         one_message,
   52:         message_altered_by_filter_local_packet_hook
   53:     ].
   54: 
   55: cache_test_cases() ->
   56:     [ filter_local_packet_uses_recipient_values ].
   57: 
   58: suite() ->
   59:     require_rpc_nodes([mim]) ++ escalus:suite().
   60: 
   61: %%--------------------------------------------------------------------
   62: %% Init & teardown
   63: %%--------------------------------------------------------------------
   64: 
   65: init_per_suite(Config) ->
   66:     {Mod, Code} = rpc(mim(), dynamic_compile, from_string, [acc_test_helper_code(Config)]),
   67:     rpc(mim(), code, load_binary, [Mod, "acc_test_helper.erl", Code]),
   68:     recreate_table(),
   69:     escalus:init_per_suite(Config).
   70: 
   71: end_per_suite(Config) ->
   72:     escalus_fresh:clean(),
   73:     escalus:end_per_suite(Config).
   74: 
   75: init_per_group(message, Config) ->
   76:     % saves ref, timestamp and some attrs of acc in ets
   77:     add_handler(user_send_packet, test_save_acc, 5),
   78:     % checks it is the same acc
   79:     add_handler(filter_local_packet, test_check_acc, 50),
   80:     % checks it is the same acc and it has been stripped but keeps persistent props
   81:     add_handler(user_receive_packet, test_check_final_acc, 50),
   82:     Config;
   83: init_per_group(cache_and_strip, Config) ->
   84:     add_handler(user_send_packet, save_my_jid, 5),
   85:     add_handler(filter_local_packet, drop_if_jid_not_mine, 1),
   86:     Config;
   87: init_per_group(_GroupName, Config) ->
   88:     Config.
   89: 
   90: end_per_group(message, _Config) ->
   91:     remove_handler(user_send_packet, test_save_acc, 5),
   92:     remove_handler(filter_local_packet, test_check_acc, 50),
   93:     remove_handler(user_receive_packet, test_check_final_acc, 50),
   94:     ok;
   95: end_per_group(cache_and_strip, _Config) ->
   96:     remove_handler(user_send_packet, save_my_jid, 5),
   97:     remove_handler(filter_local_packet, drop_if_jid_not_mine, 1),
   98:     ok;
   99: end_per_group(_GroupName, _Config) ->
  100:     ok.
  101: 
  102: init_per_testcase(message_altered_by_filter_local_packet_hook = CN, Config) ->
  103:     add_handler(filter_local_packet, alter_message, 60),
  104:     escalus:init_per_testcase(CN, Config);
  105: init_per_testcase(CaseName, Config) ->
  106:     escalus:init_per_testcase(CaseName, Config).
  107: 
  108: end_per_testcase(message_altered_by_filter_local_packet_hook = CN, Config) ->
  109:     remove_handler(filter_local_packet, alter_message, 60),
  110:     escalus:end_per_testcase(CN, Config);
  111: end_per_testcase(CaseName, Config) ->
  112:     escalus:end_per_testcase(CaseName, Config).
  113: 
  114: %%--------------------------------------------------------------------
  115: %% Tests
  116: %%--------------------------------------------------------------------
  117: 
  118: one_message(Config) ->
  119:     escalus:fresh_story(
  120:         Config, [{alice, 1}, {bob, 1}],
  121:         fun(Alice, Bob) ->
  122:             M = escalus_stanza:chat_to(Bob, <<"hej">>),
  123:             escalus:send(Alice, M),
  124:             R = escalus_client:wait_for_stanza(Bob),
  125:             % hook handlers break something if test does not pass so it should fail somewhere here
  126:             escalus:assert(is_chat_message, [<<"hej">>], R),
  127:             ok
  128:         end).
  129: 
  130: message_altered_by_filter_local_packet_hook(Config) ->
  131:     % this test uses additional hook which changes body of a message on filter_local_packet hook
  132:     % later processing, including stripping accumulator and replacing element, must use
  133:     % correct values
  134:     escalus:fresh_story(
  135:         Config, [{alice, 1}, {bob, 1}],
  136:         fun(Alice, Bob) ->
  137:             M = escalus_stanza:chat_to(escalus_client:short_jid(Bob), <<"hi">>),
  138:             escalus:send(Alice, M),
  139:             R = escalus_client:wait_for_stanza(Bob),
  140:             % filter_local_packet alters packet to be delivered
  141:             % and mongoose_acc:strip must respect it
  142:             escalus:assert(is_chat_message, [<<"bye">>], R),
  143:             ok
  144:         end).
  145: 
  146: 
  147: filter_local_packet_uses_recipient_values(Config) ->
  148:     % this test is to make sure that when a message (or rather accumulator) reaches
  149:     % filter_local_packet stage it's been already stripped of sender-related caches
  150:     % preprocessing hook stores sender jid, filter_local_packet drops a message if there
  151:     % a sender_jid cached in acc
  152:     escalus:fresh_story(
  153:         Config, [{alice, 1}, {bob, 1}],
  154:         fun(Alice, Bob) ->
  155:             M = escalus_stanza:chat_to(escalus_client:short_jid(Bob), <<"hi">>),
  156:             escalus:send(Alice, M),
  157:             escalus_client:wait_for_stanza(Bob),
  158:             ok
  159:         end).
  160: 
  161: %%--------------------------------------------------------------------
  162: %% Helpers
  163: %%--------------------------------------------------------------------
  164: 
  165: 
  166: acc_test_helper_code(Config) ->
  167:     Dir = proplists:get_value(mim_data_dir, Config),
  168:     F = filename:join(Dir, "acc_test_helper.erl"),
  169:     {ok, Code} = file:read_file(F),
  170:     binary_to_list(Code).
  171: 
  172: add_handler(Hook, F, Seq) ->
  173:     rpc(mim(), gen_hook, add_handler, handler(Hook, F, Seq)).
  174: 
  175: remove_handler(Hook, F, Seq) ->
  176:     rpc(mim(), gen_hook, delete_handler, handler(Hook, F, Seq)).
  177: 
  178: handler(Hook, F, Seq) ->
  179:     [Hook, domain_helper:host_type(mim), fun acc_test_helper:F/3, #{}, Seq].
  180: 
  181: %% creates a temporary ets table keeping refs and some attrs of accumulators created in c2s
  182: recreate_table() ->
  183:     rpc(mim(), acc_test_helper, recreate_table, []).