1: -module(mongoose_cleanup_SUITE).
    2: 
    3: -include_lib("eunit/include/eunit.hrl").
    4: -include("mongoose.hrl").
    5: 
    6: -export([all/0,
    7:          init_per_suite/1, end_per_suite/1,
    8:          init_per_testcase/2, end_per_testcase/2]).
    9: -export([cleaner_runs_hook_on_nodedown/1, notify_self_hook/3]).
   10: -export([auth_anonymous/1,
   11:          last/1,
   12:          stream_management/1,
   13:          local/1,
   14:          s2s/1,
   15:          bosh/1
   16:         ]).
   17: 
   18: -define(HOST, <<"localhost">>).
   19: -define(NS_CC_2, <<"urn:xmpp:carbons:2">>).
   20: 
   21: %% -----------------------------------------------------
   22: %% CT callbacks
   23: %% -----------------------------------------------------
   24: 
   25: all() ->
   26:     [
   27:      cleaner_runs_hook_on_nodedown,
   28:      auth_anonymous,
   29:      last,
   30:      stream_management,
   31:      local,
   32:      s2s,
   33:      bosh
   34:     ].
   35: 
   36: init_per_suite(Config) ->
   37:     {ok, _} = application:ensure_all_started(jid),
   38:     ok = mnesia:create_schema([node()]),
   39:     ok = mnesia:start(),
   40:     [mongoose_config:set_opt(Key, Value) || {Key, Value} <- opts()],
   41:     mongoose_domain_api:init(),
   42:     Config.
   43: 
   44: end_per_suite(Config) ->
   45:     mongoose_domain_api:stop(),
   46:     [mongoose_config:unset_opt(Key) || {Key, _Value} <- opts()],
   47:     mnesia:stop(),
   48:     mnesia:delete_schema([node()]),
   49:     Config.
   50: 
   51: opts() ->
   52:     [{hosts, [?HOST]},
   53:      {host_types, []},
   54:      {all_metrics_are_global, false}].
   55: 
   56: init_per_testcase(T, Config) ->
   57:     {ok, _HooksServer} = gen_hook:start_link(),
   58:     setup_meck(meck_mods(T)),
   59:     Config.
   60: 
   61: end_per_testcase(T, Config) ->
   62:     unload_meck(meck_mods(T)),
   63:     Config.
   64: 
   65: meck_mods(bosh) -> [exometer, mod_bosh_socket];
   66: meck_mods(s2s) -> [exometer, ejabberd_commands, mongoose_bin];
   67: meck_mods(local) -> [exometer];
   68: meck_mods(_) -> [exometer, ejabberd_sm, ejabberd_local].
   69: 
   70: %% -----------------------------------------------------
   71: %% Tests
   72: %% -----------------------------------------------------
   73: 
   74: cleaner_runs_hook_on_nodedown(_Config) ->
   75:     meck:expect(gen_hook, error_running_hook, fun(_, _, _, _, _) -> ok end),
   76:     {ok, Cleaner} = mongoose_cleaner:start_link(),
   77:     gen_hook:add_handler(node_cleanup, global,
   78:                          fun ?MODULE:notify_self_hook/3,
   79:                          #{self => self()}, 50),
   80: 
   81:     FakeNode = fakename@fakehost,
   82:     Cleaner ! {nodedown, FakeNode},
   83: 
   84:     receive
   85:         {got_nodedown, FakeNode} -> ok
   86:     after timer:seconds(1) ->
   87:         ct:fail({timeout, got_nodedown})
   88:     end,
   89:     ?assertEqual(false, meck:called(gen_hook, error_running_hook,
   90:                                     ['_', '_', '_', '_', '_'])).
   91: 
   92: notify_self_hook(Acc, #{node := Node}, #{self := Self}) ->
   93:     Self ! {got_nodedown, Node},
   94:     {ok, Acc}.
   95: 
   96: auth_anonymous(_Config) ->
   97:     HostType = host_type(),
   98:     {U, S, R, JID, SID} = get_fake_session(),
   99:     ejabberd_auth_anonymous:start(HostType),
  100:     Info = #{auth_module => cyrsasl_anonymous},
  101:     ejabberd_auth_anonymous:register_connection(#{}, HostType, SID, JID, Info),
  102:     true = ejabberd_auth_anonymous:does_user_exist(HostType, U, S),
  103:     mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID),
  104:     false = ejabberd_auth_anonymous:does_user_exist(HostType, U, S).
  105: 
  106: last(_Config) ->
  107:     HostType = host_type(),
  108:     {U, S, R, _JID, SID} = get_fake_session(),
  109:     mod_last:start(HostType, config_parser_helper:mod_config(mod_last, #{iqdisc => no_queue})),
  110:     not_found = mod_last:get_last_info(HostType, U, S),
  111:     Status1 = <<"status1">>,
  112:     #{} = mod_last:on_presence_update(new_acc(S), U, S, R, Status1),
  113:     {ok, TS1, Status1} = mod_last:get_last_info(HostType, U, S),
  114:     async_helper:wait_until(
  115:       fun() ->
  116:               mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID),
  117:               {ok, TS2, <<>>} = mod_last:get_last_info(HostType, U, S),
  118:               TS2 - TS1 > 0
  119:       end,
  120:       true).
  121: 
  122: stream_management(_Config) ->
  123:     HostType = host_type(),
  124:     {U, S, R, _JID, SID} = get_fake_session(),
  125:     mod_stream_management:start(HostType, config_parser_helper:default_mod_config(mod_stream_management)),
  126:     SMID = <<"123">>,
  127:     mod_stream_management:register_smid(HostType, SMID, SID),
  128:     {sid, SID} = mod_stream_management:get_sid(HostType, SMID),
  129:     mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID),
  130:     {error, smid_not_found} = mod_stream_management:get_sid(HostType, SMID).
  131: 
  132: local(_Config) ->
  133:     ejabberd_local:start_link(),
  134:     Self = self(),
  135:     SelfNotify = fun(_, _, _, Arg) -> Self ! Arg end,
  136:     ID = <<"abc123">>,
  137: 
  138:     ejabberd_local:register_iq_response_handler(?HOST, ID, undefined, SelfNotify, 50),
  139:     receive
  140:         timeout -> ok
  141:     after
  142:         2000 -> ct:fail({timeout, valid_iq_timeout})
  143:     end,
  144: 
  145:     ejabberd_local:register_iq_response_handler(?HOST, ID, undefined, SelfNotify, 2000),
  146:     {ok, undefined, _F} = ejabberd_local:get_iq_callback(ID),
  147:     mongoose_hooks:node_cleanup(node()),
  148:     error = ejabberd_local:get_iq_callback(ID).
  149: 
  150: s2s(_Config) ->
  151:     ejabberd_s2s:start_link(),
  152:     FromTo = {?HOST, <<"foreign">>},
  153:     ejabberd_s2s:try_register(FromTo),
  154:     Self = self(),
  155:     [Self] = ejabberd_s2s:get_connections_pids(FromTo),
  156:     mongoose_hooks:node_cleanup(node()),
  157:     [] = ejabberd_s2s:get_connections_pids(FromTo).
  158: 
  159: bosh(_Config) ->
  160:     mod_bosh:start(?HOST, config_parser_helper:default_mod_config(mod_bosh)),
  161:     SID = <<"sid">>,
  162:     Self = self(),
  163:     {error, _} = mod_bosh:get_session_socket(SID),
  164:     mod_bosh:store_session(SID, Self),
  165:     {ok, Self} = mod_bosh:get_session_socket(SID),
  166:     mongoose_hooks:node_cleanup(node()),
  167:     {error, _} = mod_bosh:get_session_socket(SID),
  168:     ok.
  169: 
  170: %% -----------------------------------------------------
  171: %% Internal
  172: %% -----------------------------------------------------
  173: 
  174: setup_meck([exometer | R]) ->
  175:     meck:new(exometer),
  176:     meck:expect(exometer, info, fun(_, _) -> undefined end),
  177:     meck:expect(exometer, new, fun(_, _) -> ok end),
  178:     meck:expect(exometer, update, fun(_, _) -> ok end),
  179:     setup_meck(R);
  180: setup_meck([ejabberd_sm | R]) ->
  181:     meck:new(ejabberd_sm),
  182:     meck:expect(ejabberd_sm, register_iq_handler,
  183:                 fun(_A1, _A2, _A3) -> ok end),
  184:     setup_meck(R);
  185: setup_meck([ejabberd_local | R]) ->
  186:     meck:new(ejabberd_local),
  187:     meck:expect(ejabberd_local, register_iq_handler,
  188:                 fun(_A1, _A2, _A3) -> ok end),
  189:     setup_meck(R);
  190: setup_meck([ejabberd_commands | R]) ->
  191:     meck:new(ejabberd_commands),
  192:     meck:expect(ejabberd_commands, register_commands, fun(_) -> ok end),
  193:     setup_meck(R);
  194: setup_meck([mongoose_bin | R]) ->
  195:     meck:new(mongoose_bin, [passthrough]),
  196:     meck:expect(mongoose_bin, gen_from_crypto, fun() -> <<"123456">> end),
  197:     setup_meck(R);
  198: setup_meck([mod_bosh_socket | R]) ->
  199:     meck:new(mod_bosh_socket, [passthrough]),
  200:     meck:expect(mod_bosh_socket, start_supervisor, fun() -> {ok, self()} end),
  201:     setup_meck(R);
  202: setup_meck([]) ->
  203:     ok.
  204: 
  205: unload_meck(Mods) ->
  206:     [ {meck:validate(Mod), meck:unload(Mod)} ||
  207:       Mod <- Mods ].
  208: 
  209: -spec get_fake_session() ->
  210:     {U :: binary(), S :: binary(), R :: binary(),
  211:      JID :: jid:jid(), SID :: ejabberd_sm:sid()}.
  212: get_fake_session() ->
  213:     U = <<"someuser">>,
  214:     S = ?HOST,
  215:     R = <<"someresource">>,
  216:     JID = jid:make(U, S, R),
  217:     SID = {os:timestamp(), self()},
  218:     {U, S, R, JID, SID}.
  219: 
  220: new_acc(Server) ->
  221:     mongoose_acc:new(#{location => ?LOCATION,
  222:                        lserver => Server,
  223:                        host_type => host_type(),
  224:                        element => undefined}).
  225: 
  226: host_type() ->
  227:     <<"test host type">>.