1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1996-2013. 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: %% Description: Tests supervisor.erl
   20: 
   21: -module(supervisor_SUITE).
   22: 
   23: -include_lib("common_test/include/ct.hrl").
   24: -define(TIMEOUT, ?t:minutes(1)).
   25: 
   26: %% Testserver specific export
   27: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   28: 	 init_per_group/2,end_per_group/2, init_per_testcase/2,
   29: 	 end_per_testcase/2]).
   30: 
   31: %% Internal export
   32: -export([init/1, terminate_all_children/1,
   33:          middle9212/0, gen_server9212/0, handle_info/2]).
   34: 
   35: %% API tests
   36: -export([ sup_start_normal/1, sup_start_ignore_init/1, 
   37: 	  sup_start_ignore_child/1, sup_start_ignore_temporary_child/1,
   38: 	  sup_start_ignore_temporary_child_start_child/1,
   39: 	  sup_start_ignore_temporary_child_start_child_simple/1,
   40: 	  sup_start_error_return/1, sup_start_fail/1, sup_stop_infinity/1,
   41: 	  sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1,
   42: 	  child_adm_simple/1, child_specs/1, extra_return/1]).
   43: 
   44: %% Tests concept permanent, transient and temporary 
   45: -export([ permanent_normal/1, transient_normal/1,
   46: 	  temporary_normal/1,
   47: 	  permanent_shutdown/1, transient_shutdown/1,
   48: 	  temporary_shutdown/1,
   49:           faulty_application_shutdown/1,
   50: 	  permanent_abnormal/1, transient_abnormal/1,
   51: 	  temporary_abnormal/1, temporary_bystander/1]).
   52: 
   53: %% Restart strategy tests 
   54: -export([ one_for_one/1,
   55: 	  one_for_one_escalation/1, one_for_all/1,
   56: 	  one_for_all_escalation/1, one_for_all_other_child_fails_restart/1,
   57: 	  simple_one_for_one/1, simple_one_for_one_escalation/1,
   58: 	  rest_for_one/1, rest_for_one_escalation/1,
   59: 	  rest_for_one_other_child_fails_restart/1,
   60: 	  simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
   61: 
   62: %% Misc tests
   63: -export([child_unlink/1, tree/1, count_children_memory/1,
   64: 	 do_not_save_start_parameters_for_temporary_children/1,
   65: 	 do_not_save_child_specs_for_temporary_children/1,
   66: 	 simple_one_for_one_scale_many_temporary_children/1,
   67:          simple_global_supervisor/1, hanging_restart_loop/1,
   68: 	 hanging_restart_loop_simple/1]).
   69: 
   70: %%-------------------------------------------------------------------------
   71: 
   72: suite() ->
   73:     [{ct_hooks,[ts_install_cth]}].
   74: 
   75: all() -> 
   76:     [{group, sup_start}, {group, sup_stop}, child_adm,
   77:      child_adm_simple, extra_return, child_specs,
   78:      {group, restart_one_for_one},
   79:      {group, restart_one_for_all},
   80:      {group, restart_simple_one_for_one},
   81:      {group, restart_rest_for_one},
   82:      {group, normal_termination},
   83:      {group, shutdown_termination},
   84:      {group, abnormal_termination}, child_unlink, tree,
   85:      count_children_memory, do_not_save_start_parameters_for_temporary_children,
   86:      do_not_save_child_specs_for_temporary_children,
   87:      simple_one_for_one_scale_many_temporary_children, temporary_bystander,
   88:      simple_global_supervisor, hanging_restart_loop, hanging_restart_loop_simple].
   89: 
   90: groups() -> 
   91:     [{sup_start, [],
   92:       [sup_start_normal, sup_start_ignore_init,
   93:        sup_start_ignore_child, sup_start_ignore_temporary_child,
   94:        sup_start_ignore_temporary_child_start_child,
   95:        sup_start_ignore_temporary_child_start_child_simple,
   96:        sup_start_error_return, sup_start_fail]},
   97:      {sup_stop, [],
   98:       [sup_stop_infinity, sup_stop_timeout,
   99:        sup_stop_brutal_kill]},
  100:      {normal_termination, [],
  101:       [permanent_normal, transient_normal, temporary_normal]},
  102:      {shutdown_termination, [],
  103:       [permanent_shutdown, transient_shutdown, temporary_shutdown,
  104:        faulty_application_shutdown]},
  105:      {abnormal_termination, [],
  106:       [permanent_abnormal, transient_abnormal,
  107:        temporary_abnormal]},
  108:      {restart_one_for_one, [],
  109:       [one_for_one, one_for_one_escalation]},
  110:      {restart_one_for_all, [],
  111:       [one_for_all, one_for_all_escalation,
  112:        one_for_all_other_child_fails_restart]},
  113:      {restart_simple_one_for_one, [],
  114:       [simple_one_for_one, simple_one_for_one_shutdown,
  115:        simple_one_for_one_extra, simple_one_for_one_escalation]},
  116:      {restart_rest_for_one, [],
  117:       [rest_for_one, rest_for_one_escalation,
  118:        rest_for_one_other_child_fails_restart]}].
  119: 
  120: init_per_suite(Config) ->
  121:     Config.
  122: 
  123: end_per_suite(_Config) ->
  124:     ok.
  125: 
  126: init_per_group(_GroupName, Config) ->
  127:     Config.
  128: 
  129: end_per_group(_GroupName, Config) ->
  130:     Config.
  131: 
  132: init_per_testcase(count_children_memory, Config) ->
  133:     try erlang:memory() of
  134: 	_ ->
  135: 	    erts_debug:set_internal_state(available_internal_state, true),
  136: 	    Dog = ?t:timetrap(?TIMEOUT),
  137: 	    [{watchdog,Dog}|Config]
  138:     catch error:notsup ->
  139: 	    {skip, "+Meamin used during test; erlang:memory/1 not available"}
  140:     end;
  141: init_per_testcase(_Case, Config) ->
  142:     Dog = ?t:timetrap(?TIMEOUT),
  143:     [{watchdog,Dog}|Config].
  144: 
  145: end_per_testcase(count_children_memory, Config) ->
  146:     catch erts_debug:set_internal_state(available_internal_state, false),
  147:     ?t:timetrap_cancel(?config(watchdog,Config)),
  148:     ok;
  149: end_per_testcase(_Case, Config) ->
  150:     ?t:timetrap_cancel(?config(watchdog,Config)),
  151:     ok.
  152: 
  153: start_link(InitResult) ->
  154:     supervisor:start_link({local, sup_test}, ?MODULE, InitResult).
  155: 
  156: %% Simulate different supervisors callback.  
  157: init(fail) ->
  158:     erlang:error({badmatch,2});
  159: init(InitResult) ->
  160:     InitResult.
  161: 
  162: %% Respect proplist return of supervisor:count_children
  163: get_child_counts(Supervisor) ->
  164:     Counts = supervisor:count_children(Supervisor),
  165:     [proplists:get_value(specs, Counts),
  166:      proplists:get_value(active, Counts),
  167:      proplists:get_value(supervisors, Counts),
  168:      proplists:get_value(workers, Counts)].
  169: 
  170: %%-------------------------------------------------------------------------
  171: %% Test cases starts here.
  172: %% -------------------------------------------------------------------------
  173: %% Tests that the supervisor process starts correctly and that it can
  174: %% be terminated gracefully.
  175: sup_start_normal(Config) when is_list(Config) ->
  176:     process_flag(trap_exit, true),
  177:     {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  178:     terminate(Pid, shutdown).
  179: 
  180: %%-------------------------------------------------------------------------
  181: %% Tests what happens if init-callback returns ignore.
  182: sup_start_ignore_init(Config) when is_list(Config) ->
  183:     process_flag(trap_exit, true),
  184:     ignore = start_link(ignore),
  185:     check_exit_reason(normal).
  186: 
  187: %%-------------------------------------------------------------------------
  188: %% Tests what happens if init-callback returns ignore.
  189: sup_start_ignore_child(Config) when is_list(Config) ->
  190:     process_flag(trap_exit, true),
  191:     {ok, _Pid}  = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  192:     Child1 = {child1, {supervisor_1, start_child, [ignore]}, 
  193: 	      permanent, 1000, worker, []},
  194:     Child2 = {child2, {supervisor_1, start_child, []}, permanent,
  195: 	      1000, worker, []},
  196: 
  197:     {ok, undefined} = supervisor:start_child(sup_test, Child1),
  198:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  199: 
  200:     [{child2, CPid2, worker, []},{child1, undefined, worker, []}]
  201: 	= supervisor:which_children(sup_test),
  202:     [2,1,0,2] = get_child_counts(sup_test).
  203: 
  204: %%-------------------------------------------------------------------------
  205: %% Tests what happens if child's init-callback returns ignore for a
  206: %% temporary child when ChildSpec is returned directly from supervisor
  207: %% init callback.
  208: %% Child spec shall NOT be saved!!!
  209: sup_start_ignore_temporary_child(Config) when is_list(Config) ->
  210:     process_flag(trap_exit, true),
  211:     Child1 = {child1, {supervisor_1, start_child, [ignore]},
  212: 	      temporary, 1000, worker, []},
  213:     Child2 = {child2, {supervisor_1, start_child, []}, temporary,
  214: 	      1000, worker, []},
  215:     {ok, _Pid}  = start_link({ok, {{one_for_one, 2, 3600}, [Child1,Child2]}}),
  216: 
  217:     [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test),
  218:     true = is_pid(CPid2),
  219:     [1,1,0,1] = get_child_counts(sup_test).
  220: 
  221: %%-------------------------------------------------------------------------
  222: %% Tests what happens if child's init-callback returns ignore for a
  223: %% temporary child when child is started with start_child/2.
  224: %% Child spec shall NOT be saved!!!
  225: sup_start_ignore_temporary_child_start_child(Config) when is_list(Config) ->
  226:     process_flag(trap_exit, true),
  227:     {ok, _Pid}  = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  228:     Child1 = {child1, {supervisor_1, start_child, [ignore]},
  229: 	      temporary, 1000, worker, []},
  230:     Child2 = {child2, {supervisor_1, start_child, []}, temporary,
  231: 	      1000, worker, []},
  232: 
  233:     {ok, undefined} = supervisor:start_child(sup_test, Child1),
  234:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  235: 
  236:     [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test),
  237:     [1,1,0,1] = get_child_counts(sup_test).
  238: 
  239: %%-------------------------------------------------------------------------
  240: %% Tests what happens if child's init-callback returns ignore for a
  241: %% temporary child when child is started with start_child/2, and the
  242: %% supervisor is simple_one_for_one.
  243: %% Child spec shall NOT be saved!!!
  244: sup_start_ignore_temporary_child_start_child_simple(Config)
  245:   when is_list(Config) ->
  246:     process_flag(trap_exit, true),
  247:     Child1 = {child1, {supervisor_1, start_child, [ignore]},
  248: 	      temporary, 1000, worker, []},
  249:     {ok, _Pid}  = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child1]}}),
  250: 
  251:     {ok, undefined} = supervisor:start_child(sup_test, []),
  252:     {ok, CPid2} = supervisor:start_child(sup_test, []),
  253: 
  254:     [{undefined, CPid2, worker, []}] = supervisor:which_children(sup_test),
  255:     [1,1,0,1] = get_child_counts(sup_test).
  256: 
  257: %%-------------------------------------------------------------------------
  258: %% Tests what happens if init-callback returns a invalid value.
  259: sup_start_error_return(Config) when is_list(Config) ->
  260:     process_flag(trap_exit, true),
  261:     {error, Term} = start_link(invalid),
  262:     check_exit_reason(Term).
  263: 
  264: %%-------------------------------------------------------------------------
  265: %% Tests what happens if init-callback fails.
  266: sup_start_fail(Config) when is_list(Config) ->
  267:     process_flag(trap_exit, true),
  268:     {error, Term} = start_link(fail),
  269:     check_exit_reason(Term).
  270: 
  271: %%-------------------------------------------------------------------------
  272: %% See sup_stop/1 when Shutdown = infinity, this walue is allowed for
  273: %% children of type supervisor _AND_ worker.
  274: sup_stop_infinity(Config) when is_list(Config) ->
  275:     process_flag(trap_exit, true),
  276:     {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  277:     Child1 = {child1, {supervisor_1, start_child, []}, 
  278: 	      permanent, infinity, supervisor, []},
  279:     Child2 = {child2, {supervisor_1, start_child, []}, permanent,
  280: 	      infinity, worker, []},
  281:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  282:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  283:     link(CPid1),
  284:     link(CPid2),
  285: 
  286:     terminate(Pid, shutdown),
  287:     check_exit_reason(CPid1, shutdown),
  288:     check_exit_reason(CPid2, shutdown).
  289: 
  290: %%-------------------------------------------------------------------------
  291: %% See sup_stop/1 when Shutdown = 1000
  292: sup_stop_timeout(Config) when is_list(Config) ->
  293:     process_flag(trap_exit, true),
  294:     {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  295:     Child1 = {child1, {supervisor_1, start_child, []}, 
  296: 	      permanent, 1000, worker, []},
  297:     Child2 = {child2, {supervisor_1, start_child, []}, permanent,
  298: 	      1000, worker, []},
  299:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  300:     link(CPid1),
  301:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  302:     link(CPid2),
  303: 
  304:     CPid2 ! {sleep, 200000},
  305: 
  306:     terminate(Pid, shutdown),
  307: 
  308:     check_exit_reason(CPid1, shutdown),
  309:     check_exit_reason(CPid2, killed).
  310: 
  311: 
  312: %%-------------------------------------------------------------------------
  313: %% See sup_stop/1 when Shutdown = brutal_kill
  314: sup_stop_brutal_kill(Config) when is_list(Config) ->
  315:     process_flag(trap_exit, true),
  316:     {ok, Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  317:     Child1 = {child1, {supervisor_1, start_child, []}, 
  318: 	      permanent, 1000, worker, []},
  319:     Child2 = {child2, {supervisor_1, start_child, []}, permanent,
  320: 	      brutal_kill, worker, []},
  321:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  322:     link(CPid1),
  323:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  324:     link(CPid2),
  325: 
  326:     terminate(Pid, shutdown),
  327: 
  328:     check_exit_reason(CPid1, shutdown),
  329:     check_exit_reason(CPid2, killed).
  330: 
  331: %%-------------------------------------------------------------------------
  332: %% The start function provided to start a child may return {ok, Pid}
  333: %% or {ok, Pid, Info}, if it returns the latter check that the
  334: %% supervisor ignores the Info, and includes it unchanged in return
  335: %% from start_child/2 and restart_child/2.
  336: extra_return(Config) when is_list(Config) ->
  337:     process_flag(trap_exit, true),
  338:     Child = {child1, {supervisor_1, start_child, [extra_return]}, 
  339: 	     permanent, 1000,
  340: 	     worker, []},
  341:     {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child]}}),
  342:     [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
  343:     link(CPid),
  344:     {error, not_found} = supervisor:terminate_child(sup_test, hej),
  345:     {error, not_found} = supervisor:delete_child(sup_test, hej),
  346:     {error, not_found} = supervisor:restart_child(sup_test, hej),
  347:     {error, running} = supervisor:delete_child(sup_test, child1),
  348:     {error, running} = supervisor:restart_child(sup_test, child1),
  349:     [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
  350:     [1,1,0,1] = get_child_counts(sup_test),
  351: 
  352:     ok = supervisor:terminate_child(sup_test, child1),
  353:     check_exit_reason(CPid, shutdown),
  354:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
  355:     [1,0,0,1] = get_child_counts(sup_test),
  356: 
  357:     {ok, CPid2,extra_return} =
  358: 	supervisor:restart_child(sup_test, child1),
  359:     [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
  360:     [1,1,0,1] = get_child_counts(sup_test),
  361: 
  362:     ok = supervisor:terminate_child(sup_test, child1),
  363:     ok = supervisor:terminate_child(sup_test, child1),
  364:     ok = supervisor:delete_child(sup_test, child1),
  365:     {error, not_found} = supervisor:restart_child(sup_test, child1),
  366:     [] = supervisor:which_children(sup_test),
  367:     [0,0,0,0] = get_child_counts(sup_test),
  368: 
  369:     {ok, CPid3, extra_return} = supervisor:start_child(sup_test, Child),
  370:     [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
  371:     [1,1,0,1] = get_child_counts(sup_test),
  372: 
  373:     ok.
  374: %%-------------------------------------------------------------------------
  375: %% Test API functions start_child/2, terminate_child/2, delete_child/2
  376: %% restart_child/2, which_children/1, count_children/1. Only correct
  377: %% childspecs are used, handling of incorrect childspecs is tested in
  378: %% child_specs/1.
  379: child_adm(Config) when is_list(Config) ->
  380:     process_flag(trap_exit, true),
  381:     Child = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  382: 	     worker, []},
  383:     {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child]}}),
  384:     [{child1, CPid, worker, []}] = supervisor:which_children(sup_test),
  385:     [1,1,0,1] = get_child_counts(sup_test),
  386:     link(CPid),
  387: 
  388:     %% Start of an already runnig process 
  389:     {error,{already_started, CPid}} =
  390: 	supervisor:start_child(sup_test, Child),
  391: 
  392:     %% Termination
  393:     {error, not_found} = supervisor:terminate_child(sup_test, hej),
  394:     {'EXIT',{noproc,{gen_server,call, _}}} =
  395: 	(catch supervisor:terminate_child(foo, child1)),
  396:     ok = supervisor:terminate_child(sup_test, child1),
  397:     check_exit_reason(CPid, shutdown),
  398:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
  399:     [1,0,0,1] = get_child_counts(sup_test),
  400:     %% Like deleting something that does not exist, it will succeed!
  401:     ok = supervisor:terminate_child(sup_test, child1),
  402: 
  403:     %% Start of already existing but not running process 
  404:     {error,already_present} = supervisor:start_child(sup_test, Child),
  405: 
  406:     %% Restart
  407:     {ok, CPid2} = supervisor:restart_child(sup_test, child1),
  408:     [{child1, CPid2, worker, []}] = supervisor:which_children(sup_test),
  409:     [1,1,0,1] = get_child_counts(sup_test),
  410:     {error, running} = supervisor:restart_child(sup_test, child1),
  411:     {error, not_found} = supervisor:restart_child(sup_test, child2),
  412: 
  413:     %% Deletion
  414:     {error, running} = supervisor:delete_child(sup_test, child1),
  415:     {error, not_found} = supervisor:delete_child(sup_test, hej),
  416:     {'EXIT',{noproc,{gen_server,call, _}}} =
  417: 	(catch supervisor:delete_child(foo, child1)),
  418:     ok = supervisor:terminate_child(sup_test, child1),
  419:     ok = supervisor:delete_child(sup_test, child1),
  420:     {error, not_found} = supervisor:restart_child(sup_test, child1),
  421:     [] = supervisor:which_children(sup_test),
  422:     [0,0,0,0] = get_child_counts(sup_test),
  423: 
  424:     %% Start
  425:     {'EXIT',{noproc,{gen_server,call, _}}} =
  426: 	(catch supervisor:start_child(foo, Child)),
  427:     {ok, CPid3} = supervisor:start_child(sup_test, Child),
  428:     [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
  429:     [1,1,0,1] = get_child_counts(sup_test),
  430: 
  431:     %% Terminate with Pid not allowed when not simple_one_for_one
  432:     {error,not_found} = supervisor:terminate_child(sup_test, CPid3),
  433:     [{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
  434:     [1,1,0,1] = get_child_counts(sup_test),
  435: 
  436:     {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
  437: 	= (catch supervisor:which_children(foo)),
  438:     {'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
  439: 	= (catch supervisor:count_children(foo)),
  440:     ok.
  441: %%-------------------------------------------------------------------------
  442: %% The API functions terminate_child/2, delete_child/2 restart_child/2
  443: %% are not valid for a simple_one_for_one supervisor check that the
  444: %% correct error message is returned.
  445: child_adm_simple(Config) when is_list(Config) ->
  446:     Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
  447: 	     worker, []},
  448:     {ok, _Pid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
  449:     %% In simple_one_for_one all children are added dynamically 
  450:     [] = supervisor:which_children(sup_test),
  451:     [1,0,0,0] = get_child_counts(sup_test),
  452: 
  453:     %% Start
  454:     {'EXIT',{noproc,{gen_server,call, _}}} =
  455: 	(catch supervisor:start_child(foo, [])),
  456:     {ok, CPid1} = supervisor:start_child(sup_test, []),
  457:     [{undefined, CPid1, worker, []}] =
  458: 	supervisor:which_children(sup_test),
  459:     [1,1,0,1] = get_child_counts(sup_test),
  460: 
  461:     {ok, CPid2} = supervisor:start_child(sup_test, []),
  462:     Children = supervisor:which_children(sup_test),
  463:     2 = length(Children),
  464:     true = lists:member({undefined, CPid2, worker, []}, Children),
  465:     true = lists:member({undefined, CPid1, worker, []}, Children),
  466:     [1,2,0,2] = get_child_counts(sup_test),
  467: 
  468:     %% Termination
  469:     {error, simple_one_for_one} = supervisor:terminate_child(sup_test, child1),
  470:     [1,2,0,2] = get_child_counts(sup_test),
  471:     ok = supervisor:terminate_child(sup_test,CPid1),
  472:     [_] = supervisor:which_children(sup_test),
  473:     [1,1,0,1] = get_child_counts(sup_test),
  474:     false = erlang:is_process_alive(CPid1),
  475:     %% Terminate non-existing proccess is ok
  476:     ok = supervisor:terminate_child(sup_test,CPid1),
  477:     [_] = supervisor:which_children(sup_test),
  478:     [1,1,0,1] = get_child_counts(sup_test),
  479:     %% Terminate pid which is not a child of this supervisor is not ok
  480:     NoChildPid = spawn_link(fun() -> receive after infinity -> ok end end),
  481:     {error, not_found} = supervisor:terminate_child(sup_test, NoChildPid),
  482:     true = erlang:is_process_alive(NoChildPid),
  483: 
  484:     %% Restart
  485:     {error, simple_one_for_one} = supervisor:restart_child(sup_test, child1),
  486: 
  487:     %% Deletion
  488:     {error, simple_one_for_one} = supervisor:delete_child(sup_test, child1),
  489:     ok.
  490: 
  491: %%-------------------------------------------------------------------------
  492: %% Tests child specs, invalid formats should be rejected.
  493: child_specs(Config) when is_list(Config) ->
  494:     process_flag(trap_exit, true),
  495:     {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  496:     {error, _} = supervisor:start_child(sup_test, hej),
  497: 
  498:     %% Bad child specs 
  499:     B1 = {child, mfa, permanent, 1000, worker, []},
  500:     B2 = {child, {m,f,[a]}, prmanent, 1000, worker, []}, 
  501:     B3 = {child, {m,f,[a]}, permanent, -10, worker, []},
  502:     B4 = {child, {m,f,[a]}, permanent, 10, wrker, []},
  503:     B5 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
  504:     B6 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
  505: 
  506:     %% Correct child specs!
  507:     %% <Modules> (last parameter in a child spec) can be [] as we do 
  508:     %% not test code upgrade here.  
  509:     C1 = {child, {m,f,[a]}, permanent, infinity, supervisor, []},
  510:     C2 = {child, {m,f,[a]}, permanent, 1000, supervisor, []},
  511:     C3 = {child, {m,f,[a]}, temporary, 1000, worker, dynamic},
  512:     C4 = {child, {m,f,[a]}, transient, 1000, worker, [m]},
  513:     C5 = {child, {m,f,[a]}, permanent, infinity, worker, [m]},
  514: 
  515:     {error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
  516:     {error, {invalid_restart_type, prmanent}} =
  517: 	supervisor:start_child(sup_test, B2),
  518:     {error,  {invalid_shutdown,-10}}
  519: 	= supervisor:start_child(sup_test, B3),
  520:     {error, {invalid_child_type,wrker}}
  521: 	= supervisor:start_child(sup_test, B4),
  522:     {error, {invalid_modules,dy}}
  523: 	= supervisor:start_child(sup_test, B5),
  524: 
  525:     {error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
  526:     {error, {invalid_restart_type,prmanent}} =
  527: 	supervisor:check_childspecs([B2]),
  528:     {error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
  529:     {error, {invalid_child_type,wrker}}
  530: 	= supervisor:check_childspecs([B4]),
  531:     {error, {invalid_modules,dy}} = supervisor:check_childspecs([B5]),
  532:     {error, {invalid_module, 1}} =
  533: 	supervisor:check_childspecs([B6]),
  534: 
  535:     ok = supervisor:check_childspecs([C1]),
  536:     ok = supervisor:check_childspecs([C2]),
  537:     ok = supervisor:check_childspecs([C3]),
  538:     ok = supervisor:check_childspecs([C4]),
  539:     ok = supervisor:check_childspecs([C5]),
  540:     ok.
  541: 
  542: %%-------------------------------------------------------------------------
  543: %% A permanent child should always be restarted.
  544: permanent_normal(Config) when is_list(Config) ->
  545:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  546:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  547: 	      worker, []},
  548: 
  549:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  550: 
  551:     terminate(SupPid, CPid1, child1, normal),
  552: 
  553:     [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
  554:     case is_pid(Pid) of
  555: 	true ->
  556: 	    ok;
  557: 	false ->
  558: 	    test_server:fail({permanent_child_not_restarted, Child1})
  559:     end,
  560:     [1,1,0,1] = get_child_counts(sup_test).
  561: 
  562: %%-------------------------------------------------------------------------
  563: %% A transient child should not be restarted if it exits with reason
  564: %% normal.
  565: transient_normal(Config) when is_list(Config) ->
  566:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  567:     Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
  568: 	      worker, []},
  569: 
  570:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  571: 
  572:     terminate(SupPid, CPid1, child1, normal),
  573: 
  574:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
  575:     [1,0,0,1] = get_child_counts(sup_test).
  576: 
  577: %%-------------------------------------------------------------------------
  578: %% A temporary process should never be restarted.
  579: temporary_normal(Config) when is_list(Config) ->
  580:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  581:     Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
  582: 	      worker, []},
  583: 
  584:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  585: 
  586:     terminate(SupPid, CPid1, child1, normal),
  587: 
  588:     [] = supervisor:which_children(sup_test),
  589:     [0,0,0,0] = get_child_counts(sup_test).
  590: 
  591: %%-------------------------------------------------------------------------
  592: %% A permanent child should always be restarted.
  593: permanent_shutdown(Config) when is_list(Config) ->
  594:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  595:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  596: 	      worker, []},
  597: 
  598:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  599: 
  600:     terminate(SupPid, CPid1, child1, shutdown),
  601: 
  602:     [{child1, CPid2 ,worker,[]}] = supervisor:which_children(sup_test),
  603:     case is_pid(CPid2) of
  604: 	true ->
  605: 	    ok;
  606: 	false ->
  607: 	    test_server:fail({permanent_child_not_restarted, Child1})
  608:     end,
  609:     [1,1,0,1] = get_child_counts(sup_test),
  610: 
  611:     terminate(SupPid, CPid2, child1, {shutdown, some_info}),
  612: 
  613:     [{child1, CPid3 ,worker,[]}] = supervisor:which_children(sup_test),
  614:     case is_pid(CPid3) of
  615: 	true ->
  616: 	    ok;
  617: 	false ->
  618: 	    test_server:fail({permanent_child_not_restarted, Child1})
  619:     end,
  620: 
  621:     [1,1,0,1] = get_child_counts(sup_test).
  622: 
  623: %%-------------------------------------------------------------------------
  624: %% A transient child should not be restarted if it exits with reason
  625: %% shutdown or {shutdown,Term}.
  626: transient_shutdown(Config) when is_list(Config) ->
  627:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  628:     Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
  629: 	      worker, []},
  630: 
  631:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  632: 
  633:     terminate(SupPid, CPid1, child1, shutdown),
  634: 
  635:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
  636:     [1,0,0,1] = get_child_counts(sup_test),
  637: 
  638:     {ok, CPid2} = supervisor:restart_child(sup_test, child1),
  639: 
  640:     terminate(SupPid, CPid2, child1, {shutdown, some_info}),
  641: 
  642:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
  643:     [1,0,0,1] = get_child_counts(sup_test).
  644: 
  645: %%-------------------------------------------------------------------------
  646: %% A temporary process should never be restarted.
  647: temporary_shutdown(Config) when is_list(Config) ->
  648:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  649:     Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
  650: 	      worker, []},
  651: 
  652:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  653: 
  654:     terminate(SupPid, CPid1, child1, shutdown),
  655: 
  656:     [] = supervisor:which_children(sup_test),
  657:     [0,0,0,0] = get_child_counts(sup_test),
  658: 
  659:     {ok, CPid2} = supervisor:start_child(sup_test, Child1),
  660: 
  661:     terminate(SupPid, CPid2, child1, {shutdown, some_info}),
  662: 
  663:     [] = supervisor:which_children(sup_test),
  664:     [0,0,0,0] = get_child_counts(sup_test).
  665: 
  666: %%-------------------------------------------------------------------------
  667: %% Faulty application should shutdown and pass on errors
  668: faulty_application_shutdown(Config) when is_list(Config) ->
  669: 
  670:     %% Set some paths
  671:     AppDir  = filename:join(?config(data_dir, Config), "app_faulty"),
  672:     EbinDir = filename:join(AppDir, "ebin"),
  673: 
  674:     %% Start faulty app
  675:     code:add_patha(EbinDir),
  676: 
  677:     %% {error,
  678:     %%  {{shutdown,
  679:     %%    {failed_to_start_child,
  680:     %% 	app_faulty,
  681:     %% 	{undef,
  682:     %% 	 [{an_undefined_module_with,an_undefined_function,[argument1,argument2],
  683:     %% 	   []},
  684:     %% 	  {app_faulty_server,init,1,
  685:     %% 	   [{file,"app_faulty/src/app_faulty_server.erl"},{line,16}]},
  686:     %% 	  {gen_server,init_it,6,
  687:     %% 	   [{file,"gen_server.erl"},{line,304}]},
  688:     %% 	  {proc_lib,init_p_do_apply,3,
  689:     %% 	   [{file,"proc_lib.erl"},{line,227}]}]}}},
  690:     %%   {app_faulty,start,[normal,[]]}}}
  691: 
  692:     {error, Error} = application:start(app_faulty),
  693:     {{shutdown, {failed_to_start_child,app_faulty,{undef, CallStack}}},
  694:      {app_faulty,start,_}} = Error,
  695:     [{an_undefined_module_with,an_undefined_function,_,_}|_] = CallStack,
  696:     ok = application:unload(app_faulty),
  697:     ok.
  698: 
  699: %%-------------------------------------------------------------------------
  700: %% A permanent child should always be restarted.
  701: permanent_abnormal(Config) when is_list(Config) ->
  702:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  703:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  704: 	      worker, []},
  705: 
  706:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  707:     terminate(SupPid, CPid1, child1, abnormal),
  708: 
  709:     [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
  710:     case is_pid(Pid) of
  711: 	true ->
  712: 	    ok;
  713: 	false ->
  714: 	    test_server:fail({permanent_child_not_restarted, Child1})
  715:     end,
  716:     [1,1,0,1] = get_child_counts(sup_test).
  717: 
  718: %%-------------------------------------------------------------------------
  719: %% A transient child should be restarted if it exits with reason abnormal.
  720: transient_abnormal(Config) when is_list(Config) ->
  721:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  722:     Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
  723: 	      worker, []},
  724: 
  725:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  726:     terminate(SupPid, CPid1, child1, abnormal),
  727: 
  728:     [{child1, Pid ,worker,[]}] = supervisor:which_children(sup_test),
  729:     case is_pid(Pid) of
  730: 	true ->
  731: 	    ok;
  732: 	false ->
  733: 	    test_server:fail({transient_child_not_restarted, Child1})
  734:     end,
  735:     [1,1,0,1] = get_child_counts(sup_test).
  736: 
  737: %%-------------------------------------------------------------------------
  738: %% A temporary process should never be restarted.
  739: temporary_abnormal(Config) when is_list(Config) ->
  740:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  741:     Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
  742: 	      worker, []},
  743: 
  744:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  745:     terminate(SupPid, CPid1, child1, abnormal),
  746: 
  747:     [] = supervisor:which_children(sup_test),
  748:     [0,0,0,0] = get_child_counts(sup_test).
  749: 
  750: %%-------------------------------------------------------------------------
  751: %% A temporary process killed as part of a rest_for_one or one_for_all
  752: %% restart strategy should not be restarted given its args are not
  753: %% saved. Otherwise the supervisor hits its limit and crashes.
  754: temporary_bystander(_Config) ->
  755:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 100,
  756: 	      worker, []},
  757:     Child2 = {child2, {supervisor_1, start_child, []}, temporary, 100,
  758: 	      worker, []},
  759:     {ok, SupPid1} = supervisor:start_link(?MODULE, {ok, {{one_for_all, 2, 300}, []}}),
  760:     {ok, SupPid2} = supervisor:start_link(?MODULE, {ok, {{rest_for_one, 2, 300}, []}}),
  761:     unlink(SupPid1), % otherwise we crash with it
  762:     unlink(SupPid2), % otherwise we crash with it
  763:     {ok, CPid1} = supervisor:start_child(SupPid1, Child1),
  764:     {ok, _CPid2} = supervisor:start_child(SupPid1, Child2),
  765:     {ok, CPid3} = supervisor:start_child(SupPid2, Child1),
  766:     {ok, _CPid4} = supervisor:start_child(SupPid2, Child2),
  767:     terminate(SupPid1, CPid1, child1, normal),
  768:     terminate(SupPid2, CPid3, child1, normal),
  769:     timer:sleep(350),
  770:     catch link(SupPid1),
  771:     catch link(SupPid2),
  772:     %% The supervisor would die attempting to restart child2
  773:     true = erlang:is_process_alive(SupPid1),
  774:     true = erlang:is_process_alive(SupPid2),
  775:     %% Child2 has not been restarted
  776:     [{child1, _, _, _}] = supervisor:which_children(SupPid1),
  777:     [{child1, _, _, _}] = supervisor:which_children(SupPid2).
  778: 
  779: %%-------------------------------------------------------------------------
  780: %% Test the one_for_one base case.
  781: one_for_one(Config) when is_list(Config) ->
  782:     process_flag(trap_exit, true),
  783:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  784: 	      worker, []},
  785:     Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
  786: 	      worker, []},
  787:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
  788:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  789:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  790: 
  791:     terminate(SupPid, CPid1, child1, abnormal),
  792:     Children = supervisor:which_children(sup_test),
  793:     if length(Children) == 2 ->
  794: 	    case lists:keysearch(CPid2, 2, Children) of
  795: 		{value, _} -> ok;
  796: 		_ ->  test_server:fail(bad_child)
  797: 	    end;
  798:        true ->  test_server:fail({bad_child_list, Children})
  799:     end,
  800:     [2,2,0,2] = get_child_counts(sup_test),
  801: 
  802:     %% Test restart frequency property
  803:     terminate(SupPid, CPid2, child2, abnormal),
  804: 
  805:     [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
  806:     terminate(SupPid, Pid4, Id4, abnormal),
  807:     check_exit([SupPid]).
  808: 
  809: %%-------------------------------------------------------------------------
  810: %% Test restart escalation on a one_for_one supervisor.
  811: one_for_one_escalation(Config) when is_list(Config) ->
  812:     process_flag(trap_exit, true),
  813: 
  814:     Child1 = {child1, {supervisor_1, start_child, [error]},
  815: 	      permanent, 1000,
  816: 	      worker, []},
  817:     Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
  818: 	      worker, []},
  819: 
  820:     {ok, SupPid} = start_link({ok, {{one_for_one, 4, 3600}, []}}),
  821:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  822:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  823:     link(CPid2),
  824: 
  825:     terminate(SupPid, CPid1, child1, abnormal),
  826:     check_exit([SupPid, CPid2]).
  827: 
  828: 
  829: %%-------------------------------------------------------------------------
  830: %% Test the one_for_all base case.
  831: one_for_all(Config) when is_list(Config) ->
  832:     process_flag(trap_exit, true),
  833: 
  834:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  835: 	     worker, []},
  836:     Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
  837: 	     worker, []},
  838:     {ok, SupPid} = start_link({ok, {{one_for_all, 2, 3600}, []}}),
  839:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  840:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  841:     link(CPid2),
  842: 
  843:     terminate(SupPid, CPid1, child1, abnormal),
  844:     check_exit([CPid2]),
  845: 
  846:     Children = supervisor:which_children(sup_test),
  847:     if length(Children) == 2 -> ok;
  848:        true ->
  849: 	    test_server:fail({bad_child_list, Children})
  850:     end,
  851: 
  852:     %% Test that no old children is still alive
  853:     not_in_child_list([CPid1, CPid2], lists:map(fun({_,P,_,_}) -> P end, Children)),
  854: 
  855:     [2,2,0,2] = get_child_counts(sup_test),
  856: 
  857:     %%% Test restart frequency property
  858:     [{Id3, Pid3, _, _}|_] = supervisor:which_children(sup_test),
  859:     terminate(SupPid, Pid3, Id3, abnormal),
  860:     [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
  861:     terminate(SupPid, Pid4, Id4, abnormal),
  862:     check_exit([SupPid]).
  863: 
  864: 
  865: %%-------------------------------------------------------------------------
  866: %% Test restart escalation on a one_for_all supervisor.
  867: one_for_all_escalation(Config) when is_list(Config) ->
  868:     process_flag(trap_exit, true),
  869: 
  870:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
  871: 	     worker, []},
  872:     Child2 = {child2, {supervisor_1, start_child, [error]},
  873: 	      permanent, 1000,
  874: 	     worker, []},
  875:     {ok, SupPid} = start_link({ok, {{one_for_all, 4, 3600}, []}}),
  876:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
  877:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
  878:     link(CPid2),
  879: 
  880:     terminate(SupPid, CPid1, child1, abnormal),
  881:     check_exit([CPid2, SupPid]).
  882: 
  883: 
  884: %%-------------------------------------------------------------------------
  885: %% Test that the supervisor terminates a restarted child when a different
  886: %% child fails to start.
  887: one_for_all_other_child_fails_restart(Config) when is_list(Config) ->
  888:     process_flag(trap_exit, true),
  889:     Self = self(),
  890:     Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
  891: 	      permanent, 1000, worker, []},
  892:     Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
  893: 	      permanent, 1000, worker, []},
  894:     Children = [Child1, Child2],
  895:     StarterFun = fun() ->
  896: 	    {ok, SupPid} = start_link({ok, {{one_for_all, 3, 3600}, Children}}),
  897: 	    Self ! {sup_pid, SupPid},
  898: 	    receive {stop, Self} -> ok end
  899:     end,
  900:     StarterPid = spawn_link(StarterFun),
  901:     Ok = {{ok, undefined}, Self},
  902:     %% Let the children start.
  903:     Child1Pid = receive {child1, Pid1} -> Pid1 end,
  904:     Child1Pid ! Ok,
  905:     Child2Pid = receive {child2, Pid2} -> Pid2 end,
  906:     Child2Pid ! Ok,
  907:     %% Supervisor started.
  908:     SupPid = receive {sup_pid, Pid} -> Pid end,
  909:     link(SupPid),
  910:     exit(Child1Pid, die),
  911:     %% Let child1 restart but don't let child2.
  912:     Child1Pid2  = receive {child1, Pid3} -> Pid3 end,
  913:     Child1Pid2Ref = erlang:monitor(process, Child1Pid2),
  914:     Child1Pid2 ! Ok,
  915:     Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
  916:     Child2Pid2 ! {{stop, normal}, Self},
  917:     %% Check child1 is terminated.
  918:     receive
  919: 	{'DOWN', Child1Pid2Ref, _, _, shutdown} ->
  920: 	    ok;
  921: 	{_childName, _Pid} ->
  922: 	    exit(SupPid, kill),
  923: 	    check_exit([StarterPid, SupPid]),
  924: 	    test_server:fail({restarting_child_not_terminated, Child1Pid2})
  925:     end,
  926:     %% Let the restart complete.
  927:     Child1Pid3 = receive {child1, Pid5} -> Pid5 end,
  928:     Child1Pid3 ! Ok,
  929:     Child2Pid3 = receive {child2, Pid6} -> Pid6 end,
  930:     Child2Pid3 ! Ok,
  931:     StarterPid ! {stop, Self},
  932:     check_exit([StarterPid, SupPid]).
  933: 
  934: 
  935: %%-------------------------------------------------------------------------
  936: %% Test the simple_one_for_one base case.
  937: simple_one_for_one(Config) when is_list(Config) ->
  938:     process_flag(trap_exit, true),
  939:     Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
  940: 	     worker, []},
  941:     {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
  942:     {ok, CPid1} = supervisor:start_child(sup_test, []),
  943:     {ok, CPid2} = supervisor:start_child(sup_test, []),
  944: 
  945:     terminate(SupPid, CPid1, child1, abnormal),
  946: 
  947:     Children = supervisor:which_children(sup_test),
  948:     if length(Children) == 2 ->
  949: 	    case lists:keysearch(CPid2, 2, Children) of
  950: 		{value, _} -> ok;
  951: 		_ ->  test_server:fail(bad_child)
  952: 	    end;
  953:        true ->  test_server:fail({bad_child_list, Children})
  954:     end,
  955:     [1,2,0,2] = get_child_counts(sup_test),
  956: 
  957:     %% Test restart frequency property
  958:     terminate(SupPid, CPid2, child2, abnormal),
  959: 
  960:     [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
  961: 
  962:     terminate(SupPid, Pid4, Id4, abnormal),
  963:     check_exit([SupPid]).
  964: 
  965: 
  966: %%-------------------------------------------------------------------------
  967: %% Test simple_one_for_one children shutdown accordingly to the
  968: %% supervisor's shutdown strategy.
  969: simple_one_for_one_shutdown(Config) when is_list(Config) ->
  970:     process_flag(trap_exit, true),
  971:     ShutdownTime = 1000,
  972:     Child = {child, {supervisor_2, start_child, []},
  973:              permanent, 2*ShutdownTime, worker, []},
  974:     {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
  975: 
  976:     %% Will be gracefully shutdown
  977:     {ok, _CPid1} = supervisor:start_child(sup_test, [ShutdownTime]),
  978:     {ok, _CPid2} = supervisor:start_child(sup_test, [ShutdownTime]),
  979: 
  980:     %% Will be killed after 2*ShutdownTime milliseconds
  981:     {ok, _CPid3} = supervisor:start_child(sup_test, [5*ShutdownTime]),
  982: 
  983:     {T, ok} = timer:tc(fun terminate/2, [SupPid, shutdown]),
  984:     if T < 1000*ShutdownTime ->
  985:             %% Because supervisor's children wait before exiting, it can't
  986:             %% terminate quickly
  987:             test_server:fail({shutdown_too_short, T});
  988:        T >= 1000*5*ShutdownTime ->
  989:             test_server:fail({shutdown_too_long, T});
  990:        true ->
  991:             check_exit([SupPid])
  992:     end.
  993: 
  994: 
  995: %%-------------------------------------------------------------------------
  996: %% Tests automatic restart of children who's start function return
  997: %% extra info.
  998: simple_one_for_one_extra(Config) when is_list(Config) ->
  999:     process_flag(trap_exit, true),
 1000:     Child = {child, {supervisor_1, start_child, [extra_info]}, 
 1001: 	     permanent, 1000, worker, []},
 1002:     {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
 1003:     {ok, CPid1, extra_info} = supervisor:start_child(sup_test, []),
 1004:     {ok, CPid2, extra_info} = supervisor:start_child(sup_test, []),
 1005:     link(CPid2),
 1006:     terminate(SupPid, CPid1, child1, abnormal),
 1007:     Children = supervisor:which_children(sup_test),
 1008:     if length(Children) == 2 ->
 1009: 	    case lists:keysearch(CPid2, 2, Children) of
 1010: 		{value, _} -> ok;
 1011: 		_ ->  test_server:fail(bad_child)
 1012: 	    end;
 1013:        true ->  test_server:fail({bad_child_list, Children})
 1014:     end,
 1015:     [1,2,0,2] = get_child_counts(sup_test),
 1016:     terminate(SupPid, CPid2, child2, abnormal),
 1017:     [{Id4, Pid4, _, _}|_] = supervisor:which_children(sup_test),
 1018:     terminate(SupPid, Pid4, Id4, abnormal),
 1019:     check_exit([SupPid]).
 1020: 
 1021: %%-------------------------------------------------------------------------
 1022: %% Test restart escalation on a simple_one_for_one supervisor.
 1023: simple_one_for_one_escalation(Config) when is_list(Config) ->
 1024:     process_flag(trap_exit, true),
 1025:     Child = {child, {supervisor_1, start_child, []}, permanent, 1000,
 1026: 	     worker, []},
 1027:     {ok, SupPid} = start_link({ok, {{simple_one_for_one, 4, 3600}, [Child]}}),
 1028:     {ok, CPid1} = supervisor:start_child(sup_test, [error]),
 1029:     link(CPid1),
 1030:     {ok, CPid2} = supervisor:start_child(sup_test, []),
 1031:     link(CPid2),
 1032: 
 1033:     terminate(SupPid, CPid1, child, abnormal),
 1034:     check_exit([SupPid, CPid2]).
 1035: 
 1036: %%-------------------------------------------------------------------------
 1037: %% Test the rest_for_one base case.
 1038: rest_for_one(Config) when is_list(Config) ->
 1039:     process_flag(trap_exit, true),
 1040:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
 1041: 	     worker, []},
 1042:     Child2 = {child2, {supervisor_1, start_child, []}, permanent, 1000,
 1043: 	     worker, []},
 1044:     Child3 = {child3, {supervisor_1, start_child, []}, permanent, 1000,
 1045: 	     worker, []},
 1046:     {ok, SupPid} = start_link({ok, {{rest_for_one, 2, 3600}, []}}),
 1047:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
 1048:     link(CPid1),
 1049:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
 1050:     {ok, CPid3} = supervisor:start_child(sup_test, Child3),
 1051:     link(CPid3),
 1052:     [3,3,0,3] = get_child_counts(sup_test),
 1053: 
 1054:     terminate(SupPid, CPid2, child2, abnormal),
 1055: 
 1056:     %% Check that Cpid3 did die
 1057:     check_exit([CPid3]),
 1058: 
 1059:     Children = supervisor:which_children(sup_test),
 1060:     is_in_child_list([CPid1], Children),
 1061: 
 1062:     if length(Children) == 3 ->
 1063: 	    ok;
 1064:        true ->
 1065: 	    test_server:fail({bad_child_list, Children})
 1066:     end,
 1067:     [3,3,0,3] = get_child_counts(sup_test),
 1068: 
 1069:     %% Test that no old children is still alive
 1070:     Pids = lists:map(fun({_,P,_,_}) -> P end, Children),
 1071:     not_in_child_list([CPid2, CPid3], Pids),
 1072:     in_child_list([CPid1], Pids),
 1073: 
 1074:     %% Test restart frequency property
 1075:     [{child3, Pid3, _, _}|_] = supervisor:which_children(sup_test),
 1076: 
 1077:     terminate(SupPid, Pid3, child3, abnormal),
 1078: 
 1079:     [_,{child2, Pid4, _, _}|_] = supervisor:which_children(sup_test),
 1080: 
 1081:     terminate(SupPid, Pid4, child2, abnormal),
 1082:     check_exit([SupPid]).
 1083: 
 1084: %%-------------------------------------------------------------------------
 1085: %% Test restart escalation on a rest_for_one supervisor.
 1086: rest_for_one_escalation(Config) when is_list(Config) ->
 1087:     process_flag(trap_exit, true),
 1088:     Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
 1089: 	     worker, []},
 1090:     Child2 = {child2, {supervisor_1, start_child, [error]},
 1091: 	      permanent, 1000,
 1092: 	     worker, []},
 1093:     {ok, SupPid} = start_link({ok, {{rest_for_one, 4, 3600}, []}}),
 1094:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
 1095:     {ok, CPid2} = supervisor:start_child(sup_test, Child2),
 1096:     link(CPid2),
 1097: 
 1098:     terminate(SupPid, CPid1, child1, abnormal),
 1099:     check_exit([CPid2, SupPid]).
 1100: 
 1101: 
 1102: %%-------------------------------------------------------------------------
 1103: %% Test that the supervisor terminates a restarted child when a different
 1104: %% child fails to start.
 1105: rest_for_one_other_child_fails_restart(Config) when is_list(Config) ->
 1106:     process_flag(trap_exit, true),
 1107:     Self = self(),
 1108:     Child1 = {child1, {supervisor_3, start_child, [child1, Self]},
 1109: 	      permanent, 1000, worker, []},
 1110:     Child2 = {child2, {supervisor_3, start_child, [child2, Self]},
 1111: 	      permanent, 1000, worker, []},
 1112:     Children = [Child1, Child2],
 1113:     StarterFun = fun() ->
 1114: 	    {ok, SupPid} = start_link({ok, {{rest_for_one, 3, 3600}, Children}}),
 1115: 	    Self ! {sup_pid, SupPid},
 1116: 	    receive {stop, Self} -> ok end
 1117:     end,
 1118:     StarterPid = spawn_link(StarterFun),
 1119:     Ok = {{ok, undefined}, Self},
 1120:     %% Let the children start.
 1121:     Child1Pid = receive {child1, Pid1} -> Pid1 end,
 1122:     Child1Pid ! Ok,
 1123:     Child2Pid = receive {child2, Pid2} -> Pid2 end,
 1124:     Child2Pid ! Ok,
 1125:     %% Supervisor started.
 1126:     SupPid = receive {sup_pid, Pid} -> Pid end,
 1127:     link(SupPid),
 1128:     exit(Child1Pid, die),
 1129:     %% Let child1 restart but don't let child2.
 1130:     Child1Pid2  = receive {child1, Pid3} -> Pid3 end,
 1131:     Child1Pid2 ! Ok,
 1132:     Child2Pid2 = receive {child2, Pid4} -> Pid4 end,
 1133:     Child2Pid2 ! {{stop, normal}, Self},
 1134: 	%% Let child2 restart.
 1135:     receive
 1136: 	{child2, Child2Pid3} ->
 1137: 	    Child2Pid3 ! Ok;
 1138: 	{child1, _Child1Pid3} ->
 1139: 	    exit(SupPid, kill),
 1140: 	    check_exit([StarterPid, SupPid]),
 1141: 	    test_server:fail({restarting_started_child, Child1Pid2})
 1142:     end,
 1143:     StarterPid ! {stop, Self},
 1144:     check_exit([StarterPid, SupPid]).
 1145: 
 1146: 
 1147: %%-------------------------------------------------------------------------
 1148: %% Test that the supervisor does not hang forever if the child unliks
 1149: %% and then is terminated by the supervisor.
 1150: child_unlink(Config) when is_list(Config) ->
 1151: 
 1152:     {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
 1153: 
 1154:     Child = {naughty_child, {naughty_child, 
 1155: 			     start_link, [SupPid]}, permanent, 
 1156: 	     1000, worker, [supervisor_SUITE]},
 1157: 
 1158:     {ok, _ChildPid} = supervisor:start_child(sup_test, Child),
 1159: 
 1160:     Pid = spawn(supervisor, terminate_child, [SupPid, naughty_child]),
 1161: 
 1162:     SupPid ! foo,
 1163:     timer:sleep(5000),
 1164:     %% If the supervisor did not hang it will have got rid of the 
 1165:     %% foo message that we sent.
 1166:     case erlang:process_info(SupPid, message_queue_len) of
 1167: 	{message_queue_len, 0}->
 1168: 	    ok;
 1169: 	_ ->
 1170: 	    exit(Pid, kill),
 1171: 	    test_server:fail(supervisor_hangs)
 1172:     end.
 1173: %%-------------------------------------------------------------------------
 1174: %% Test a basic supervison tree.
 1175: tree(Config) when is_list(Config) ->
 1176:     process_flag(trap_exit, true),
 1177: 
 1178:     Child1 = {child1, {supervisor_1, start_child, []},
 1179: 	      permanent, 1000,
 1180: 	      worker, []},
 1181:     Child2 = {child2, {supervisor_1, start_child, []},
 1182: 	      permanent, 1000,
 1183: 	      worker, []},
 1184:     Child3 = {child3, {supervisor_1, start_child, [error]},
 1185: 	      permanent, 1000,
 1186: 	      worker, []},
 1187:     Child4 = {child4, {supervisor_1, start_child, []},
 1188: 	      permanent, 1000,
 1189: 	      worker, []},
 1190: 
 1191:     ChildSup1 = {supchild1, 
 1192: 		 {supervisor, start_link,
 1193: 		  [?MODULE, {ok, {{one_for_one, 4, 3600}, [Child1, Child2]}}]},
 1194: 		 permanent, infinity,
 1195: 		 supervisor, []},
 1196:     ChildSup2 = {supchild2, 
 1197: 		 {supervisor, start_link, 
 1198: 		  [?MODULE, {ok, {{one_for_one, 4, 3600}, []}}]},
 1199: 		 permanent, infinity,
 1200: 		 supervisor, []},
 1201: 
 1202:     %% Top supervisor
 1203:     {ok, SupPid} = start_link({ok, {{one_for_all, 4, 3600}, []}}),
 1204: 
 1205:     %% Child supervisors  
 1206:     {ok, Sup1} = supervisor:start_child(SupPid, ChildSup1),
 1207:     {ok, Sup2} = supervisor:start_child(SupPid, ChildSup2),
 1208:     [2,2,2,0] = get_child_counts(SupPid),
 1209: 
 1210:     %% Workers
 1211:     [{_, CPid2, _, _},{_, CPid1, _, _}] =
 1212: 	supervisor:which_children(Sup1),
 1213:     [2,2,0,2] = get_child_counts(Sup1),
 1214:     [0,0,0,0] = get_child_counts(Sup2),
 1215: 
 1216:     %% Dynamic children
 1217:     {ok, CPid3} = supervisor:start_child(Sup2, Child3),
 1218:     {ok, CPid4} = supervisor:start_child(Sup2, Child4),
 1219:     [2,2,0,2] = get_child_counts(Sup1),
 1220:     [2,2,0,2] = get_child_counts(Sup2),
 1221: 
 1222:     %% Test that the only the process that dies is restarted
 1223:     terminate(Sup2, CPid4, child4, abnormal),
 1224: 
 1225:     [{_, CPid2, _, _},{_, CPid1, _, _}] =
 1226: 	supervisor:which_children(Sup1),
 1227:     [2,2,0,2] = get_child_counts(Sup1),
 1228: 
 1229:     [{_, NewCPid4, _, _},{_, CPid3, _, _}] =
 1230: 	supervisor:which_children(Sup2),
 1231:     [2,2,0,2] = get_child_counts(Sup2),
 1232: 
 1233:     false = NewCPid4 == CPid4,
 1234: 
 1235:     %% Test that supervisor tree is restarted, but not dynamic children.
 1236:     terminate(Sup2, CPid3, child3, abnormal),
 1237: 
 1238:     timer:sleep(1000),
 1239: 
 1240:     [{supchild2, NewSup2, _, _},{supchild1, NewSup1, _, _}] =
 1241: 	supervisor:which_children(SupPid),
 1242:     [2,2,2,0] = get_child_counts(SupPid),
 1243: 
 1244:     [{child2, _, _, _},{child1, _, _, _}]  =
 1245: 	supervisor:which_children(NewSup1),
 1246:     [2,2,0,2] = get_child_counts(NewSup1),
 1247: 
 1248:     [] = supervisor:which_children(NewSup2),
 1249:     [0,0,0,0] = get_child_counts(NewSup2).
 1250: 
 1251: %%-------------------------------------------------------------------------
 1252: %% Test that count_children does not eat memory.
 1253: count_children_memory(Config) when is_list(Config) ->
 1254:     process_flag(trap_exit, true),
 1255:     Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
 1256: 	     worker, []},
 1257:     {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
 1258:     [supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
 1259: 
 1260:     garbage_collect(),
 1261:     _Size1 = proc_memory(),
 1262:     Children = supervisor:which_children(sup_test),
 1263:     _Size2 = proc_memory(),
 1264:     ChildCount = get_child_counts(sup_test),
 1265:     _Size3 = proc_memory(),
 1266: 
 1267:     [supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
 1268: 
 1269:     garbage_collect(),
 1270:     Children2 = supervisor:which_children(sup_test),
 1271:     Size4 = proc_memory(),
 1272:     ChildCount2 = get_child_counts(sup_test),
 1273:     Size5 = proc_memory(),
 1274: 
 1275:     garbage_collect(),
 1276:     Children3 = supervisor:which_children(sup_test),
 1277:     Size6 = proc_memory(),
 1278:     ChildCount3 = get_child_counts(sup_test),
 1279:     Size7 = proc_memory(),
 1280: 
 1281:     1000 = length(Children),
 1282:     [1,1000,0,1000] = ChildCount,
 1283:     2000 = length(Children2),
 1284:     [1,2000,0,2000] = ChildCount2,
 1285:     Children3 = Children2,
 1286:     ChildCount3 = ChildCount2,
 1287: 
 1288:     %% count_children consumes memory using an accumulator function,
 1289:     %% but the space can be reclaimed incrementally,
 1290:     %% which_children may generate garbage that will be reclaimed later.
 1291:     case (Size5 =< Size4) of
 1292: 	true -> ok;
 1293: 	false ->
 1294: 	    test_server:fail({count_children, used_more_memory,Size4,Size5})
 1295:     end,
 1296:     case Size7 =< Size6 of
 1297: 	true -> ok;
 1298: 	false ->
 1299: 	    test_server:fail({count_children, used_more_memory,Size6,Size7})
 1300:     end,
 1301: 
 1302:     [terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3],
 1303:     [1,0,0,0] = get_child_counts(sup_test).
 1304: 
 1305: proc_memory() ->
 1306:     erts_debug:set_internal_state(wait, deallocations),
 1307:     erlang:memory(processes_used).
 1308: 
 1309: %%-------------------------------------------------------------------------
 1310: %% Temporary children shall not be restarted so they should not save
 1311: %% start parameters, as it potentially can take up a huge amount of
 1312: %% memory for no purpose.
 1313: do_not_save_start_parameters_for_temporary_children(Config) when is_list(Config) ->
 1314:     process_flag(trap_exit, true),
 1315:     dont_save_start_parameters_for_temporary_children(one_for_all),
 1316:     dont_save_start_parameters_for_temporary_children(one_for_one),
 1317:     dont_save_start_parameters_for_temporary_children(rest_for_one),
 1318:     dont_save_start_parameters_for_temporary_children(simple_one_for_one).
 1319: 
 1320: start_children(_,_, 0) ->
 1321:     ok;
 1322: start_children(Sup, Args, N) ->
 1323:     Spec = child_spec(Args, N),
 1324:     {ok, _, _} = supervisor:start_child(Sup, Spec),
 1325:     start_children(Sup, Args, N-1).
 1326: 
 1327: child_spec([_|_] = SimpleOneForOneArgs, _) ->
 1328:     SimpleOneForOneArgs;
 1329: child_spec({Name, MFA, RestartType, Shutdown, Type, Modules}, N) ->
 1330:     NewName = list_to_atom((atom_to_list(Name) ++ integer_to_list(N))),
 1331:     {NewName, MFA, RestartType, Shutdown, Type, Modules}.
 1332: 
 1333: %%-------------------------------------------------------------------------
 1334: %% Temporary children shall not be restarted so supervisors should not
 1335: %% save their spec when they terminate.
 1336: do_not_save_child_specs_for_temporary_children(Config) when is_list(Config) ->
 1337:     process_flag(trap_exit, true),
 1338:     dont_save_child_specs_for_temporary_children(one_for_all, kill),
 1339:     dont_save_child_specs_for_temporary_children(one_for_one, kill),
 1340:     dont_save_child_specs_for_temporary_children(rest_for_one, kill),
 1341: 
 1342:     dont_save_child_specs_for_temporary_children(one_for_all, normal),
 1343:     dont_save_child_specs_for_temporary_children(one_for_one, normal),
 1344:     dont_save_child_specs_for_temporary_children(rest_for_one, normal),
 1345: 
 1346:     dont_save_child_specs_for_temporary_children(one_for_all, abnormal),
 1347:     dont_save_child_specs_for_temporary_children(one_for_one, abnormal),
 1348:     dont_save_child_specs_for_temporary_children(rest_for_one, abnormal),
 1349: 
 1350:     dont_save_child_specs_for_temporary_children(one_for_all, supervisor),
 1351:     dont_save_child_specs_for_temporary_children(one_for_one, supervisor),
 1352:     dont_save_child_specs_for_temporary_children(rest_for_one, supervisor).
 1353: 
 1354: %%-------------------------------------------------------------------------
 1355: dont_save_start_parameters_for_temporary_children(simple_one_for_one = Type) ->
 1356:     Permanent = {child, {supervisor_1, start_child, []},
 1357: 		 permanent, 1000, worker, []},
 1358:     Transient = {child, {supervisor_1, start_child, []},
 1359: 		 transient, 1000, worker, []},
 1360:     Temporary = {child, {supervisor_1, start_child, []},
 1361: 		 temporary, 1000, worker, []},
 1362:     {ok, Sup1} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, [Permanent]}}),
 1363:     {ok, Sup2} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, [Transient]}}),
 1364:     {ok, Sup3} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, [Temporary]}}),
 1365: 
 1366:     LargeList = lists:duplicate(10, "Potentially large"),
 1367: 
 1368:     start_children(Sup1, [LargeList], 100),
 1369:     start_children(Sup2, [LargeList], 100),
 1370:     start_children(Sup3, [LargeList], 100),
 1371: 
 1372:     [{memory,Mem1}] = process_info(Sup1, [memory]),
 1373:     [{memory,Mem2}] = process_info(Sup2, [memory]),
 1374:     [{memory,Mem3}] = process_info(Sup3, [memory]),
 1375: 
 1376:     true = (Mem3 < Mem1)  and  (Mem3 < Mem2),
 1377: 
 1378:     terminate(Sup1, shutdown),
 1379:     terminate(Sup2, shutdown),
 1380:     terminate(Sup3, shutdown);
 1381: 
 1382: dont_save_start_parameters_for_temporary_children(Type) ->
 1383:     {ok, Sup1} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
 1384:     {ok, Sup2} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
 1385:     {ok, Sup3} = supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
 1386: 
 1387:     LargeList = lists:duplicate(10, "Potentially large"),
 1388: 
 1389:     Permanent = {child1, {supervisor_1, start_child, [LargeList]},
 1390: 		 permanent, 1000, worker, []},
 1391:     Transient = {child2, {supervisor_1, start_child, [LargeList]},
 1392: 		 transient, 1000, worker, []},
 1393:     Temporary = {child3, {supervisor_1, start_child, [LargeList]},
 1394: 		 temporary, 1000, worker, []},
 1395: 
 1396:     start_children(Sup1, Permanent, 100),
 1397:     start_children(Sup2, Transient, 100),
 1398:     start_children(Sup3, Temporary, 100),
 1399: 
 1400:     [{memory,Mem1}] = process_info(Sup1, [memory]),
 1401:     [{memory,Mem2}] = process_info(Sup2, [memory]),
 1402:     [{memory,Mem3}] = process_info(Sup3, [memory]),
 1403: 
 1404:     true = (Mem3 < Mem1)  and  (Mem3 < Mem2),
 1405: 
 1406:     terminate(Sup1, shutdown),
 1407:     terminate(Sup2, shutdown),
 1408:     terminate(Sup3, shutdown).
 1409: 
 1410: dont_save_child_specs_for_temporary_children(Type, TerminateHow)->
 1411:     {ok, Sup} =
 1412: 	supervisor:start_link(?MODULE, {ok, {{Type, 2, 3600}, []}}),
 1413: 
 1414:     Permanent = {child1, {supervisor_1, start_child, []},
 1415: 		 permanent, 1000, worker, []},
 1416:     Transient = {child2, {supervisor_1, start_child, []},
 1417: 		 transient, 1000, worker, []},
 1418:     Temporary = {child3, {supervisor_1, start_child, []},
 1419: 		 temporary, 1000, worker, []},
 1420: 
 1421:     permanent_child_spec_saved(Permanent, Sup, TerminateHow),
 1422: 
 1423:     transient_child_spec_saved(Transient, Sup, TerminateHow),
 1424: 
 1425:     temporary_child_spec_not_saved(Temporary, Sup, TerminateHow),
 1426: 
 1427:     terminate(Sup, shutdown).
 1428: 
 1429: permanent_child_spec_saved(ChildSpec, Sup, supervisor = TerminateHow) ->
 1430:     already_present(Sup, ChildSpec, TerminateHow);
 1431: 
 1432: permanent_child_spec_saved(ChildSpec, Sup, TerminateHow) ->
 1433:     restarted(Sup, ChildSpec, TerminateHow).
 1434: 
 1435: transient_child_spec_saved(ChildSpec, Sup, supervisor = TerminateHow) ->
 1436:     already_present(Sup, ChildSpec, TerminateHow);
 1437: 
 1438: transient_child_spec_saved(ChildSpec, Sup, normal = TerminateHow) ->
 1439:     already_present(Sup, ChildSpec, TerminateHow);
 1440: 
 1441: transient_child_spec_saved(ChildSpec, Sup, TerminateHow) ->
 1442:     restarted(Sup, ChildSpec, TerminateHow).
 1443: 
 1444: temporary_child_spec_not_saved({Id, _,_,_,_,_} = ChildSpec, Sup, TerminateHow) ->
 1445:     {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
 1446:     terminate(Sup, Pid, Id, TerminateHow),
 1447:     {ok, _} = supervisor:start_child(Sup, ChildSpec).
 1448: 
 1449: already_present(Sup, {Id,_,_,_,_,_} = ChildSpec, TerminateHow) ->
 1450:     {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
 1451:     terminate(Sup, Pid, Id, TerminateHow),
 1452:     {error, already_present} = supervisor:start_child(Sup, ChildSpec),
 1453:     {ok, _} = supervisor:restart_child(Sup, Id).
 1454: 
 1455: restarted(Sup, {Id,_,_,_,_,_} = ChildSpec, TerminateHow) ->
 1456:     {ok, Pid} = supervisor:start_child(Sup, ChildSpec),
 1457:     terminate(Sup, Pid, Id, TerminateHow),
 1458:     %% Permanent processes will be restarted by the supervisor
 1459:     %% when not terminated by api
 1460:     {error, {already_started, _}} = supervisor:start_child(Sup, ChildSpec).
 1461: 
 1462: 
 1463: %%-------------------------------------------------------------------------
 1464: %% OTP-9242: Pids for dynamic temporary children were saved as a list,
 1465: %% which caused bad scaling when adding/deleting many processes.
 1466: simple_one_for_one_scale_many_temporary_children(_Config) ->
 1467:     process_flag(trap_exit, true),
 1468:     Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
 1469: 	     worker, []},
 1470:     {ok, _SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
 1471: 
 1472:     C1 = [begin 
 1473: 		 {ok,P} = supervisor:start_child(sup_test,[]), 
 1474: 		 P
 1475: 	     end || _<- lists:seq(1,1000)],
 1476:     {T1,done} = timer:tc(?MODULE,terminate_all_children,[C1]),
 1477:     
 1478:     C2 = [begin 
 1479: 		 {ok,P} = supervisor:start_child(sup_test,[]), 
 1480: 		 P
 1481: 	     end || _<- lists:seq(1,10000)],
 1482:     {T2,done} = timer:tc(?MODULE,terminate_all_children,[C2]),
 1483:     
 1484:     if T1 > 0 ->
 1485: 	    Scaling = T2 div T1,
 1486: 	    if Scaling > 20 ->
 1487: 		    %% The scaling shoul be linear (i.e.10, really), but we
 1488: 		    %% give some extra here to avoid failing the test
 1489: 		    %% unecessarily.
 1490: 		    ?t:fail({bad_scaling,Scaling});
 1491: 	       true ->
 1492: 		    ok
 1493: 	    end;
 1494:        true ->
 1495: 	    %% Means T2 div T1 -> infinity
 1496: 	    ok
 1497:     end.
 1498:     
 1499: 
 1500: terminate_all_children([C|Cs]) ->
 1501:     ok = supervisor:terminate_child(sup_test,C),
 1502:     terminate_all_children(Cs);
 1503: terminate_all_children([]) ->
 1504:     done.
 1505: 
 1506: 
 1507: %%-------------------------------------------------------------------------
 1508: %% OTP-9212. Restart of global supervisor.
 1509: simple_global_supervisor(_Config) ->
 1510:     kill_supervisor(),
 1511:     kill_worker(),
 1512:     exit_worker(),
 1513:     restart_worker(),
 1514:     ok.
 1515: 
 1516: kill_supervisor() ->
 1517:     {Top, Sup2_1, Server_1} = start9212(),
 1518: 
 1519:     %% Killing a supervisor isn't really supported, but try it anyway...
 1520:     exit(Sup2_1, kill),
 1521:     timer:sleep(200),
 1522:     Sup2_2 = global:whereis_name(sup2),
 1523:     Server_2 = global:whereis_name(server),
 1524:     true = is_pid(Sup2_2),
 1525:     true = is_pid(Server_2),
 1526:     true = Sup2_1 =/= Sup2_2,
 1527:     true = Server_1 =/= Server_2,
 1528: 
 1529:     stop9212(Top).
 1530: 
 1531: handle_info({fail, With, After}, _State) ->
 1532:     timer:sleep(After),
 1533:     erlang:error(With).
 1534: 
 1535: kill_worker() ->
 1536:     {Top, _Sup2, Server_1} = start9212(),
 1537:     exit(Server_1, kill),
 1538:     timer:sleep(200),
 1539:     Server_2 = global:whereis_name(server),
 1540:     true = is_pid(Server_2),
 1541:     true = Server_1 =/= Server_2,
 1542:     stop9212(Top).
 1543: 
 1544: exit_worker() ->
 1545:     %% Very much the same as kill_worker().
 1546:     {Top, _Sup2, Server_1} = start9212(),
 1547:     Server_1 ! {fail, normal, 0},
 1548:     timer:sleep(200),
 1549:     Server_2 = global:whereis_name(server),
 1550:     true = is_pid(Server_2),
 1551:     true = Server_1 =/= Server_2,
 1552:     stop9212(Top).
 1553: 
 1554: restart_worker() ->
 1555:     {Top, _Sup2, Server_1} = start9212(),
 1556:     ok = supervisor:terminate_child({global, sup2}, child),
 1557:     {ok, _Child} = supervisor:restart_child({global, sup2}, child),
 1558:     Server_2 = global:whereis_name(server),
 1559:     true = is_pid(Server_2),
 1560:     true = Server_1 =/= Server_2,
 1561:     stop9212(Top).
 1562: 
 1563: start9212() ->
 1564:     Middle = {middle,{?MODULE,middle9212,[]}, permanent,2000,supervisor,[]},
 1565:     InitResult = {ok, {{one_for_all,3,60}, [Middle]}},
 1566:     {ok, TopPid} = start_link(InitResult),
 1567: 
 1568:     Sup2 = global:whereis_name(sup2),
 1569:     Server = global:whereis_name(server),
 1570:     true = is_pid(Sup2),
 1571:     true = is_pid(Server),
 1572:     {TopPid, Sup2, Server}.
 1573: 
 1574: stop9212(Top) ->
 1575:     Old = process_flag(trap_exit, true),
 1576:     exit(Top, kill),
 1577:     timer:sleep(200),
 1578:     undefined = global:whereis_name(sup2),
 1579:     undefined = global:whereis_name(server),
 1580:     check_exit([Top]),
 1581:     _ = process_flag(trap_exit, Old),
 1582:     ok.
 1583: 
 1584: middle9212() ->
 1585:     Child = {child, {?MODULE,gen_server9212,[]},permanent, 2000, worker, []},
 1586:     InitResult = {ok, {{one_for_all,3,60}, [Child]}},
 1587:     supervisor:start_link({global,sup2}, ?MODULE, InitResult).
 1588: 
 1589: gen_server9212() ->
 1590:     InitResult = {ok, []},
 1591:     gen_server:start_link({global,server}, ?MODULE, InitResult, []).
 1592: 
 1593: 
 1594: %%-------------------------------------------------------------------------
 1595: %% Test that child and supervisor can be shutdown while hanging in restart loop.
 1596: %% See OTP-9549.
 1597: hanging_restart_loop(Config) when is_list(Config) ->
 1598:     process_flag(trap_exit, true),
 1599:     {ok, Pid} = start_link({ok, {{one_for_one, 8, 10}, []}}),
 1600:     Child1 = {child1, {supervisor_deadlock, start_child, []},
 1601: 	      permanent, brutal_kill, worker, []},
 1602: 
 1603:     %% Ets table with state read by supervisor_deadlock.erl
 1604:     ets:new(supervisor_deadlock,[set,named_table,public]),
 1605:     ets:insert(supervisor_deadlock,{fail_start,false}),
 1606: 
 1607:     {ok, CPid1} = supervisor:start_child(sup_test, Child1),
 1608:     link(CPid1),
 1609: 
 1610:     ets:insert(supervisor_deadlock,{fail_start,true}),
 1611:     supervisor_deadlock:restart_child(),
 1612:     timer:sleep(2000), % allow restart to happen before proceeding
 1613: 
 1614:     {error, already_present} = supervisor:start_child(sup_test, Child1),
 1615:     {error, restarting} = supervisor:restart_child(sup_test, child1),
 1616:     {error, restarting} = supervisor:delete_child(sup_test, child1),
 1617:     [{child1,restarting,worker,[]}] = supervisor:which_children(sup_test),
 1618:     [1,0,0,1] = get_child_counts(sup_test),
 1619: 
 1620:     ok = supervisor:terminate_child(sup_test, child1),
 1621:     check_exit_reason(CPid1, error),
 1622:     [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
 1623: 
 1624:     ets:insert(supervisor_deadlock,{fail_start,false}),
 1625:     {ok, CPid2} = supervisor:restart_child(sup_test, child1),
 1626:     link(CPid2),
 1627: 
 1628:     ets:insert(supervisor_deadlock,{fail_start,true}),
 1629:     supervisor_deadlock:restart_child(),
 1630:     timer:sleep(2000), % allow restart to happen before proceeding
 1631: 
 1632:     %% Terminating supervisor.
 1633:     %% OTP-9549 fixes so this does not give a timetrap timeout -
 1634:     %% i.e. that supervisor does not hang in restart loop.
 1635:     terminate(Pid,shutdown),
 1636: 
 1637:     %% Check that child died with reason from 'restart' request above
 1638:     check_exit_reason(CPid2, error),
 1639:     undefined = whereis(sup_test),
 1640:     ok.
 1641: 
 1642: %%-------------------------------------------------------------------------
 1643: %% Test that child and supervisor can be shutdown while hanging in
 1644: %% restart loop, simple_one_for_one.
 1645: %% See OTP-9549.
 1646: hanging_restart_loop_simple(Config) when is_list(Config) ->
 1647:     process_flag(trap_exit, true),
 1648:     Child1 = {child1, {supervisor_deadlock, start_child, []},
 1649: 	      permanent, brutal_kill, worker, []},
 1650:     {ok, Pid} = start_link({ok, {{simple_one_for_one, 8, 10}, [Child1]}}),
 1651: 
 1652:     %% Ets table with state read by supervisor_deadlock.erl
 1653:     ets:new(supervisor_deadlock,[set,named_table,public]),
 1654:     ets:insert(supervisor_deadlock,{fail_start,false}),
 1655: 
 1656:     {ok, CPid1} = supervisor:start_child(sup_test, []),
 1657:     link(CPid1),
 1658: 
 1659:     ets:insert(supervisor_deadlock,{fail_start,true}),
 1660:     supervisor_deadlock:restart_child(),
 1661:     timer:sleep(2000), % allow restart to happen before proceeding
 1662: 
 1663:     {error, simple_one_for_one} = supervisor:restart_child(sup_test, child1),
 1664:     {error, simple_one_for_one} = supervisor:delete_child(sup_test, child1),
 1665:     [{undefined,restarting,worker,[]}] = supervisor:which_children(sup_test),
 1666:     [1,0,0,1] = get_child_counts(sup_test),
 1667: 
 1668:     ok = supervisor:terminate_child(sup_test, CPid1),
 1669:     check_exit_reason(CPid1, error),
 1670:     [] = supervisor:which_children(sup_test),
 1671: 
 1672:     ets:insert(supervisor_deadlock,{fail_start,false}),
 1673:     {ok, CPid2} = supervisor:start_child(sup_test, []),
 1674:     link(CPid2),
 1675: 
 1676:     ets:insert(supervisor_deadlock,{fail_start,true}),
 1677:     supervisor_deadlock:restart_child(),
 1678:     timer:sleep(2000), % allow restart to happen before proceeding
 1679: 
 1680:     %% Terminating supervisor.
 1681:     %% OTP-9549 fixes so this does not give a timetrap timeout -
 1682:     %% i.e. that supervisor does not hang in restart loop.
 1683:     terminate(Pid,shutdown),
 1684: 
 1685:     %% Check that child died with reason from 'restart' request above
 1686:     check_exit_reason(CPid2, error),
 1687:     undefined = whereis(sup_test),
 1688:     ok.
 1689: 
 1690: %%-------------------------------------------------------------------------
 1691: terminate(Pid, Reason) when Reason =/= supervisor ->
 1692:     terminate(dummy, Pid, dummy, Reason).
 1693: 
 1694: terminate(Sup, _, ChildId, supervisor) ->
 1695:     ok = supervisor:terminate_child(Sup, ChildId);
 1696: terminate(_, ChildPid, _, kill) ->
 1697:     Ref = erlang:monitor(process, ChildPid),
 1698:     exit(ChildPid, kill),
 1699:     receive
 1700: 	{'DOWN', Ref, process, ChildPid, killed} ->
 1701: 	    ok
 1702:     end;
 1703: terminate(_, ChildPid, _, shutdown) ->
 1704:     Ref = erlang:monitor(process, ChildPid),
 1705:     exit(ChildPid, shutdown),
 1706:     receive
 1707: 	{'DOWN', Ref, process, ChildPid, shutdown} ->
 1708: 	    ok
 1709:     end;
 1710: terminate(_, ChildPid, _, {shutdown, Term}) ->
 1711:     Ref = erlang:monitor(process, ChildPid),
 1712:     exit(ChildPid, {shutdown, Term}),
 1713:     receive
 1714: 	{'DOWN', Ref, process, ChildPid, {shutdown, Term}} ->
 1715: 	    ok
 1716:     end;
 1717: terminate(_, ChildPid, _, normal) ->
 1718:     Ref = erlang:monitor(process, ChildPid),
 1719:     ChildPid ! stop,
 1720:     receive
 1721: 	{'DOWN', Ref, process, ChildPid, normal} ->
 1722: 	    ok
 1723:     end;
 1724: terminate(_, ChildPid, _,abnormal) ->
 1725:     Ref = erlang:monitor(process, ChildPid),
 1726:     ChildPid ! die,
 1727:     receive
 1728: 	{'DOWN', Ref, process, ChildPid, died} ->
 1729: 	    ok
 1730:     end.
 1731: 
 1732: in_child_list([], _) ->
 1733:     true;
 1734: in_child_list([Pid | Rest], Pids) ->
 1735:     case is_in_child_list(Pid, Pids) of
 1736: 	true ->
 1737: 	    in_child_list(Rest, Pids);
 1738: 	false ->
 1739: 	    test_server:fail(child_should_be_alive)
 1740:     end.
 1741: not_in_child_list([], _) ->
 1742:     true;
 1743: not_in_child_list([Pid | Rest], Pids) ->
 1744:     case is_in_child_list(Pid, Pids) of
 1745: 	true ->
 1746: 	    test_server:fail(child_should_not_be_alive);
 1747: 	false ->
 1748: 	    not_in_child_list(Rest, Pids)
 1749:     end.
 1750: 
 1751: is_in_child_list(Pid, ChildPids) ->
 1752:     lists:member(Pid, ChildPids).
 1753: 
 1754: check_exit([]) ->
 1755:     ok;
 1756: check_exit([Pid | Pids]) ->
 1757:     receive
 1758: 	{'EXIT', Pid, _} ->
 1759: 	    check_exit(Pids)
 1760:     end.
 1761: 
 1762: check_exit_reason(Reason) ->
 1763:     receive
 1764: 	{'EXIT', _, Reason} ->
 1765: 	    ok;
 1766: 	{'EXIT', _, Else} ->
 1767: 	    test_server:fail({bad_exit_reason, Else})
 1768:     end.
 1769: 
 1770: check_exit_reason(Pid, Reason) ->
 1771:     receive
 1772: 	{'EXIT', Pid, Reason} ->
 1773: 	    ok;
 1774: 	{'EXIT', Pid, Else} ->
 1775: 	    test_server:fail({bad_exit_reason, Else})
 1776:     end.