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