1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(cth_auto_clean).
22
23%% CTH Callbacks
24-export([id/1, init/2,
25	 pre_init_per_suite/3, post_init_per_suite/4,
26         pre_end_per_suite/3, post_end_per_suite/4,
27	 pre_init_per_group/4, post_init_per_group/5,
28	 pre_end_per_group/4, post_end_per_group/5,
29	 pre_init_per_testcase/4, post_init_per_testcase/5,
30	 pre_end_per_testcase/4, post_end_per_testcase/5]).
31
32id(_Opts) ->
33    ?MODULE.
34
35init(?MODULE, _Opts) ->
36    ok.
37
38pre_init_per_suite(_Suite, Config, State) ->
39    identify(?FUNCTION_NAME),
40    SharedGL = test_server_io:get_gl(true),
41    SharedGL = find_and_kill(),
42    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
43    %% get status of processes at startup, to be compared with end result
44    {Config, [{all_procs,processes()} | State]}.
45
46post_init_per_suite(_Suite, _Config, Return, State) ->
47    identify(?FUNCTION_NAME),
48    SharedGL = find_and_kill(),
49    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
50    {Return, State}.
51
52pre_end_per_suite(_Suite, Config, State) ->
53    identify(?FUNCTION_NAME),
54    SharedGL = find_and_kill(),
55    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
56    {Config, State}.
57
58post_end_per_suite(_Suite, _Config, Return, State) ->
59    identify(?FUNCTION_NAME),
60    SharedGL = find_and_kill(),
61    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
62    AllProcs = processes(),
63    Remaining = AllProcs--proplists:get_value(all_procs, State),
64    ct:pal("Final remaining processes = ~p", [Remaining]),
65    %% only the end_per_suite process shoud remain at this point!
66    Remaining = [self()],
67    {Return, State}.
68
69pre_init_per_group(_Suite, _Group, Config, State) ->
70    identify(?FUNCTION_NAME),
71    SharedGL = find_and_kill(procs_and_gls),
72    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
73    {Config, State}.
74
75post_init_per_group(_Suite, _Group, _Config, Result, State) ->
76    identify(?FUNCTION_NAME),
77    SharedGL = find_and_kill(procs_and_gls),
78    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
79    {Result, State}.
80
81pre_init_per_testcase(_Suite, _TC, Config, State) ->
82    identify(?FUNCTION_NAME),
83    ThisGL = group_leader(),
84    find_and_kill(proc, ThisGL),
85    case proplists:get_value(tc_group_properties, Config) of
86        [{name,_},parallel] ->
87            timer:sleep(1000);
88        _ ->
89            do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
90    end,
91    {Config, State}.
92
93post_init_per_testcase(_Suite, _TC, Config, Return, State) ->
94    identify(?FUNCTION_NAME),
95    ThisGL = group_leader(),
96    find_and_kill(proc, ThisGL),
97    case proplists:get_value(tc_group_properties, Config) of
98        [{name,_},parallel] ->
99            timer:sleep(1000);
100        _ ->
101            do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
102    end,
103    {Return, State}.
104
105pre_end_per_testcase(_Suite, _TC, Config, State) ->
106    identify(?FUNCTION_NAME),
107    ThisGL = group_leader(),
108    find_and_kill(proc, ThisGL),
109    case proplists:get_value(tc_group_properties, Config) of
110        [{name,_},parallel] ->
111            timer:sleep(1000);
112        _ ->
113            do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
114    end,
115    {Config, State}.
116
117post_end_per_testcase(_Suite, _TC, Config, Result, State) ->
118    identify(?FUNCTION_NAME),
119    ThisGL = group_leader(),
120    find_and_kill(proc, ThisGL),
121    case proplists:get_value(tc_group_properties, Config) of
122        [{name,_},parallel] ->
123            timer:sleep(1000);
124        _ ->
125            do_until(fun() -> element(1,ct:remaining_test_procs()) end, [])
126    end,
127    {Result, State}.
128
129pre_end_per_group(_Suite, _Group, Config, State) ->
130    identify(?FUNCTION_NAME),
131    SharedGL = find_and_kill(procs_and_gls),
132    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
133    {Config, State}.
134
135post_end_per_group(_Suite, _Group, _Config, Return, State) ->
136    identify(?FUNCTION_NAME),
137    SharedGL = find_and_kill(procs_and_gls),
138    do_until(fun() -> ct:remaining_test_procs() end, {[],SharedGL,[]}),
139    {Return, State}.
140
141
142%%%-----------------------------------------------------------------
143%%% HELP FUNCTIONS
144%%%-----------------------------------------------------------------
145
146identify(Func) ->
147    ct:pal("********** THIS IS ~w on ~w", [Func, self()]),
148    ok.
149
150find_and_kill() ->
151    find_and_kill(procs).
152
153find_and_kill(procs) ->
154    {Procs,SharedGL,_ParallelGLs} = ct:remaining_test_procs(),
155    ct:pal("Remaining test processes = ~p", [pi(Procs)]),
156    [pkill(P, kill) || {P,_GL} <- Procs],
157    SharedGL;
158
159find_and_kill(procs_and_gls) ->
160    {Procs,SharedGL,GLs} = ct:remaining_test_procs(),
161    ct:pal("Remaining test processes = ~p", [pi(Procs)]),
162    [pkill(P, kill) || {P,_GL} <- Procs],
163    ct:pal("Remaining group leaders = ~p", [pi(GLs)]),
164    [pkill(GL, kill) || GL <- GLs, GL /= SharedGL],
165    SharedGL.
166
167find_and_kill(proc, ProcGL) ->
168    {Procs,SharedGL,GLs} = ct:remaining_test_procs(),
169    ct:pal("Remaining test processes = ~p", [pi(Procs++GLs)]),
170    [pkill(P, kill) || {P,GL} <- Procs, GL == ProcGL],
171    SharedGL.
172
173pi([{P,_GL}|Ps]) ->
174    pi([P|Ps]);
175pi([P|Ps]) ->
176    case node() == node(P) of
177        true ->
178            {_,GL} = process_info(P,group_leader),
179            {_,CF} = process_info(P,current_function),
180            {_,IC} = process_info(P,initial_call),
181            {_,D} = process_info(P,dictionary),
182            Shared = test_server_io:get_gl(true),
183            User = whereis(user),
184            if (GL /= P) and (GL /= Shared) and (GL /= User) ->
185                    [{P,GL,CF,IC,D} | pi([GL|Ps])];
186               true ->
187                    [{P,GL,CF,IC,D} | pi(Ps)]
188            end;
189        false ->
190            pi(Ps)
191    end;
192pi([]) ->
193    [].
194
195do_until(Fun, Until) ->
196    io:format("Will do until ~p~n", [Until]),
197    do_until(Fun, Until, 1000).
198
199do_until(_, Until, 0) ->
200    io:format("Couldn't get ~p~n", [Until]),
201    exit({not_reached,Until});
202
203do_until(Fun, Until, N) ->
204    case Fun() of
205        Until ->
206            ok;
207        _Tmp ->
208            do_until(Fun, Until, N-1)
209    end.
210
211pkill(P, How) ->
212    ct:pal("KILLING ~w NOW!", [P]),
213    exit(P, How).
214
215