1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1996-2011. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: %%
   19: -module(supervisor_bridge_SUITE).
   20: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   21: 	 init_per_group/2,end_per_group/2,starting/1,
   22: 	 mini_terminate/1,mini_die/1,badstart/1,
   23:          simple_global_supervisor/1]).
   24: -export([client/1,init/1,internal_loop_init/1,terminate/2,server9212/0]).
   25: 
   26: -include_lib("test_server/include/test_server.hrl").
   27: -define(bridge_name,supervisor_bridge_SUITE_server).
   28: -define(work_bridge_name,work_supervisor_bridge_SUITE_server).
   29: 
   30: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   31: 
   32: suite() -> [{ct_hooks,[ts_install_cth]}].
   33: 
   34: all() -> 
   35:     [starting, mini_terminate, mini_die, badstart, simple_global_supervisor].
   36: 
   37: groups() -> 
   38:     [].
   39: 
   40: init_per_suite(Config) ->
   41:     Config.
   42: 
   43: end_per_suite(_Config) ->
   44:     ok.
   45: 
   46: init_per_group(_GroupName, Config) ->
   47:     Config.
   48: 
   49: end_per_group(_GroupName, Config) ->
   50:     Config.
   51: 
   52: 
   53: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   54: 
   55: starting(suite) -> [];
   56: starting(Config) when is_list(Config) ->
   57:     process_flag(trap_exit,true),
   58: 
   59:     ?line ignore = start(1),
   60:     ?line {error,testing} = start(2),
   61:     ok.
   62: 
   63: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   64: 
   65: mini_terminate(suite) -> [];
   66: mini_terminate(Config) when is_list(Config) ->
   67:     miniappl(1),
   68:     ok.
   69: 
   70: mini_die(suite) -> [];
   71: mini_die(Config) when is_list(Config) ->
   72:     miniappl(2),
   73:     ok.
   74: 
   75: miniappl(N) ->
   76:     process_flag(trap_exit,true),
   77:     ?line {ok,Server} = start(3),
   78:     ?line Client = spawn_link(?MODULE,client,[N]),
   79:     ?line Handle = test_server:timetrap(2000),
   80:     ?line miniappl_loop(Client,Server),
   81:     ?line test_server:timetrap_cancel(Handle).
   82: 
   83: miniappl_loop([],[]) ->
   84:     ok;
   85: miniappl_loop(Client,Server) ->
   86:     io:format("Client ~p, Server ~p\n",[Client,Server]),
   87:     receive
   88: 	{'EXIT',Client,_} ->
   89: 	    ?line miniappl_loop([],Server);
   90: 	{'EXIT',Server,killed} -> %% terminate
   91: 	    ?line miniappl_loop(Client,[]);
   92: 	{'EXIT',Server,died} -> %% die
   93: 	    ?line miniappl_loop(Client,[]);
   94: 	{dying,_Reason} ->
   95: 	    ?line miniappl_loop(Client, Server);
   96: 	Other ->
   97: 	    ?line exit({failed,Other})
   98:     end.
   99: 
  100: %%%%%%%%%%%%%%%%%%%%
  101: % Client
  102: 
  103: client(N) ->
  104:     io:format("Client starting...\n"),
  105:     ok = public_request(),
  106:     case N of
  107: 	1 -> public_kill();
  108: 	2 -> ?work_bridge_name ! die
  109:     end,
  110:     io:format("Killed server, terminating client...\n"),
  111:     exit(fine).
  112: 
  113: %%%%%%%%%%%%%%%%%%%%
  114: % Non compliant server
  115: 
  116: start(N) ->
  117:     supervisor_bridge:start_link({local,?bridge_name},?MODULE,N).
  118: 
  119: public_request() ->
  120:     ?work_bridge_name ! {non_compliant_message,self()},
  121:     io:format("Client waiting for answer...\n"),
  122:     receive
  123: 	non_compliant_answer ->
  124: 	    ok
  125:     end,
  126:     io:format("Client got answer...\n").
  127: 
  128: public_kill() ->
  129:     %% This func knows about supervisor_bridge
  130:     exit(whereis(?work_bridge_name),kill).
  131: 
  132: init(1) ->
  133:     ignore;
  134: init(2) ->
  135:     {error,testing};
  136: init(3) ->
  137:     %% This func knows about supervisor_bridge
  138:     InternalPid = spawn_link(?MODULE,internal_loop_init,[self()]),
  139:     receive
  140: 	{InternalPid,init_done} ->
  141: 	    {ok,InternalPid,self()}
  142:     end;
  143: init({4,Result}) ->
  144:     Result.
  145: 
  146: internal_loop_init(Parent) ->
  147:     register(?work_bridge_name, self()),
  148:     Parent ! {self(),init_done},
  149:     internal_loop({Parent,self()}).
  150: 
  151: internal_loop(State) ->
  152:     receive
  153: 	{non_compliant_message,From} ->
  154: 	    io:format("Got request from ~p\n",[From]),
  155: 	    From ! non_compliant_answer,
  156: 	    internal_loop(State);
  157: 	die ->
  158: 	    exit(died)
  159:     end.
  160: 
  161: terminate(Reason,{Parent,Worker}) ->
  162:     %% This func knows about supervisor_bridge
  163:     io:format("Terminating bridge...\n"),
  164:     exit(Worker,kill),
  165:     Parent ! {dying,Reason},
  166:     anything;
  167: terminate(_Reason, _State) ->
  168:     any.
  169: 
  170: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  171: 
  172: badstart(suite) -> [];
  173: badstart(doc) -> "Test various bad ways of starting a supervisor bridge.";
  174: badstart(Config) when is_list(Config) ->
  175:     ?line Dog = test_server:timetrap(test_server:minutes(1)),
  176: 
  177:     %% Various bad arguments.
  178: 
  179:     ?line {'EXIT',_} =
  180: 	(catch supervisor_bridge:start_link({xxx,?bridge_name},?MODULE,1)),
  181:     ?line {'EXIT',_} =
  182: 	(catch supervisor_bridge:start_link({local,"foo"},?MODULE,1)),
  183:     ?line {'EXIT',_} =
  184: 	(catch supervisor_bridge:start_link(?bridge_name,?MODULE,1)),
  185:     ?line [] = test_server:messages_get(),	% No messages waiting
  186: 
  187:     %% Already started.
  188: 
  189:     ?line process_flag(trap_exit, true),
  190:     ?line {ok,Pid} =
  191: 	supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
  192:     ?line {error,{already_started,Pid}} =
  193: 	supervisor_bridge:start_link({local,?bridge_name},?MODULE,3),
  194:     ?line public_kill(),
  195: 
  196:     %% We used to wait 1 ms before retrieving the message queue,
  197:     %% but that might not always be enough if the machine is overloaded.
  198:     ?line receive
  199: 	      {'EXIT', Pid, killed} -> ok
  200: 	  end,
  201:     ?line test_server:timetrap_cancel(Dog),
  202:     ok.
  203: 
  204: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  205: %% OTP-9212. Restart of global supervisor.
  206: 
  207: simple_global_supervisor(suite) -> [];
  208: simple_global_supervisor(doc) -> "Globally registered supervisor.";
  209: simple_global_supervisor(Config) when is_list(Config) ->
  210:     ?line Dog = test_server:timetrap({seconds,10}),
  211: 
  212:     Child = {child, {?MODULE,server9212,[]}, permanent, 2000, worker, []},
  213:     InitResult = {ok, {{one_for_all,3,60}, [Child]}},
  214:     {ok, Sup} =
  215:         supervisor:start_link({local,bridge9212}, ?MODULE, {4,InitResult}),
  216: 
  217:     BN_1 = global:whereis_name(?bridge_name),
  218:     ?line exit(BN_1, kill),
  219:     timer:sleep(200),
  220:     BN_2 = global:whereis_name(?bridge_name),
  221:     ?line true = is_pid(BN_2),
  222:     ?line true = BN_1 =/= BN_2,
  223: 
  224:     ?line process_flag(trap_exit, true),
  225:     exit(Sup, kill),
  226:     ?line receive {'EXIT', Sup, killed} -> ok end,
  227:     ?line test_server:timetrap_cancel(Dog),
  228:     ok.
  229: 
  230: server9212() ->
  231:     supervisor_bridge:start_link({global,?bridge_name}, ?MODULE, 3).