1: %%%-------------------------------------------------------------------
    2: %%% @author bartek
    3: %%% @copyright (C) 2017, <COMPANY>
    4: %%% @doc
    5: %%%
    6: %%% @end
    7: %%% Created : 21. Apr 2017 16:09
    8: %%%-------------------------------------------------------------------
    9: -module(roster_SUITE).
   10: -author("bartek").
   11: 
   12: -include_lib("eunit/include/eunit.hrl").
   13: -include("ejabberd_c2s.hrl").
   14: -include("mongoose.hrl").
   15: -include_lib("exml/include/exml_stream.hrl").
   16: -include_lib("mod_roster.hrl").
   17: -compile([export_all, nowarn_export_all]).
   18: 
   19: -define(_eq(E, I), ?_assertEqual(E, I)).
   20: -define(eq(E, I), ?assertEqual(E, I)).
   21: -define(am(E, I), ?assertMatch(E, I)).
   22: -define(ne(E, I), ?assert(E =/= I)).
   23: 
   24: -define(ACC_PARAMS, #{location => ?LOCATION,
   25:                       lserver => domain(),
   26:                       host_type => host_type(),
   27:                       element => undefined}).
   28: 
   29: -define(HOST_TYPE, <<"test type">>).
   30: 
   31: all() -> [
   32:     roster_old,
   33:     roster_old_with_filter,
   34:     roster_new,
   35:     roster_case_insensitive
   36: ].
   37: 
   38: init_per_suite(C) ->
   39:     ok = mnesia:create_schema([node()]),
   40:     ok = mnesia:start(),
   41:     {ok, _} = application:ensure_all_started(jid),
   42:     {ok, _} = application:ensure_all_started(exometer_core),
   43:     meck:new(gen_iq_handler, [no_link]),
   44:     meck:expect(gen_iq_handler, add_iq_handler_for_domain, fun(_, _, _, _, _, _) -> ok end),
   45:     meck:expect(gen_iq_handler, remove_iq_handler_for_domain, fun(_, _, _) -> ok end),
   46:     meck:new(mongoose_domain_api, [no_link]),
   47:     meck:expect(mongoose_domain_api, get_domain_host_type, fun(_) -> {ok, host_type()} end),
   48:     [mongoose_config:set_opt(Key, Value) || {Key, Value} <- opts()],
   49:     C.
   50: 
   51: end_per_suite(C) ->
   52:     [mongoose_config:unset_opt(Key) || {Key, _Value} <- opts()],
   53:     meck:unload(),
   54:     mnesia:stop(),
   55:     mnesia:delete_schema([node()]),
   56:     C.
   57: 
   58: init_per_testcase(_TC, C) ->
   59:     init_ets(),
   60:     gen_hook:start_link(),
   61:     mongoose_modules:start(),
   62:     C.
   63: 
   64: end_per_testcase(_TC, C) ->
   65:     Acc = mongoose_acc:new(?ACC_PARAMS),
   66:     mod_roster:remove_user(Acc, a(), domain()),
   67:     mongoose_modules:stop(),
   68:     delete_ets(),
   69:     C.
   70: 
   71: opts() ->
   72:     [{hosts, [host_type()]},
   73:      {host_types, []},
   74:      {all_metrics_are_global, false},
   75:      {{modules, host_type()}, #{mod_roster => config_parser_helper:default_mod_config(mod_roster)}}].
   76: 
   77: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   78: %%%%%%%%%%%%%%%%%%%%%%%%%%% TESTS %%%%%%%%%%%%%%%%%%%%%%%
   79: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   80: 
   81: 
   82: roster_old(_C) ->
   83:     R1 = get_roster_old(),
   84:     ?assertEqual(length(R1), 0),
   85:     ok = mod_roster:set_items(host_type(), alice_jid(), addbob_stanza()),
   86:     assert_state_old(none, none),
   87:     subscription(out, subscribe),
   88:     assert_state_old(none, out),
   89:     ok.
   90: 
   91: roster_old_with_filter(_C) ->
   92:     R1 = get_roster_old(),
   93:     ?assertEqual(0, length(R1)),
   94:     ok = mod_roster:set_items(host_type(), alice_jid(), addbob_stanza()),
   95:     assert_state_old(none, none),
   96:     subscription(in, subscribe),
   97:     R2 = get_roster_old(),
   98:     ?assertEqual(0, length(R2)),
   99:     R3 = get_full_roster(),
  100:     ?assertEqual(1, length(R3)),
  101:     ok.
  102: 
  103: roster_new(_C) ->
  104:     R1 = mod_roster:get_roster_entry(host_type(), alice_jid(), bob_ljid(), short),
  105:     ?assertEqual(does_not_exist, R1),
  106:     ok = mod_roster:set_items(host_type(), alice_jid(), addbob_stanza()),
  107:     assert_state_old(none, none),
  108:     ct:pal("get_roster_old(): ~p", [get_roster_old()]),
  109:     R2 = mod_roster:get_roster_entry(host_type(), alice_jid(), bob_ljid(), short),
  110:     ?assertMatch(#roster{}, R2), % is not guaranteed to contain full info
  111:     R3 = mod_roster:get_roster_entry(host_type(), alice_jid(), bob_ljid(), full),
  112:     assert_state(R3, none, none, [<<"friends">>]),
  113:     subscription(out, subscribe),
  114:     R4 = mod_roster:get_roster_entry(host_type(), alice_jid(), bob_ljid(), full),
  115:     assert_state(R4, none, out, [<<"friends">>]).
  116: 
  117: 
  118: roster_case_insensitive(_C) ->
  119:     ok = mod_roster:set_items(host_type(), alice_jid(), addbob_stanza()),
  120:     R1 = get_roster_old(),
  121:     ?assertEqual(1, length(R1)),
  122:     R2 = get_roster_old(ae()),
  123:     ?assertEqual(1, length(R2)),
  124:     R3 = mod_roster:get_roster_entry(host_type(), alice_jid(), bob_ljid(), full),
  125:     assert_state(R3, none, none, [<<"friends">>]),
  126:     R3 = mod_roster:get_roster_entry(host_type(), alicE_jid(), bob_ljid(), full),
  127:     assert_state(R3, none, none, [<<"friends">>]),
  128:     ok.
  129: 
  130: 
  131: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  132: %%%%%%%%%%%%%%%%%%%%%%%%%% HELPERS %%%%%%%%%%%%%%%%%%%%%%
  133: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  134: 
  135: assert_state(Rentry, Subscription, Ask, Groups) ->
  136:     ?assertEqual(Subscription, Rentry#roster.subscription),
  137:     ?assertEqual(Ask, Rentry#roster.ask),
  138:     ?assertEqual(Groups, Rentry#roster.groups).
  139: 
  140: subscription(Direction, Type) ->
  141:     TFun = fun() ->
  142:                    mod_roster:process_subscription_t(host_type(), Direction, alice_jid(),
  143:                                                      bob_jid(), Type, <<>>)
  144:            end,
  145:     {atomic, _} = mod_roster:transaction(host_type(), TFun).
  146: 
  147: get_roster_old() ->
  148:     get_roster_old(a()).
  149: 
  150: get_roster_old(User) ->
  151:     Acc = mongoose_acc:new(?ACC_PARAMS),
  152:     Acc1 = mod_roster:get_user_roster(Acc, jid:make(User, domain(), <<>>)),
  153:     mongoose_acc:get(roster, items, Acc1).
  154: 
  155: get_full_roster() ->
  156:     Acc0 = mongoose_acc:new(?ACC_PARAMS),
  157:     Acc1 = mongoose_acc:set(roster, show_full_roster, true, Acc0),
  158:     Acc2 = mod_roster:get_user_roster(Acc1, alice_jid()),
  159:     mongoose_acc:get(roster, items, Acc2).
  160: 
  161: assert_state_old(Subscription, Ask) ->
  162:     [Rentry] = get_roster_old(),
  163:     ?assertEqual(Subscription, Rentry#roster.subscription),
  164:     ?assertEqual(Ask, Rentry#roster.ask).
  165: 
  166: init_ets() ->
  167:     catch ets:new(mongoose_services, [named_table]),
  168:     ok.
  169: 
  170: delete_ets() ->
  171:     catch ets:delete(mongoose_services),
  172:     ok.
  173: 
  174: alice_jid() ->
  175:     jid:make(a(), domain(), <<>>).
  176: 
  177: alicE_jid() ->
  178:     jid:make(ae(), domain(), <<>>).
  179: 
  180: a() -> <<"alice">>.
  181: ae() -> <<"alicE">>.
  182: 
  183: domain() -> <<"localhost">>.
  184: 
  185: bob() -> <<"bob@localhost">>.
  186: 
  187: bob_jid() ->
  188:     jid:make(<<"bob">>, domain(), <<>>).
  189: 
  190: bob_ljid() ->
  191:     jid:to_lower(bob_jid()).
  192: 
  193: host_type() -> <<"test type">>.
  194: 
  195: addbob_stanza() ->
  196:     #xmlel{children = [
  197:         #xmlel{
  198:             attrs = [{<<"jid">>, bob()}],
  199:             children = [
  200:                 #xmlel{name = <<"group">>,
  201:                     children = [
  202:                         #xmlcdata{content = <<"friends">>}
  203:                     ]}
  204:             ]}
  205:         ]
  206:     }.