refactor(test): use a linked janitor for test teardown

This commit is contained in:
Thales Macedo Garitezi 2022-12-08 09:48:28 -03:00
parent b66d2904be
commit 464d0a5057
3 changed files with 94 additions and 33 deletions

View File

@ -67,8 +67,7 @@
-export([clear_screen/0]).
-export([with_mock/4]).
-export([
on_exit/2,
run_on_exit_callbacks/1
on_exit/1
]).
%% Toxiproxy API
@ -939,19 +938,16 @@ latency_up_proxy(off, Name, ProxyHost, ProxyPort) ->
%% Testcase teardown utilities
%%-------------------------------------------------------------------------------
get_on_exit_callbacks(Id) ->
persistent_term:get({?MODULE, on_exit, Id}, []).
get_or_spawn_janitor() ->
case get({?MODULE, janitor_proc}) of
undefined ->
{ok, Janitor} = emqx_test_janitor:start_link(),
put({?MODULE, janitor_proc}, Janitor),
Janitor;
Janitor ->
Janitor
end.
put_on_exit_callbacks(Id, Funs) ->
persistent_term:put({?MODULE, on_exit, Id}, Funs).
on_exit(Id, Fun) ->
Callbacks = get_on_exit_callbacks(Id),
put_on_exit_callbacks(Id, [Fun | Callbacks]).
%% should be called at `end_per_testcase'.
%% TODO: scope per group and suite as well?
run_on_exit_callbacks(Id) ->
Callbacks = get_on_exit_callbacks(Id),
persistent_term:erase({?MODULE, on_exit, Id}),
lists:foreach(fun(Fun) -> Fun() end, Callbacks).
on_exit(Fun) ->
Janitor = get_or_spawn_janitor(),
ok = emqx_test_janitor:push_on_exit_callback(Janitor, Fun).

View File

@ -0,0 +1,69 @@
%%--------------------------------------------------------------------
%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_test_janitor).
-behaviour(gen_server).
%% `gen_server' API
-export([
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2
]).
%% API
-export([
start_link/0,
push_on_exit_callback/2
]).
%%----------------------------------------------------------------------------------
%% API
%%----------------------------------------------------------------------------------
start_link() ->
gen_server:start_link(?MODULE, self(), []).
push_on_exit_callback(Server, Callback) when is_function(Callback, 0) ->
gen_server:call(Server, {push, Callback}).
%%----------------------------------------------------------------------------------
%% `gen_server' API
%%----------------------------------------------------------------------------------
init(Parent) ->
process_flag(trap_exit, true),
Ref = monitor(process, Parent),
{ok, #{callbacks => [], owner => {Ref, Parent}}}.
terminate(_Reason, #{callbacks := Callbacks}) ->
lists:foreach(fun(Fun) -> Fun() end, Callbacks).
handle_call({push, Callback}, _From, State = #{callbacks := Callbacks}) ->
{reply, ok, State#{callbacks := [Callback | Callbacks]}};
handle_call(_Req, _From, State) ->
{reply, error, State}.
handle_cast(_Req, State) ->
{noreply, State}.
handle_info({'DOWN', Ref, process, Parent, _Reason}, State = #{owner := {Ref, Parent}}) ->
{stop, normal, State};
handle_info(_Msg, State) ->
{noreply, State}.

View File

@ -16,10 +16,7 @@
-define(BRIDGE_TYPE, gcp_pubsub).
-define(BRIDGE_TYPE_BIN, <<"gcp_pubsub">>).
-import(emqx_common_test_helpers, [on_exit/2, run_on_exit_callbacks/1]).
-define(on_exit_key(TESTCASE), {?MODULE, TESTCASE}).
-define(on_exit(FUN), on_exit({?MODULE, ?FUNCTION_NAME}, FUN)).
-import(emqx_common_test_helpers, [on_exit/1]).
%%------------------------------------------------------------------------------
%% CT boilerplate
@ -138,9 +135,8 @@ init_per_testcase(TestCase, Config0) ->
Config = generate_config(Config0),
[{telemetry_table, Tid} | Config].
end_per_testcase(TestCase, _Config) ->
end_per_testcase(_TestCase, _Config) ->
ok = snabbkaffe:stop(),
run_on_exit_callbacks(?on_exit_key(TestCase)),
delete_all_bridges(),
ok = emqx_connector_web_hook_server:stop(),
ok.
@ -515,7 +511,7 @@ install_telemetry_handler(TestCase) ->
end,
unused_config
),
on_exit(?on_exit_key(TestCase), fun() ->
on_exit(fun() ->
telemetry:detach(HandlerId),
ets:delete(Tid)
end),
@ -567,7 +563,7 @@ t_publish_success(Config) ->
end
),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
assert_empty_metrics(ResourceId),
Payload = <<"payload">>,
Message = emqx_message:make(Topic, Payload),
@ -669,7 +665,7 @@ t_publish_templated(Config) ->
end
),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
assert_empty_metrics(ResourceId),
Payload = <<"payload">>,
Message =
@ -734,7 +730,7 @@ t_publish_success_batch(Config) ->
)
),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
assert_empty_metrics(ResourceId),
NumMessages = BatchSize * 2,
Messages = [emqx_message:make(Topic, integer_to_binary(N)) || N <- lists:seq(1, NumMessages)],
@ -916,7 +912,7 @@ t_publish_econnrefused(Config) ->
%% in ehttpc.
{ok, _} = create_bridge(Config, #{<<"pipelining">> => 1}),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
assert_empty_metrics(ResourceId),
ok = emqx_connector_web_hook_server:stop(),
do_econnrefused_or_timeout_test(Config, econnrefused).
@ -931,7 +927,7 @@ t_publish_timeout(Config) ->
<<"resource_opts">> => #{<<"batch_size">> => 1}
}),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
assert_empty_metrics(ResourceId),
TestPid = self(),
TimeoutHandler =
@ -1132,7 +1128,7 @@ t_success_no_body(Config) ->
Topic = <<"t/topic">>,
{ok, _} = create_bridge(Config),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
Payload = <<"payload">>,
Message = emqx_message:make(Topic, Payload),
?check_trace(
@ -1170,7 +1166,7 @@ t_failure_with_body(Config) ->
Topic = <<"t/topic">>,
{ok, _} = create_bridge(Config),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
Payload = <<"payload">>,
Message = emqx_message:make(Topic, Payload),
?check_trace(
@ -1208,7 +1204,7 @@ t_failure_no_body(Config) ->
Topic = <<"t/topic">>,
{ok, _} = create_bridge(Config),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
Payload = <<"payload">>,
Message = emqx_message:make(Topic, Payload),
?check_trace(
@ -1257,7 +1253,7 @@ t_unrecoverable_error(Config) ->
{ok, _} = create_bridge(Config),
assert_empty_metrics(ResourceId),
{ok, #{<<"id">> := RuleId}} = create_rule_and_action_http(Config),
?on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
on_exit(fun() -> ok = emqx_rule_engine:delete_rule(RuleId) end),
Payload = <<"payload">>,
Message = emqx_message:make(Topic, Payload),
?check_trace(