1: -module(mongoose_cleanup_SUITE). 2: 3: -include_lib("eunit/include/eunit.hrl"). 4: -include_lib("common_test/include/ct.hrl"). 5: -include("mongoose.hrl"). 6: 7: -compile([export_all, nowarn_export_all]). 8: 9: -define(HOST, <<"localhost">>). 10: 11: %% ----------------------------------------------------- 12: %% CT callbacks 13: %% ----------------------------------------------------- 14: 15: all() -> 16: [ 17: cleaner_runs_hook_on_nodedown, 18: cleaner_runs_hook_on_nodedown_for_host_type, 19: auth_anonymous, 20: last, 21: {group, cets}, 22: {group, mnesia} 23: ]. 24: 25: groups() -> 26: [{cets, [], backend_tests()}, 27: {mnesia, [], backend_tests()}, 28: {component, [], component_cases()}, 29: {muc, [], muc_cases()}]. 30: 31: backend_tests() -> 32: [{group, component}, {group, muc}, bosh, stream_management, s2s]. 33: 34: component_cases() -> 35: [component, component_from_other_node_remains]. 36: 37: muc_cases() -> 38: [muc_node_cleanup_for_host_type, muc_room, muc_room_from_other_node_remains]. 39: 40: init_per_suite(Config) -> 41: {ok, _} = application:ensure_all_started(jid), 42: ok = mnesia:create_schema([node()]), 43: ok = mnesia:start(), 44: mongoose_config:set_opts(opts()), 45: lists:foreach(fun setup_meck/1, meck_mods()), 46: async_helper:start(Config, [{mim_ct_sup, start_link, [ejabberd_sup]}, 47: {mongooseim_helper, start_link_loaded_hooks, []}, 48: {mongoose_domain_sup, start_link, []}]). 49: 50: end_per_suite(Config) -> 51: async_helper:stop_all(Config), 52: lists:foreach(fun unload_meck/1, meck_mods()), 53: mongoose_config:erase_opts(), 54: mnesia:stop(), 55: mnesia:delete_schema([node()]). 56: 57: init_per_group(cets, Config) -> 58: [{backend, cets} | start_cets_disco(Config)]; 59: init_per_group(mnesia, Config) -> 60: [{backend, mnesia} | Config]; 61: init_per_group(component, Config) -> 62: mongoose_config:set_opt(component_backend, ?config(backend, Config)), 63: [{needs_component, true} | Config]; 64: init_per_group(Group, Config) -> 65: start_modules(Group, Config), 66: Config. 67: 68: end_per_group(cets, Config) -> 69: stop_cets_disco(Config); 70: end_per_group(Group, Config) -> 71: stop_modules(Group, Config). 72: 73: init_per_testcase(s2s, Config) -> 74: mongoose_config:set_opt(s2s_backend, ?config(backend, Config)), 75: Config; 76: init_per_testcase(TestCase, Config) -> 77: start_component_if_needed(?config(needs_component, Config)), 78: start_modules(TestCase, Config), 79: Config. 80: 81: end_per_testcase(TestCase, Config) -> 82: stop_modules(TestCase, Config), 83: stop_component_if_needed(?config(needs_component, Config)). 84: 85: start_modules(GroupOrCase, Config) -> 86: mongoose_modules:replace_modules(?HOST, [], required_modules(GroupOrCase, Config)). 87: 88: stop_modules(GroupOrCase, Config) -> 89: mongoose_modules:replace_modules(?HOST, maps:keys(required_modules(GroupOrCase, Config)), #{}). 90: 91: opts() -> 92: #{hosts => [?HOST], 93: host_types => [], 94: all_metrics_are_global => false, 95: s2s_backend => mnesia, 96: {auth, ?HOST} => config_parser_helper:extra_auth(), 97: {modules, ?HOST} => #{} 98: }. 99: 100: meck_mods() -> 101: [exometer, mod_bosh_socket, mongoose_bin, ejabberd_sm, ejabberd_local]. 102: 103: required_modules(muc, Config) -> 104: required_module(mod_muc, #{online_backend => ?config(backend, Config), backend => mnesia}); 105: required_modules(bosh, Config) -> 106: required_module(mod_bosh, #{backend => ?config(backend, Config)}); 107: required_modules(stream_management, Config) -> 108: required_module(mod_stream_management, #{backend => ?config(backend, Config)}); 109: required_modules(_GroupOrCase, _Config) -> 110: #{}. 111: 112: required_module(Module, ExtraOpts) -> 113: #{Module => config_parser_helper:mod_config(Module, ExtraOpts)}. 114: 115: start_component_if_needed(true) -> 116: mongoose_router:start(), 117: mongoose_component:start(); 118: start_component_if_needed(_) -> 119: ok. 120: 121: stop_component_if_needed(true) -> 122: mongoose_component:stop(); 123: stop_component_if_needed(_) -> 124: ok. 125: 126: %% ----------------------------------------------------- 127: %% Tests 128: %% ----------------------------------------------------- 129: 130: cleaner_runs_hook_on_nodedown(_Config) -> 131: meck:expect(gen_hook, error_running_hook, fun(_, _, _, _, _) -> ok end), 132: {ok, Cleaner} = mongoose_cleaner:start_link(), 133: gen_hook:add_handler(node_cleanup, global, 134: fun ?MODULE:notify_self_hook/3, 135: #{self => self()}, 50), 136: FakeNode = fakename@fakehost, 137: Cleaner ! {nodedown, FakeNode}, 138: receive 139: {got_nodedown, FakeNode} -> ok 140: after timer:seconds(1) -> 141: ct:fail({timeout, got_nodedown}) 142: end, 143: ?assertEqual(false, meck:called(gen_hook, error_running_hook, 144: ['_', '_', '_', '_', '_'])). 145: 146: cleaner_runs_hook_on_nodedown_for_host_type(_Config) -> 147: HostType = ?HOST, 148: {ok, Cleaner} = mongoose_cleaner:start_link(), 149: gen_hook:add_handler(node_cleanup_for_host_type, HostType, 150: fun ?MODULE:notify_self_hook_for_host_type/3, 151: #{self => self()}, 50), 152: FakeNode = fakename@fakehost, 153: Cleaner ! {nodedown, FakeNode}, 154: receive 155: {got_nodedown_for_host_type, FakeNode, HostType} -> ok 156: after timer:seconds(1) -> 157: ct:fail({timeout, got_nodedown}) 158: end. 159: 160: notify_self_hook(Acc, #{node := Node}, #{self := Self}) -> 161: Self ! {got_nodedown, Node}, 162: {ok, Acc}. 163: 164: notify_self_hook_for_host_type(Acc, #{node := Node}, #{self := Self, host_type := HostType}) -> 165: Self ! {got_nodedown_for_host_type, Node, HostType}, 166: {ok, Acc}. 167: 168: auth_anonymous(_Config) -> 169: HostType = ?HOST, 170: {U, S, R, JID, SID} = get_fake_session(), 171: ejabberd_auth_anonymous:start(HostType), 172: Info = #{auth_module => cyrsasl_anonymous}, 173: ejabberd_auth_anonymous:register_connection(#{}, 174: #{sid => SID, jid => JID, info => Info}, 175: #{host_type => HostType}), 176: true = ejabberd_auth_anonymous:does_user_exist(HostType, U, S), 177: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 178: false = ejabberd_auth_anonymous:does_user_exist(HostType, U, S). 179: 180: last(_Config) -> 181: HostType = ?HOST, 182: {U, S, R, JID, SID} = get_fake_session(), 183: {started, ok} = start(HostType, 184: mod_last, 185: config_parser_helper:mod_config(mod_last, #{iqdisc => no_queue})), 186: not_found = mod_last:get_last_info(HostType, U, S), 187: Status1 = <<"status1">>, 188: {ok, #{}} = mod_last:on_presence_update(new_acc(S), #{jid => JID, status => Status1}, #{}), 189: {ok, TS1, Status1} = mod_last:get_last_info(HostType, U, S), 190: async_helper:wait_until( 191: fun() -> 192: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 193: {ok, TS2, <<>>} = mod_last:get_last_info(HostType, U, S), 194: TS2 - TS1 > 0 195: end, 196: true). 197: 198: stream_management(_Config) -> 199: HostType = ?HOST, 200: {U, S, R, _JID, SID} = get_fake_session(), 201: SMID = <<"123">>, 202: mod_stream_management:register_smid(HostType, SMID, SID), 203: {sid, SID} = mod_stream_management:get_sid(HostType, SMID), 204: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 205: {error, smid_not_found} = mod_stream_management:get_sid(HostType, SMID). 206: 207: s2s(_Config) -> 208: ejabberd_s2s:start_link(), 209: FromTo = {?HOST, <<"foreign">>}, 210: ejabberd_s2s:try_register(FromTo), 211: Self = self(), 212: [Self] = ejabberd_s2s:get_s2s_out_pids(FromTo), 213: mongoose_hooks:node_cleanup(node()), 214: [] = ejabberd_s2s:get_s2s_out_pids(FromTo). 215: 216: bosh(_Config) -> 217: SID = <<"sid">>, 218: Self = self(), 219: {error, _} = mod_bosh:get_session_socket(SID), 220: mod_bosh:store_session(SID, Self), 221: {ok, Self} = mod_bosh:get_session_socket(SID), 222: mongoose_hooks:node_cleanup(node()), 223: {error, _} = mod_bosh:get_session_socket(SID), 224: ok. 225: 226: component(_Config) -> 227: Handler = fun() -> ok end, 228: Domain = <<"cool.localhost">>, 229: Node = some_node, 230: {ok, _} = mongoose_component:register_components([Domain], Node, Handler, false), 231: true = mongoose_component:has_component(Domain), 232: #{mongoose_component := ok} = mongoose_hooks:node_cleanup(Node), 233: [] = mongoose_component:dirty_get_all_components(all), 234: false = mongoose_component:has_component(Domain), 235: ok. 236: 237: component_from_other_node_remains(_Config) -> 238: Handler = fun() -> ok end, 239: Domain = <<"cool.localhost">>, 240: {ok, Comps} = mongoose_component:register_components([Domain], other_node, Handler, false), 241: true = mongoose_component:has_component(Domain), 242: #{mongoose_component := ok} = mongoose_hooks:node_cleanup(some_node), 243: true = mongoose_component:has_component(Domain), 244: mongoose_component:unregister_components(Comps), 245: ok. 246: 247: muc_node_cleanup_for_host_type(_Config) -> 248: {ok, Pid} = mongoose_cleaner:start_link(), 249: Pid ! {nodedown, 'badnode@localhost'}, 250: %% Check if the cleaner process is still running 251: ok = gen_server:call(Pid, ping). 252: 253: muc_room(_Config) -> 254: HostType = ?HOST, 255: MucHost = <<"muc.localhost">>, 256: Pid = remote_pid(), 257: Node = node(Pid), 258: Room = <<"remote_room">>, 259: ok = mod_muc_online_backend:register_room(HostType, MucHost, Room, Pid), 260: ok = mod_muc_online_backend:node_cleanup(HostType, Node), 261: {error, not_found} = mod_muc_online_backend:find_room_pid(HostType, MucHost, Room). 262: 263: muc_room_from_other_node_remains(_Config) -> 264: HostType = ?HOST, 265: MucHost = <<"muc.localhost">>, 266: Pid = self(), 267: RemoteNode = node(remote_pid()), 268: Room = <<"room_on_other_node">>, 269: ok = mod_muc_online_backend:register_room(HostType, MucHost, Room, Pid), 270: ok = mod_muc_online_backend:node_cleanup(HostType, RemoteNode), 271: {ok, Pid} = mod_muc_online_backend:find_room_pid(HostType, MucHost, Room). 272: 273: %% ----------------------------------------------------- 274: %% Internal 275: %% ----------------------------------------------------- 276: 277: setup_meck(exometer) -> 278: meck:new(exometer, [no_link]), 279: meck:expect(exometer, info, fun(_, _) -> undefined end), 280: meck:expect(exometer, new, fun(_, _) -> ok end), 281: meck:expect(exometer, update, fun(_, _) -> ok end); 282: setup_meck(ejabberd_sm) -> 283: meck:new(ejabberd_sm, [no_link]), 284: meck:expect(ejabberd_sm, register_iq_handler, 285: fun(_A1, _A2, _A3) -> ok end); 286: setup_meck(ejabberd_local) -> 287: meck:new(ejabberd_local, [no_link]), 288: meck:expect(ejabberd_local, register_iq_handler, 289: fun(_A1, _A2, _A3) -> ok end); 290: setup_meck(mongoose_bin) -> 291: meck:new(mongoose_bin, [passthrough, no_link]), 292: meck:expect(mongoose_bin, gen_from_crypto, fun() -> <<"123456">> end); 293: setup_meck(mod_bosh_socket) -> 294: meck:new(mod_bosh_socket, [passthrough, no_link]), 295: meck:expect(mod_bosh_socket, start_supervisor, fun() -> {ok, self()} end). 296: 297: unload_meck(Module) -> 298: meck:validate(Module), 299: meck:unload(Module). 300: 301: -spec get_fake_session() -> 302: {U :: binary(), S :: binary(), R :: binary(), 303: JID :: jid:jid(), SID :: ejabberd_sm:sid()}. 304: get_fake_session() -> 305: U = <<"someuser">>, 306: S = ?HOST, 307: R = <<"someresource">>, 308: JID = jid:make(U, S, R), 309: SID = {os:timestamp(), self()}, 310: {U, S, R, JID, SID}. 311: 312: new_acc(Server) -> 313: mongoose_acc:new(#{location => ?LOCATION, 314: lserver => Server, 315: host_type => ?HOST, 316: element => undefined}). 317: 318: start(HostType, Module) -> 319: start(HostType, Module, config_parser_helper:default_mod_config(Module)). 320: 321: start(HostType, Module, Opts) -> 322: mongoose_modules:ensure_started(HostType, Module, Opts). 323: 324: disco_opts() -> 325: #{name => mongoose_cets_discovery, disco_file => "does_not_exist.txt"}. 326: 327: start_cets_disco(Config) -> 328: {ok, Pid} = cets_discovery:start(disco_opts()), 329: [{cets_disco, Pid} | Config]. 330: 331: stop_cets_disco(Config) -> 332: case proplists:get_value(cets_disco, Config) of 333: Pid when is_pid(Pid) -> 334: exit(Pid, kill); 335: _ -> 336: ok 337: end. 338: 339: %% Pid 90 on cool_node@localhost 340: %% Made using: 341: %% erl -name cool_node@localhost 342: %% rp(term_to_binary(list_to_pid("<0.90.0>"))). 343: remote_pid_binary() -> 344: <<131, 88, 100, 0, 19, 99, 111, 111, 108, 95, 110, 111, 100, 101, 64, 345: 108, 111, 99, 97, 108, 104, 111, 115, 116, 0, 0, 0, 90, 0, 0, 0, 0, 100, 346: 200, 255, 233>>. 347: 348: remote_pid() -> 349: binary_to_term(remote_pid_binary()).