%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2009-2016. 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.
%%
%% %CopyrightEnd%
%%
-module(cth_auto_clean).
%% CTH Callbacks
-export([id/1, init/2,
pre_init_per_suite/3, post_init_per_suite/4,
pre_end_per_suite/3, post_end_per_suite/4,
pre_init_per_group/4, post_init_per_group/5,
pre_end_per_group/4, post_end_per_group/5,
pre_init_per_testcase/4, post_init_per_testcase/5,
pre_end_per_testcase/4, post_end_per_testcase/5]).
id(_Opts) ->
?MODULE.
init(?MODULE, _Opts) ->
ok.
pre_init_per_suite(_Suite, Config, State) ->
identify(?FUNCTION_NAME),
SharedGL = test_server_io:get_gl(true),
SharedGL = find_and_kill(),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
%% get status of processes at startup, to be compared with end result
{Config, [{all_procs,processes()} | State]}.
post_init_per_suite(_Suite, _Config, Return, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Return, State}.
pre_end_per_suite(_Suite, Config, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Config, State}.
post_end_per_suite(_Suite, _Config, Return, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
AllProcs = processes(),
Remaining = AllProcs--proplists:get_value(all_procs, State),
ct:pal("Final remaining processes = ~p", [Remaining]),
%% only the end_per_suite process shoud remain at this point!
Remaining = [self()],
{Return, State}.
pre_init_per_group(_Suite, _Group, Config, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(procs_and_gls),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Config, State}.
post_init_per_group(_Suite, _Group, _Config, Result, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(procs_and_gls),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Result, State}.
pre_init_per_testcase(_Suite, _TC, Config, State) ->
identify(?FUNCTION_NAME),
ThisGL = group_leader(),
find_and_kill(proc, ThisGL),
case proplists:get_value(tc_group_properties, Config) of
[{name,_},parallel] ->
timer:sleep(1000);
_ ->
do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
end,
{Config, State}.
post_init_per_testcase(_Suite, _TC, Config, Return, State) ->
identify(?FUNCTION_NAME),
ThisGL = group_leader(),
find_and_kill(proc, ThisGL),
case proplists:get_value(tc_group_properties, Config) of
[{name,_},parallel] ->
timer:sleep(1000);
_ ->
do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
end,
{Return, State}.
pre_end_per_testcase(_Suite, _TC, Config, State) ->
identify(?FUNCTION_NAME),
ThisGL = group_leader(),
find_and_kill(proc, ThisGL),
case proplists:get_value(tc_group_properties, Config) of
[{name,_},parallel] ->
timer:sleep(1000);
_ ->
do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
end,
{Config, State}.
post_end_per_testcase(_Suite, _TC, Config, Result, State) ->
identify(?FUNCTION_NAME),
ThisGL = group_leader(),
find_and_kill(proc, ThisGL),
case proplists:get_value(tc_group_properties, Config) of
[{name,_},parallel] ->
timer:sleep(1000);
_ ->
do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
end,
{Result, State}.
pre_end_per_group(_Suite, _Group, Config, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(procs_and_gls),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Config, State}.
post_end_per_group(_Suite, _Group, _Config, Return, State) ->
identify(?FUNCTION_NAME),
SharedGL = find_and_kill(procs_and_gls),
do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
{Return, State}.
%%%-----------------------------------------------------------------
%%% HELP FUNCTIONS
%%%-----------------------------------------------------------------
identify(Func) ->
ct:pal("********** THIS IS ~w on ~w", [Func, self()]),
ok.
find_and_kill() ->
find_and_kill(procs).
find_and_kill(procs) ->
{Procs,SharedGL,_ParallelGLs} = ct:remaining_test_procs(),
ct:pal("Remaining test processes = ~p", [pi(Procs)]),
[pkill(P, kill) || {P,_GL} <- Procs],
SharedGL;
find_and_kill(procs_and_gls) ->
{Procs,SharedGL,GLs} = ct:remaining_test_procs(),
ct:pal("Remaining test processes = ~p", [pi(Procs)]),
[pkill(P, kill) || {P,_GL} <- Procs],
ct:pal("Remaining group leaders = ~p", [pi(GLs)]),
[pkill(GL, kill) || GL <- GLs, GL /= SharedGL],
SharedGL.
find_and_kill(proc, ProcGL) ->
{Procs,SharedGL,GLs} = ct:remaining_test_procs(),
ct:pal("Remaining test processes = ~p", [pi(Procs++GLs)]),
[pkill(P, kill) || {P,GL} <- Procs, GL == ProcGL],
SharedGL.
pi([{P,_GL}|Ps]) ->
pi([P|Ps]);
pi([P|Ps]) ->
case node() == node(P) of
true ->
{_,GL} = process_info(P,group_leader),
{_,CF} = process_info(P,current_function),
{_,IC} = process_info(P,initial_call),
{_,D} = process_info(P,dictionary),
Shared = test_server_io:get_gl(true),
User = whereis(user),
if (GL /= P) and (GL /= Shared) and (GL /= User) ->
[{P,GL,CF,IC,D} | pi([GL|Ps])];
true ->
[{P,GL,CF,IC,D} | pi(Ps)]
end;
false ->
pi(Ps)
end;
pi([]) ->
[].
do_until(Fun, Until) ->
io:format("Will do until ~p~n", [Until]),
do_until(Fun, Until, 1000).
do_until(_, Until, 0) ->
io:format("Couldn't get ~p~n", [Until]),
exit({not_reached,Until});
do_until(Fun, Until, N) ->
case Fun() of
Until ->
ok;
_Tmp ->
do_until(Fun, Until, N-1)
end.
pkill(P, How) ->
ct:pal("KILLING ~w NOW!", [P]),
exit(P, How).