%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2011. 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(supervisor_bridge_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,starting/1,
mini_terminate/1,mini_die/1,badstart/1,
simple_global_supervisor/1]).
-export([client/1,init/1,internal_loop_init/1,terminate/2,server9212/0]).
-include_lib("common_test/include/ct.hrl").
-define(bridge_name,supervisor_bridge_SUITE_server).
-define(work_bridge_name,work_supervisor_bridge_SUITE_server).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
all() ->
[starting, mini_terminate, mini_die, badstart, simple_global_supervisor].
groups() ->
[].
init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
starting(Config) when is_list(Config) ->
process_flag(trap_exit,true),
ignore = start(1),
{error,testing} = start(2),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
mini_terminate(Config) when is_list(Config) ->
miniappl(1),
ok.
mini_die(Config) when is_list(Config) ->
miniappl(2),
ok.
miniappl(N) ->
process_flag(trap_exit,true),
{ok,Server} = start(3),
Client = spawn_link(?MODULE,client,[N]),
ct:timetrap({seconds,2}),
miniappl_loop(Client, Server).
miniappl_loop([],[]) ->
ok;
miniappl_loop(Client,Server) ->
io:format("Client ~p, Server ~p\n",[Client,Server]),
receive
{'EXIT',Client,_} ->
miniappl_loop([],Server);
{'EXIT',Server,killed} -> %% terminate
miniappl_loop(Client,[]);
{'EXIT',Server,died} -> %% die
miniappl_loop(Client,[]);
{dying,_Reason} ->
miniappl_loop(Client, Server);
Other ->
exit({failed,Other})
end.
%%%%%%%%%%%%%%%%%%%%
%% Client
client(N) ->
io:format("Client starting...\n"),
ok = public_request(),
case N of
1 -> public_kill();
2 -> ?work_bridge_name ! die
end,
io:format("Killed server, terminating client...\n"),
exit(fine).
%%%%%%%%%%%%%%%%%%%%
%% Non compliant server
start(N) ->
supervisor_bridge:start_link({local,?bridge_name},?MODULE,N).
public_request() ->
?work_bridge_name ! {non_compliant_message,self()},
io:format("Client waiting for answer...\n"),
receive
non_compliant_answer ->
ok
end,
io:format("Client got answer...\n").
public_kill() ->
%% This func knows about supervisor_bridge
exit(whereis(?work_bridge_name),kill).
init(1) ->
ignore;
init(2) ->
{error,testing};
init(3) ->
%% This func knows about supervisor_bridge
InternalPid = spawn_link(?MODULE,internal_loop_init,[self()]),
receive
{InternalPid,init_done} ->
{ok,InternalPid,self()}
end;
init({4,Result}) ->
Result.
internal_loop_init(Parent) ->
register(?work_bridge_name, self()),
Parent ! {self(),init_done},
internal_loop({Parent,self()}).
internal_loop(State) ->
receive
{non_compliant_message,From} ->
io:format("Got request from ~p\n",[From]),
From ! non_compliant_answer,
internal_loop(State);
die ->
exit(died)
end.
terminate(Reason,{Parent,Worker}) ->
%% This func knows about supervisor_bridge
io:format("Terminating bridge...\n"),
exit(Worker,kill),
Parent ! {dying,Reason},
anything;
terminate(_Reason, _State) ->
any.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test various bad ways of starting a supervisor bridge.
badstart(Config) when is_list(Config) ->
%% Various bad arguments.
{'EXIT',_} =
(catch supervisor_bridge:start_link({xxx,?bridge_name},?MODULE,1)),
{'EXIT',_} =
(catch supervisor_bridge:start_link({local,"foo"},?MODULE,1)),
{'EXIT',_} =
(catch supervisor_bridge:start_link(?bridge_name,?MODULE,1)),
receive
Msg ->
ct:fail({unexpected,Msg})
after 1 ->
ok
end,
%% Already started.
process_flag(trap_exit, true),
{ok,Pid} =
supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
{error,{already_started,Pid}} =
supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
public_kill(),
%% We used to wait 1 ms before retrieving the message queue,
%% but that might not always be enough if the machine is overloaded.
receive
{'EXIT', Pid, killed} -> ok
end,
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% OTP-9212. Restart of global supervisor.
%% Globally registered supervisor.
simple_global_supervisor(Config) when is_list(Config) ->
Child = {child, {?MODULE,server9212,[]}, permanent, 2000, worker, []},
InitResult = {ok, {{one_for_all,3,60}, [Child]}},
{ok, Sup} =
supervisor:start_link({local,bridge9212}, ?MODULE, {4,InitResult}),
BN_1 = global:whereis_name(?bridge_name),
exit(BN_1, kill),
timer:sleep(200),
BN_2 = global:whereis_name(?bridge_name),
true = is_pid(BN_2),
true = BN_1 =/= BN_2,
process_flag(trap_exit, true),
exit(Sup, kill),
receive {'EXIT', Sup, killed} -> ok end,
ok.
server9212() ->
supervisor_bridge:start_link({global,?bridge_name}, ?MODULE, 3).