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: meck_mods() -> 100: [exometer, mod_bosh_socket, mongoose_bin, ejabberd_sm, ejabberd_local]. 101: 102: required_modules(muc, Config) -> 103: required_module(mod_muc, #{online_backend => ?config(backend, Config), backend => mnesia}); 104: required_modules(bosh, Config) -> 105: required_module(mod_bosh, #{backend => ?config(backend, Config)}); 106: required_modules(stream_management, Config) -> 107: required_module(mod_stream_management, #{backend => ?config(backend, Config)}); 108: required_modules(_GroupOrCase, _Config) -> 109: #{}. 110: 111: required_module(Module, ExtraOpts) -> 112: #{Module => config_parser_helper:mod_config(Module, ExtraOpts)}. 113: 114: start_component_if_needed(true) -> 115: mongoose_router:start(), 116: mongoose_component:start(); 117: start_component_if_needed(_) -> 118: ok. 119: 120: stop_component_if_needed(true) -> 121: mongoose_component:stop(); 122: stop_component_if_needed(_) -> 123: ok. 124: 125: %% ----------------------------------------------------- 126: %% Tests 127: %% ----------------------------------------------------- 128: 129: cleaner_runs_hook_on_nodedown(_Config) -> 130: meck:expect(gen_hook, error_running_hook, fun(_, _, _, _, _) -> ok end), 131: {ok, Cleaner} = mongoose_cleaner:start_link(), 132: gen_hook:add_handler(node_cleanup, global, 133: fun ?MODULE:notify_self_hook/3, 134: #{self => self()}, 50), 135: FakeNode = fakename@fakehost, 136: Cleaner ! {nodedown, FakeNode}, 137: receive 138: {got_nodedown, FakeNode} -> ok 139: after timer:seconds(1) -> 140: ct:fail({timeout, got_nodedown}) 141: end, 142: ?assertEqual(false, meck:called(gen_hook, error_running_hook, 143: ['_', '_', '_', '_', '_'])). 144: 145: cleaner_runs_hook_on_nodedown_for_host_type(_Config) -> 146: HostType = ?HOST, 147: {ok, Cleaner} = mongoose_cleaner:start_link(), 148: gen_hook:add_handler(node_cleanup_for_host_type, HostType, 149: fun ?MODULE:notify_self_hook_for_host_type/3, 150: #{self => self()}, 50), 151: FakeNode = fakename@fakehost, 152: Cleaner ! {nodedown, FakeNode}, 153: receive 154: {got_nodedown_for_host_type, FakeNode, HostType} -> ok 155: after timer:seconds(1) -> 156: ct:fail({timeout, got_nodedown}) 157: end. 158: 159: notify_self_hook(Acc, #{node := Node}, #{self := Self}) -> 160: Self ! {got_nodedown, Node}, 161: {ok, Acc}. 162: 163: notify_self_hook_for_host_type(Acc, #{node := Node}, #{self := Self, host_type := HostType}) -> 164: Self ! {got_nodedown_for_host_type, Node, HostType}, 165: {ok, Acc}. 166: 167: auth_anonymous(_Config) -> 168: HostType = ?HOST, 169: {U, S, R, JID, SID} = get_fake_session(), 170: ejabberd_auth_anonymous:start(HostType), 171: Info = #{auth_module => cyrsasl_anonymous}, 172: ejabberd_auth_anonymous:register_connection(#{}, 173: #{sid => SID, jid => JID, info => Info}, 174: #{host_type => HostType}), 175: true = ejabberd_auth_anonymous:does_user_exist(HostType, U, S), 176: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 177: false = ejabberd_auth_anonymous:does_user_exist(HostType, U, S). 178: 179: last(_Config) -> 180: HostType = ?HOST, 181: {U, S, R, JID, SID} = get_fake_session(), 182: {started, ok} = start(HostType, 183: mod_last, 184: config_parser_helper:mod_config(mod_last, #{iqdisc => no_queue})), 185: not_found = mod_last:get_last_info(HostType, U, S), 186: Status1 = <<"status1">>, 187: {ok, #{}} = mod_last:on_presence_update(new_acc(S), #{jid => JID, status => Status1}, #{}), 188: {ok, TS1, Status1} = mod_last:get_last_info(HostType, U, S), 189: async_helper:wait_until( 190: fun() -> 191: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 192: {ok, TS2, <<>>} = mod_last:get_last_info(HostType, U, S), 193: TS2 - TS1 > 0 194: end, 195: true). 196: 197: stream_management(_Config) -> 198: HostType = ?HOST, 199: {U, S, R, _JID, SID} = get_fake_session(), 200: SMID = <<"123">>, 201: mod_stream_management:register_smid(HostType, SMID, SID), 202: {sid, SID} = mod_stream_management:get_sid(HostType, SMID), 203: mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID), 204: {error, smid_not_found} = mod_stream_management:get_sid(HostType, SMID). 205: 206: s2s(_Config) -> 207: ejabberd_s2s:start_link(), 208: FromTo = {?HOST, <<"foreign">>}, 209: ejabberd_s2s:try_register(FromTo), 210: Self = self(), 211: [Self] = ejabberd_s2s:get_s2s_out_pids(FromTo), 212: mongoose_hooks:node_cleanup(node()), 213: [] = ejabberd_s2s:get_s2s_out_pids(FromTo). 214: 215: bosh(_Config) -> 216: SID = <<"sid">>, 217: Self = self(), 218: {error, _} = mod_bosh:get_session_socket(SID), 219: mod_bosh:store_session(SID, Self), 220: {ok, Self} = mod_bosh:get_session_socket(SID), 221: mongoose_hooks:node_cleanup(node()), 222: {error, _} = mod_bosh:get_session_socket(SID), 223: ok. 224: 225: component(_Config) -> 226: Handler = fun() -> ok end, 227: Domain = <<"cool.localhost">>, 228: Node = some_node, 229: {ok, _} = mongoose_component:register_components([Domain], Node, Handler, false), 230: true = mongoose_component:has_component(Domain), 231: #{mongoose_component := ok} = mongoose_hooks:node_cleanup(Node), 232: [] = mongoose_component:dirty_get_all_components(all), 233: false = mongoose_component:has_component(Domain), 234: ok. 235: 236: component_from_other_node_remains(_Config) -> 237: Handler = fun() -> ok end, 238: Domain = <<"cool.localhost">>, 239: {ok, Comps} = mongoose_component:register_components([Domain], other_node, Handler, false), 240: true = mongoose_component:has_component(Domain), 241: #{mongoose_component := ok} = mongoose_hooks:node_cleanup(some_node), 242: true = mongoose_component:has_component(Domain), 243: mongoose_component:unregister_components(Comps), 244: ok. 245: 246: muc_node_cleanup_for_host_type(_Config) -> 247: {ok, Pid} = mongoose_cleaner:start_link(), 248: Pid ! {nodedown, 'badnode@localhost'}, 249: %% Check if the cleaner process is still running 250: ok = gen_server:call(Pid, ping). 251: 252: muc_room(_Config) -> 253: HostType = ?HOST, 254: MucHost = <<"muc.localhost">>, 255: Pid = remote_pid(), 256: Node = node(Pid), 257: Room = <<"remote_room">>, 258: ok = mod_muc_online_backend:register_room(HostType, MucHost, Room, Pid), 259: ok = mod_muc_online_backend:node_cleanup(HostType, Node), 260: {error, not_found} = mod_muc_online_backend:find_room_pid(HostType, MucHost, Room). 261: 262: muc_room_from_other_node_remains(_Config) -> 263: HostType = ?HOST, 264: MucHost = <<"muc.localhost">>, 265: Pid = self(), 266: RemoteNode = node(remote_pid()), 267: Room = <<"room_on_other_node">>, 268: ok = mod_muc_online_backend:register_room(HostType, MucHost, Room, Pid), 269: ok = mod_muc_online_backend:node_cleanup(HostType, RemoteNode), 270: {ok, Pid} = mod_muc_online_backend:find_room_pid(HostType, MucHost, Room). 271: 272: %% ----------------------------------------------------- 273: %% Internal 274: %% ----------------------------------------------------- 275: 276: setup_meck(exometer) -> 277: meck:new(exometer, [no_link]), 278: meck:expect(exometer, info, fun(_, _) -> undefined end), 279: meck:expect(exometer, new, fun(_, _) -> ok end), 280: meck:expect(exometer, update, fun(_, _) -> ok end); 281: setup_meck(ejabberd_sm) -> 282: meck:new(ejabberd_sm, [no_link]), 283: meck:expect(ejabberd_sm, register_iq_handler, 284: fun(_A1, _A2, _A3) -> ok end); 285: setup_meck(ejabberd_local) -> 286: meck:new(ejabberd_local, [no_link]), 287: meck:expect(ejabberd_local, register_iq_handler, 288: fun(_A1, _A2, _A3) -> ok end); 289: setup_meck(mongoose_bin) -> 290: meck:new(mongoose_bin, [passthrough, no_link]), 291: meck:expect(mongoose_bin, gen_from_crypto, fun() -> <<"123456">> end); 292: setup_meck(mod_bosh_socket) -> 293: meck:new(mod_bosh_socket, [passthrough, no_link]), 294: meck:expect(mod_bosh_socket, start_supervisor, fun() -> {ok, self()} end). 295: 296: unload_meck(Module) -> 297: meck:validate(Module), 298: meck:unload(Module). 299: 300: -spec get_fake_session() -> 301: {U :: binary(), S :: binary(), R :: binary(), 302: JID :: jid:jid(), SID :: ejabberd_sm:sid()}. 303: get_fake_session() -> 304: U = <<"someuser">>, 305: S = ?HOST, 306: R = <<"someresource">>, 307: JID = jid:make(U, S, R), 308: SID = {os:timestamp(), self()}, 309: {U, S, R, JID, SID}. 310: 311: new_acc(Server) -> 312: mongoose_acc:new(#{location => ?LOCATION, 313: lserver => Server, 314: host_type => ?HOST, 315: element => undefined}). 316: 317: start(HostType, Module) -> 318: start(HostType, Module, config_parser_helper:default_mod_config(Module)). 319: 320: start(HostType, Module, Opts) -> 321: mongoose_modules:ensure_started(HostType, Module, Opts). 322: 323: disco_opts() -> 324: #{name => mongoose_cets_discovery, disco_file => "does_not_exist.txt"}. 325: 326: start_cets_disco(Config) -> 327: {ok, Pid} = cets_discovery:start(disco_opts()), 328: [{cets_disco, Pid} | Config]. 329: 330: stop_cets_disco(Config) -> 331: case proplists:get_value(cets_disco, Config) of 332: Pid when is_pid(Pid) -> 333: exit(Pid, kill); 334: _ -> 335: ok 336: end. 337: 338: %% Pid 90 on cool_node@localhost 339: %% Made using: 340: %% erl -name cool_node@localhost 341: %% rp(term_to_binary(list_to_pid("<0.90.0>"))). 342: remote_pid_binary() -> 343: <<131, 88, 100, 0, 19, 99, 111, 111, 108, 95, 110, 111, 100, 101, 64, 344: 108, 111, 99, 97, 108, 104, 111, 115, 116, 0, 0, 0, 90, 0, 0, 0, 0, 100, 345: 200, 255, 233>>. 346: 347: remote_pid() -> 348: binary_to_term(remote_pid_binary()).