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: -module(gen_server_SUITE).
   20: 
   21: -include_lib("test_server/include/test_server.hrl").
   22: -include_lib("kernel/include/inet.hrl").
   23: 
   24: -export([init_per_testcase/2, end_per_testcase/2]).
   25: 
   26: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   27: 	 init_per_group/2,end_per_group/2]).
   28: -export([start/1, crash/1, call/1, cast/1, cast_fast/1,
   29: 	 info/1, abcast/1, multicall/1, multicall_down/1,
   30: 	 call_remote1/1, call_remote2/1, call_remote3/1,
   31: 	 call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1,
   32: 	 spec_init_local_registered_parent/1, 
   33: 	 spec_init_global_registered_parent/1,
   34: 	 otp_5854/1, hibernate/1, otp_7669/1, call_format_status/1,
   35: 	 error_format_status/1, get_state/1, replace_state/1, call_with_huge_message_queue/1
   36: 	]).
   37: 
   38: % spawn export
   39: -export([spec_init_local/2, spec_init_global/2, spec_init_via/2,
   40: 	 spec_init_default_timeout/2, spec_init_global_default_timeout/2,
   41:          spec_init_anonymous/1,
   42: 	 spec_init_anonymous_default_timeout/1,
   43: 	 spec_init_not_proc_lib/1, cast_fast_messup/0]).
   44: 
   45: 
   46: % The gen_server behaviour
   47: -export([init/1, handle_call/3, handle_cast/2,
   48: 	 handle_info/2, terminate/2, format_status/2]).
   49: 
   50: suite() -> [{ct_hooks,[ts_install_cth]}].
   51: 
   52: all() -> 
   53:     [start, crash, call, cast, cast_fast, info, abcast,
   54:      multicall, multicall_down, call_remote1, call_remote2,
   55:      call_remote3, call_remote_n1, call_remote_n2,
   56:      call_remote_n3, spec_init,
   57:      spec_init_local_registered_parent,
   58:      spec_init_global_registered_parent, otp_5854, hibernate,
   59:      otp_7669, call_format_status, error_format_status,
   60:      get_state, replace_state,
   61:      call_with_huge_message_queue].
   62: 
   63: groups() -> 
   64:     [].
   65: 
   66: init_per_suite(Config) ->
   67:     Config.
   68: 
   69: end_per_suite(_Config) ->
   70:     ok.
   71: 
   72: init_per_group(_GroupName, Config) ->
   73:     Config.
   74: 
   75: end_per_group(_GroupName, Config) ->
   76:     Config.
   77: 
   78: 
   79: -define(default_timeout, ?t:minutes(1)).
   80:  
   81: init_per_testcase(Case, Config) when Case == call_remote1;
   82: 				     Case == call_remote2;
   83: 				     Case == call_remote3;
   84: 				     Case == call_remote_n1;
   85: 				     Case == call_remote_n2;
   86: 				     Case == call_remote_n3 ->
   87:     {ok,N} = start_node(hubba),
   88:     ?line Dog = ?t:timetrap(?default_timeout),
   89:     [{node,N},{watchdog, Dog} | Config];
   90: init_per_testcase(_Case, Config) ->
   91:     ?line Dog = ?t:timetrap(?default_timeout),
   92:     [{watchdog, Dog} | Config].
   93: end_per_testcase(_Case, Config) ->
   94:     case proplists:get_value(node, Config) of
   95: 	undefined ->
   96: 	    ok;
   97: 	N ->
   98: 	    test_server:stop_node(N)
   99:     end,
  100:     Dog = ?config(watchdog, Config),
  101:     test_server:timetrap_cancel(Dog),
  102:     ok.
  103: 
  104: 
  105: %% --------------------------------------
  106: %% Start and stop a gen_server.
  107: %% --------------------------------------
  108: 
  109: start(suite) -> [];
  110: start(Config) when is_list(Config) ->
  111:     OldFl = process_flag(trap_exit, true),
  112: 
  113:     %% anonymous
  114:     ?line {ok, Pid0} = gen_server:start(gen_server_SUITE, [], []),
  115:     ?line ok = gen_server:call(Pid0, started_p),
  116:     ?line ok = gen_server:call(Pid0, stop),
  117:     ?line busy_wait_for_process(Pid0,600),
  118:     ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid0, started_p, 1)),
  119: 
  120:     %% anonymous with timeout
  121:     ?line {ok, Pid00} = gen_server:start(gen_server_SUITE, [],
  122: 					 [{timeout,1000}]),
  123:     ?line ok = gen_server:call(Pid00, started_p),
  124:     ?line ok = gen_server:call(Pid00, stop),
  125:     ?line {error, timeout} = gen_server:start(gen_server_SUITE, sleep,
  126: 					      [{timeout,100}]),
  127: 
  128:     %% anonymous with ignore
  129:     ?line ignore = gen_server:start(gen_server_SUITE, ignore, []),
  130: 
  131:     %% anonymous with stop
  132:     ?line {error, stopped} = gen_server:start(gen_server_SUITE, stop, []),
  133: 
  134:     %% anonymous linked
  135:     ?line {ok, Pid1} =
  136: 	gen_server:start_link(gen_server_SUITE, [], []),
  137:     ?line ok = gen_server:call(Pid1, started_p),
  138:     ?line ok = gen_server:call(Pid1, stop),
  139:     ?line receive
  140: 	      {'EXIT', Pid1, stopped} ->
  141: 		  ok
  142: 	  after 5000 ->
  143: 		  test_server:fail(not_stopped)
  144: 	  end,
  145: 
  146:     %% local register
  147:     ?line {ok, Pid2} =
  148: 	gen_server:start({local, my_test_name},
  149: 			 gen_server_SUITE, [], []),
  150:     ?line ok = gen_server:call(my_test_name, started_p),
  151:     ?line {error, {already_started, Pid2}} =
  152: 	gen_server:start({local, my_test_name},
  153: 			 gen_server_SUITE, [], []),
  154:     ?line ok = gen_server:call(my_test_name, stop),
  155: 
  156:     ?line busy_wait_for_process(Pid2,600),
  157: 
  158:     ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid2, started_p, 10)),
  159: 
  160:     %% local register linked
  161:     ?line {ok, Pid3} =
  162: 	gen_server:start_link({local, my_test_name},
  163: 			      gen_server_SUITE, [], []), 
  164:     ?line ok = gen_server:call(my_test_name, started_p),
  165:     ?line {error, {already_started, Pid3}} =
  166: 	gen_server:start({local, my_test_name},
  167: 			 gen_server_SUITE, [], []),
  168:     ?line ok = gen_server:call(my_test_name, stop),
  169:     ?line receive
  170: 	      {'EXIT', Pid3, stopped} ->
  171: 		  ok
  172: 	  after 5000 ->
  173: 		  test_server:fail(not_stopped)
  174: 	  end,
  175: 
  176:     %% global register
  177:     ?line {ok, Pid4} =
  178: 	gen_server:start({global, my_test_name},
  179: 			 gen_server_SUITE, [], []),
  180:     ?line ok = gen_server:call({global, my_test_name}, started_p),
  181:     ?line {error, {already_started, Pid4}} =
  182: 	gen_server:start({global, my_test_name},
  183: 			 gen_server_SUITE, [], []),
  184:     ?line ok = gen_server:call({global, my_test_name}, stop),
  185:     test_server:sleep(1),
  186:     ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid4, started_p, 10)),
  187: 
  188:     %% global register linked
  189:     ?line {ok, Pid5} =
  190: 	gen_server:start_link({global, my_test_name},
  191: 			      gen_server_SUITE, [], []), 
  192:     ?line ok = gen_server:call({global, my_test_name}, started_p),
  193:     ?line {error, {already_started, Pid5}} =
  194: 	gen_server:start({global, my_test_name},
  195: 			 gen_server_SUITE, [], []),
  196:     ?line ok = gen_server:call({global, my_test_name}, stop),
  197:     ?line receive
  198: 	      {'EXIT', Pid5, stopped} ->
  199: 		  ok
  200: 	  after 5000 ->
  201: 		  test_server:fail(not_stopped)
  202: 	  end,
  203: 
  204:     %% via register
  205:     ?line dummy_via:reset(),
  206:     ?line {ok, Pid6} =
  207: 	gen_server:start({via, dummy_via, my_test_name},
  208: 			 gen_server_SUITE, [], []),
  209:     ?line ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
  210:     ?line {error, {already_started, Pid6}} =
  211: 	gen_server:start({via, dummy_via, my_test_name},
  212: 			 gen_server_SUITE, [], []),
  213:     ?line ok = gen_server:call({via, dummy_via, my_test_name}, stop),
  214:     test_server:sleep(1),
  215:     ?line {'EXIT', {noproc,_}} = (catch gen_server:call(Pid6, started_p, 10)),
  216: 
  217:     %% via register linked
  218:     ?line dummy_via:reset(),
  219:     ?line {ok, Pid7} =
  220: 	gen_server:start_link({via, dummy_via, my_test_name},
  221: 			      gen_server_SUITE, [], []),
  222:     ?line ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
  223:     ?line {error, {already_started, Pid7}} =
  224: 	gen_server:start({via, dummy_via, my_test_name},
  225: 			 gen_server_SUITE, [], []),
  226:     ?line ok = gen_server:call({via, dummy_via, my_test_name}, stop),
  227:     ?line receive
  228: 	      {'EXIT', Pid7, stopped} ->
  229: 		  ok
  230: 	  after 5000 ->
  231: 		  test_server:fail(not_stopped)
  232: 	  end,
  233:     test_server:messages_get(),
  234: 
  235:     process_flag(trap_exit, OldFl),
  236:     ok.
  237: 
  238: crash(Config) when is_list(Config) ->
  239:     ?line error_logger_forwarder:register(),
  240: 
  241:     process_flag(trap_exit, true),
  242: 
  243:     %% This crash should not generate a crash report.
  244:     ?line {ok,Pid0} = gen_server:start_link(?MODULE, [], []),
  245:     ?line {'EXIT',{{shutdown,reason},_}} =
  246:  	(catch gen_server:call(Pid0, shutdown_reason)),
  247:     receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
  248: 
  249:     %% This crash should not generate a crash report.
  250:     ?line {ok,Pid1} = gen_server:start_link(?MODULE, {state,state1}, []),
  251:     ?line {'EXIT',{{shutdown,stop_reason},_}} =
  252: 	(catch gen_server:call(Pid1, stop_shutdown_reason)),
  253:     receive {'EXIT',Pid1,{shutdown,stop_reason}} -> ok end,
  254: 
  255:     %% This crash should not generate a crash report.
  256:     ?line {ok,Pid2} = gen_server:start_link(?MODULE, [], []),
  257:     ?line {'EXIT',{shutdown,_}} =
  258:  	(catch gen_server:call(Pid2, exit_shutdown)),
  259:     receive {'EXIT',Pid2,shutdown} -> ok end,
  260: 
  261:     %% This crash should not generate a crash report.
  262:     ?line {ok,Pid3} = gen_server:start_link(?MODULE, {state,state3}, []),
  263:     ?line {'EXIT',{shutdown,_}} =
  264: 	(catch gen_server:call(Pid3, stop_shutdown)),
  265:     receive {'EXIT',Pid3,shutdown} -> ok end,
  266: 
  267:     process_flag(trap_exit, false),
  268: 
  269:     %% This crash should generate a crash report and a report
  270:     %% from gen_server.
  271:     ?line {ok,Pid4} = gen_server:start(?MODULE, {state,state4}, []),
  272:     ?line {'EXIT',{crashed,_}} = (catch gen_server:call(Pid4, crash)),
  273:     receive
  274: 	{error,_GroupLeader4,{Pid4,
  275: 			      "** Generic server"++_,
  276: 			      [Pid4,crash,state4,crashed]}} ->
  277: 	    ok;
  278: 	Other4a ->
  279:  	    ?line io:format("Unexpected: ~p", [Other4a]),
  280:  	    ?line ?t:fail()
  281:     end,
  282:     receive
  283: 	{error_report,_,{Pid4,crash_report,[List4|_]}} ->
  284: 	    {exit,crashed,_} = proplists:get_value(error_info, List4),
  285: 	    Pid4 = proplists:get_value(pid, List4);
  286: 	Other4 ->
  287: 	    ?line io:format("Unexpected: ~p", [Other4]),
  288: 	    ?line ?t:fail()
  289:     end,
  290: 
  291:     receive
  292: 	Any ->
  293: 	    ?line io:format("Unexpected: ~p", [Any]),
  294: 	    ?line ?t:fail()
  295:     after 500 ->
  296: 	    ok
  297:     end,
  298: 
  299:     ok.
  300: 
  301: %% --------------------------------------
  302: %% Test gen_server:call and handle_call.
  303: %% Test all different return values from
  304: %% handle_call.
  305: %% --------------------------------------
  306: 
  307: call(suite) -> [];
  308: call(Config) when is_list(Config) ->
  309:     OldFl = process_flag(trap_exit, true),
  310: 
  311:     ?line {ok, _Pid} =
  312: 	gen_server:start_link({local, my_test_name},
  313: 			      gen_server_SUITE, [], []),
  314: 
  315:     ?line ok = gen_server:call(my_test_name, started_p),
  316:     ?line delayed = gen_server:call(my_test_name, {delayed_answer,1}),
  317: 
  318:     %% two requests within a specified time.
  319:     ?line ok = gen_server:call(my_test_name, {call_within, 1000}),
  320:     test_server:sleep(500),
  321:     ?line ok = gen_server:call(my_test_name, next_call),
  322:     ?line ok = gen_server:call(my_test_name, {call_within, 1000}),
  323:     test_server:sleep(1500),
  324:     ?line false = gen_server:call(my_test_name, next_call),
  325:     
  326:     %% timeout call.
  327:     ?line delayed = gen_server:call(my_test_name, {delayed_answer,1}, 30),
  328:     ?line {'EXIT',{timeout,_}} =
  329: 	(catch gen_server:call(my_test_name, {delayed_answer,30}, 1)),
  330: 
  331:     %% bad return value in the gen_server loop from handle_call.
  332:     ?line {'EXIT',{{bad_return_value, badreturn},_}} =
  333: 	(catch gen_server:call(my_test_name, badreturn)),
  334: 
  335:     process_flag(trap_exit, OldFl),
  336:     ok.
  337: 
  338: %% --------------------------------------
  339: %% Test call to nonexisting processes on remote nodes
  340: %% --------------------------------------
  341: 
  342: start_node(Name) ->
  343:     ?line Pa = filename:dirname(code:which(?MODULE)),
  344:     ?line N = test_server:start_node(Name, slave, [{args, " -pa " ++ Pa}]),
  345:     %% After starting a slave, it takes a little while until global knows
  346:     %% about it, even if nodes() includes it, so we make sure that global
  347:     %% knows about it before registering something on all nodes.
  348:     global:sync(),
  349:     N.
  350: 
  351: call_remote1(suite) -> [];
  352: call_remote1(Config) when is_list(Config) ->
  353:     N = hubba,
  354:     ?line Node = proplists:get_value(node,Config),
  355:     ?line {ok, Pid} = rpc:call(Node, gen_server, start,
  356: 			       [{global, N}, ?MODULE, [], []]),    
  357:     ?line ok = (catch gen_server:call({global, N}, started_p, infinity)),
  358:     ?line exit(Pid, boom),
  359:     ?line {'EXIT', {Reason, _}} = (catch gen_server:call({global, N},
  360: 							 started_p, infinity)),
  361:     ?line true = (Reason == noproc) orelse (Reason == boom),
  362:     ok.
  363: 
  364: call_remote2(suite) -> [];
  365: call_remote2(Config) when is_list(Config) ->
  366:     ?line N = hubba,
  367:     ?line Node = proplists:get_value(node,Config),
  368: 
  369:     ?line {ok, Pid} = rpc:call(Node, gen_server, start,
  370: 			       [{global, N}, ?MODULE, [], []]),
  371:     ?line ok = (catch gen_server:call(Pid, started_p, infinity)),
  372:     ?line exit(Pid, boom),
  373:     ?line {'EXIT', {Reason, _}} = (catch gen_server:call(Pid,
  374: 							 started_p, infinity)),
  375:     ?line true = (Reason == noproc) orelse (Reason == boom),
  376:     ok.
  377: 
  378: call_remote3(suite) -> [];
  379: call_remote3(Config) when is_list(Config) ->
  380:     ?line Node = proplists:get_value(node,Config),
  381: 
  382:     ?line {ok, Pid} = rpc:call(Node, gen_server, start,
  383: 			       [{local, piller}, ?MODULE, [], []]),
  384:     ?line ok = (catch gen_server:call({piller, Node}, started_p, infinity)),
  385:     ?line exit(Pid, boom),
  386:     ?line {'EXIT', {Reason, _}} = (catch gen_server:call({piller, Node},
  387: 							 started_p, infinity)),
  388:     ?line true = (Reason == noproc) orelse (Reason == boom),
  389:     ok.
  390: 
  391: %% --------------------------------------
  392: %% Test call to nonexisting node
  393: %% --------------------------------------
  394: 
  395: call_remote_n1(suite) -> [];
  396: call_remote_n1(Config) when is_list(Config) ->
  397:     ?line N = hubba,
  398:     ?line Node = proplists:get_value(node,Config),    
  399:     ?line {ok, _Pid} = rpc:call(Node, gen_server, start,
  400: 			       [{global, N}, ?MODULE, [], []]),
  401:     ?line _ = test_server:stop_node(Node),
  402:     ?line {'EXIT', {noproc, _}} =
  403: 	(catch gen_server:call({global, N}, started_p, infinity)),
  404: 
  405:     ok.
  406: 
  407: call_remote_n2(suite) -> [];
  408: call_remote_n2(Config) when is_list(Config) ->
  409:     ?line N = hubba,
  410:     ?line Node = proplists:get_value(node,Config),
  411: 
  412:     ?line {ok, Pid} = rpc:call(Node, gen_server, start,
  413: 			       [{global, N}, ?MODULE, [], []]),
  414:     ?line _ = test_server:stop_node(Node),
  415:     ?line {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call(Pid,
  416: 							 started_p, infinity)),
  417: 
  418:     ok.
  419: 
  420: call_remote_n3(suite) -> [];
  421: call_remote_n3(Config) when is_list(Config) ->
  422:     ?line Node = proplists:get_value(node,Config),
  423: 
  424:     ?line {ok, _Pid} = rpc:call(Node, gen_server, start,
  425: 			       [{local, piller}, ?MODULE, [], []]),
  426:     ?line _ = test_server:stop_node(Node),
  427:     ?line {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call({piller, Node},
  428: 							 started_p, infinity)),
  429: 
  430:     ok.
  431: 
  432: %% --------------------------------------
  433: %% Test gen_server:cast and handle_cast.
  434: %% Test all different return values from
  435: %% handle_cast.
  436: %% --------------------------------------
  437: 
  438: cast(suite) -> [];
  439: cast(Config) when is_list(Config) ->
  440:     ?line {ok, Pid} =
  441: 	gen_server:start({local, my_test_name},
  442: 			 gen_server_SUITE, [], []),
  443: 
  444:     ?line ok = gen_server:call(my_test_name, started_p),
  445: 
  446:     ?line ok = gen_server:cast(my_test_name, {self(),handle_cast}),
  447:     ?line receive
  448: 	      {Pid, handled_cast} ->
  449: 		  ok
  450: 	  after 1000 ->
  451: 		  test_server:fail(handle_cast)
  452: 	  end,
  453:     
  454:     ?line ok = gen_server:cast(my_test_name, {self(),delayed_cast,1}),
  455:     ?line receive
  456: 	      {Pid, delayed} ->
  457: 		  ok
  458: 	  after 1000 ->
  459: 		  test_server:fail(delayed_cast)
  460: 	  end,
  461:     
  462:     ?line ok = gen_server:cast(my_test_name, {self(),stop}),
  463:     ?line receive
  464: 	      {Pid, stopped} ->
  465: 		  ok
  466: 	  after 1000 ->
  467: 		  test_server:fail(stop)
  468: 	  end,
  469:     ok.
  470: 
  471: cast_fast(suite) -> [];
  472: cast_fast(doc) -> ["Test that cast really return immediately"];
  473: cast_fast(Config) when is_list(Config) ->
  474:     ?line {ok,Node} = start_node(hubba),
  475:     ?line {_,"@"++Host} = lists:splitwith(fun ($@) -> false; (_) -> true end,
  476: 					   atom_to_list(Node)),
  477:     ?line FalseNode = list_to_atom("hopp@"++Host),
  478:     ?line true = rpc:cast(Node, ?MODULE, cast_fast_messup, []),
  479: %    ?line io:format("Nodes ~p~n", [rpc:call(N, ?MODULE, cast_fast_messup, [])]),
  480:     ?line test_server:sleep(1000),
  481:     ?line [Node] = nodes(),
  482:     ?line {Time,ok} = test_server:timecall(gen_server, cast, 
  483: 					   [{hopp,FalseNode},hopp]),
  484:     ?line true = test_server:stop_node(Node),
  485:     ?line if Time > 1.0 -> % Default listen timeout is about 7.0 s
  486: 		  test_server:fail(hanging_cast);
  487: 	     true -> 
  488: 		  ok
  489: 	  end.
  490: 
  491: cast_fast_messup() ->
  492:     %% Register a false node: hopp@hostname
  493:     unregister(erl_epmd),
  494:     erl_epmd:start_link(),
  495:     {ok,S} = gen_tcp:listen(0, []),
  496:     {ok,P} = inet:port(S),
  497:     {ok,_Creation} = erl_epmd:register_node(hopp, P),
  498:     receive after infinity -> ok end.
  499: 
  500: %% --------------------------------------
  501: %% Test handle_info.
  502: %% --------------------------------------
  503: 
  504: info(suite) -> [];
  505: info(Config) when is_list(Config) ->
  506:     ?line {ok, Pid} =
  507: 	gen_server:start({local, my_test_name},
  508: 			 gen_server_SUITE, [], []),
  509: 
  510:     ?line ok = gen_server:call(my_test_name, started_p),
  511: 
  512:     ?line Pid ! {self(),handle_info},
  513:     ?line receive
  514: 	      {Pid, handled_info} ->
  515: 		  ok
  516: 	  after 1000 ->
  517: 		  test_server:fail(handle_info)
  518: 	  end,
  519:     
  520:     ?line Pid ! {self(),delayed_info,1},
  521:     ?line receive
  522: 	      {Pid, delayed_info} ->
  523: 		  ok
  524: 	  after 1000 ->
  525: 		  test_server:fail(delayed_info)
  526: 	  end,
  527:     
  528:     ?line Pid ! {self(),stop},
  529:     ?line receive
  530: 	      {Pid, stopped_info} ->
  531: 		  ok
  532: 	  after 1000 ->
  533: 		  test_server:fail(stop_info)
  534: 	  end,
  535:     ok.
  536: 
  537: hibernate(suite) -> [];
  538: hibernate(Config) when is_list(Config) ->
  539:     OldFl = process_flag(trap_exit, true),
  540:     ?line {ok, Pid0} =
  541: 	gen_server:start_link({local, my_test_name_hibernate0},
  542: 			 gen_server_SUITE, hibernate, []),
  543:     ?line receive after 1000 -> ok end,
  544:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid0,current_function),
  545:     ?line ok = gen_server:call(my_test_name_hibernate0, stop),
  546:     receive 
  547: 	{'EXIT', Pid0, stopped} ->
  548:  	    ok
  549:     after 5000 ->
  550: 	    test_server:fail(gen_server_did_not_die)
  551:     end,
  552: 
  553:     ?line {ok, Pid} =
  554: 	gen_server:start_link({local, my_test_name_hibernate},
  555: 			 gen_server_SUITE, [], []),
  556: 
  557:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  558:     ?line true = gen_server:call(my_test_name_hibernate, hibernate),
  559:     ?line receive after 1000 -> ok end,
  560:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  561:     ?line Parent = self(),
  562:     Fun = fun() ->
  563:  		  receive
  564:  		      go ->
  565:  			  ok
  566:  		  end,
  567:  		  receive 
  568:  		  after 1000 ->
  569:  			  ok 
  570:  		  end,
  571:  		  X = erlang:process_info(Pid,current_function),
  572:  		  Pid ! continue,
  573:  		  Parent ! {result,X}
  574:  	  end,
  575:     ?line Pid2 = spawn_link(Fun),
  576:     ?line true = gen_server:call(my_test_name_hibernate, {hibernate_noreply,Pid2}),
  577: 
  578:     ?line gen_server:cast(my_test_name_hibernate, hibernate_later),
  579:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  580:     ?line receive after 2000 -> ok end,
  581:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  582:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  583:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  584:     ?line gen_server:cast(my_test_name_hibernate, hibernate_now),
  585:     ?line receive after 1000 -> ok end,
  586:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  587:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  588:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  589:     ?line Pid ! hibernate_later,
  590:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  591:     ?line receive after 2000 -> ok end,
  592:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  593:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  594:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  595:     ?line Pid ! hibernate_now,
  596:     ?line receive after 1000 -> ok end,
  597:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  598:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  599:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  600:     ?line receive
  601:  	      {result,R} ->
  602:  		  ?line  {current_function,{erlang,hibernate,3}} = R
  603:  	  end,
  604:     ?line true = gen_server:call(my_test_name_hibernate, hibernate),
  605:     ?line receive after 1000 -> ok end,
  606:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  607:     ?line sys:suspend(my_test_name_hibernate),
  608:     ?line receive after 1000 -> ok end,
  609:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  610:     ?line sys:resume(my_test_name_hibernate),
  611:     ?line receive after 1000 -> ok end,
  612:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  613:     ?line ok = gen_server:call(my_test_name_hibernate, started_p),
  614:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  615:     
  616:     ?line ok = gen_server:call(my_test_name_hibernate, stop),
  617:     receive 
  618: 	{'EXIT', Pid, stopped} ->
  619:  	    ok
  620:     after 5000 ->
  621: 	    test_server:fail(gen_server_did_not_die)
  622:     end,
  623:     process_flag(trap_exit, OldFl),
  624:     ok.
  625: 
  626: %% --------------------------------------
  627: %% Test gen_server:abcast and handle_cast.
  628: %% Test all different return values from
  629: %% handle_cast.
  630: %% --------------------------------------
  631: 
  632: abcast(suite) -> [];
  633: abcast(Config) when is_list(Config) ->
  634:     ?line {ok, Pid} =
  635: 	gen_server:start({local, my_test_name},
  636: 			 gen_server_SUITE, [], []),
  637: 
  638:     ?line ok = gen_server:call(my_test_name, started_p),
  639: 
  640:     ?line abcast = gen_server:abcast(my_test_name, {self(),handle_cast}),
  641:     ?line receive
  642: 	      {Pid, handled_cast} ->
  643: 		  ok
  644: 	  after 1000 ->
  645: 		  test_server:fail(abcast)
  646: 	  end,
  647:     
  648:     ?line abcast = gen_server:abcast([node()], my_test_name,
  649: 				     {self(),delayed_cast,1}),
  650:     ?line receive
  651: 	      {Pid, delayed} ->
  652: 		  ok
  653: 	  after 1000 ->
  654: 		  test_server:fail(delayed_abcast)
  655: 	  end,
  656:     
  657:     ?line abcast = gen_server:abcast(my_test_name, {self(),stop}),
  658:     ?line receive
  659: 	      {Pid, stopped} ->
  660: 		  ok
  661: 	  after 1000 ->
  662: 		  test_server:fail(abcast_stop)
  663: 	  end,
  664:     ok.
  665: 
  666: %% --------------------------------------
  667: %% Test gen_server:multicall and handle_call.
  668: %% Test all different return values from
  669: %% handle_call.
  670: %% --------------------------------------
  671: 
  672: multicall(suite) -> [];
  673: multicall(Config) when is_list(Config) ->
  674:     OldFl = process_flag(trap_exit, true),
  675: 
  676:     ?line {ok, Pid} =
  677: 	gen_server:start_link({local, my_test_name},
  678: 			      gen_server_SUITE, [], []),
  679: 
  680:     ?line ok = gen_server:call(my_test_name, started_p),
  681:     Nodes = nodes(),
  682:     Node = node(),
  683:     ?line {[{Node,delayed}],Nodes} =
  684: 	   gen_server:multi_call(my_test_name, {delayed_answer,1}),
  685: 
  686:     %% two requests within a specified time.
  687:     ?line {[{Node,ok}],[]} =
  688: 	   gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
  689:     test_server:sleep(500),
  690:     ?line {[{Node,ok}],[]} =
  691: 	   gen_server:multi_call([Node], my_test_name, next_call),
  692:     ?line  {[{Node,ok}],[]} =
  693: 	    gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
  694:     test_server:sleep(1500),
  695:     ?line {[{Node,false}],[]} =
  696: 	   gen_server:multi_call([Node],my_test_name, next_call),
  697: 
  698:     %% Stop the server.
  699:     ?line {[{Node,ok}],[]} =
  700: 	   gen_server:multi_call([Node],my_test_name, stop),
  701:     receive
  702: 	{'EXIT', Pid, stopped} -> ok
  703:     after 1000 ->
  704: 	    test_server:fail(multicall_stop)
  705:     end,
  706:     
  707:     process_flag(trap_exit, OldFl),
  708: 
  709:     ok.
  710: 
  711: %% OTP-3587
  712: multicall_down(suite) -> [];
  713: multicall_down(Config) when is_list(Config) ->
  714:     %% We need a named host which is inaccessible.
  715:     ?line Name = node@test01,
  716: 
  717:     %% We use 'global' as a gen_server to call.
  718:     ?line {Good, Bad} = gen_server:multi_call([Name, node()],
  719: 					      global_name_server,
  720: 					      info,
  721: 					      3000),
  722:     io:format("good = ~p, bad = ~p~n", [Good, Bad]),
  723:     ?line [Name] = Bad,
  724:     ok.
  725: 
  726: busy_wait_for_process(Pid,N) ->
  727:     case erlang:is_process_alive(Pid) of
  728: 	true ->
  729: 	    receive
  730: 	    after 100 ->
  731: 		    ok
  732: 	    end,
  733: 	    busy_wait_for_process(Pid,N-1);
  734: 	_ ->
  735: 	    ok
  736:     end.
  737: %%--------------------------------------------------------------
  738: spec_init(doc) ->
  739:     ["Test gen_server:enter_loop/[3,4,5]. Used when you want to write " 
  740:      "your own special init-phase."];
  741: spec_init(suite) ->
  742:     [];
  743: spec_init(Config) when is_list(Config) ->
  744:     
  745:     OldFlag = process_flag(trap_exit, true),
  746: 
  747:     ?line {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]),
  748:     ?line ok = gen_server:call(Pid0, started_p),
  749:     ?line ok = gen_server:call(Pid0, stop),
  750:     receive 
  751: 	{'EXIT', Pid0, stopped} ->
  752:  	    ok
  753:     after 5000 ->
  754: 	    test_server:fail(gen_server_did_not_die)
  755:     end,
  756:     
  757:     ?line {ok, Pid01} = start_link(spec_init_local, [{not_ok, my_server}, []]),
  758:     receive 
  759:  	{'EXIT', Pid01, process_not_registered} ->
  760:  	    ok
  761:     after 5000 ->
  762: 	    test_server:fail(gen_server_did_not_die)
  763:     end,
  764:     
  765:     ?line {ok, Pid1} = start_link(spec_init_global, [{ok, my_server}, []]),
  766:     ?line ok = gen_server:call(Pid1, started_p),
  767:     ?line ok = gen_server:call(Pid1, stop),
  768:     receive 
  769: 	{'EXIT', Pid1, stopped} ->
  770:  	    ok
  771:     after 5000 ->
  772: 	    test_server:fail(gen_server_did_not_die)
  773:     end,
  774:     
  775:     ?line {ok, Pid11} = 
  776: 	start_link(spec_init_global, [{not_ok, my_server}, []]),
  777: 
  778:     receive 
  779: 	{'EXIT', Pid11, process_not_registered_globally} ->
  780:  	    ok
  781:     after 5000 ->
  782: 	    test_server:fail(gen_server_did_not_die)
  783:     end,
  784:     
  785:     ?line {ok, Pid2} = start_link(spec_init_anonymous, [[]]),
  786:     ?line ok = gen_server:call(Pid2, started_p),
  787:     ?line ok = gen_server:call(Pid2, stop),
  788:     receive 
  789: 	{'EXIT', Pid2, stopped} ->
  790:  	    ok
  791:     after 5000 ->
  792: 	    test_server:fail(gen_server_did_not_die)
  793:     end,
  794:     
  795:     ?line {ok, Pid3} = start_link(spec_init_anonymous_default_timeout, [[]]),
  796:     ?line ok = gen_server:call(Pid3, started_p),
  797:     ?line ok = gen_server:call(Pid3, stop),
  798:     receive 
  799: 	{'EXIT', Pid3, stopped} ->
  800:  	    ok
  801:     after 5000 ->
  802: 	    test_server:fail(gen_server_did_not_die)
  803:     end,
  804:     
  805:     ?line {ok, Pid4} = 
  806: 	start_link(spec_init_default_timeout, [{ok, my_server}, []]),
  807:     ?line ok = gen_server:call(Pid4, started_p),
  808:     ?line ok = gen_server:call(Pid4, stop),
  809:     receive 
  810: 	{'EXIT', Pid4, stopped} ->
  811:  	    ok
  812:     after 5000 ->
  813: 	    test_server:fail(gen_server_did_not_die)
  814:     end,
  815: 
  816:     %% Before the OTP-10130 fix this failed because a timeout message
  817:     %% was generated as the spawned process crashed because a {global, Name}
  818:     %% was matched as a timeout value instead of matching on scope.
  819:     {ok, _PidHurra} =
  820: 	start_link(spec_init_global_default_timeout, [{ok, hurra}, []]),
  821:     timer:sleep(1000),
  822:     ok = gen_server:call(_PidHurra, started_p),
  823:     
  824:     ?line Pid5 = 
  825: 	erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]),
  826:     receive 
  827: 	{'EXIT', Pid5, process_was_not_started_by_proc_lib} ->
  828:  	    ok
  829:     after 5000 ->
  830: 	    test_server:fail(gen_server_did_not_die)
  831:     end,
  832:     process_flag(trap_exit, OldFlag),
  833:     ok.
  834: 
  835: %%--------------------------------------------------------------
  836: spec_init_local_registered_parent(doc) ->
  837:     ["Test that terminate is run when the parent is a locally registered "
  838:      "process OTP-4820"];
  839: spec_init_local_registered_parent(suite) -> [];
  840: spec_init_local_registered_parent(Config) when is_list(Config) ->
  841: 
  842:     register(foobar, self()),
  843:     process_flag(trap_exit, true),
  844:     
  845:     ?line {ok, Pid} = start_link(spec_init_local, [{ok, my_server}, []]),
  846:     
  847:     ?line ok = gen_server:cast(my_server, {self(),stop}),
  848:     ?line receive
  849: 	      {Pid, stopped} ->
  850: 		  ok
  851: 	  after 1000 ->
  852: 		  test_server:fail(stop)
  853: 	  end,
  854:     unregister(foobar),
  855:     ok.
  856: %%--------------------------------------------------------------
  857: spec_init_global_registered_parent(doc) ->
  858:     ["Test that terminate is run when the parent is a global registered "
  859:      "process OTP-4820"];
  860: spec_init_global_registered_parent(suite) -> [];
  861: spec_init_global_registered_parent(Config) when is_list(Config) ->
  862: 
  863:     global:register_name(foobar, self()),
  864:     process_flag(trap_exit, true),
  865:     
  866:     ?line {ok, Pid} = start_link(spec_init_global, [{ok, my_server}, []]),
  867:     
  868:     ?line ok = gen_server:call(Pid, started_p),
  869:     ?line ok = gen_server:cast(Pid, {self(),stop}),  
  870: 
  871:     ?line receive
  872: 	      {Pid, stopped} ->
  873: 		  ok
  874: 	  after 1000 ->
  875: 		  test_server:fail(stop)
  876: 	  end,
  877:     global:unregister_name(foobar),
  878:     ok.
  879: %%--------------------------------------------------------------
  880: otp_5854(suite) ->
  881:     [];
  882: otp_5854(doc) ->
  883:     ["Test check for registered name in enter_loop/3,4,5"];
  884: otp_5854(Config) when is_list(Config) ->
  885:     OldFlag = process_flag(trap_exit, true),
  886: 
  887:     ?line dummy_via:reset(),
  888: 
  889:     %% Make sure gen_server:enter_loop does not accept {local,Name}
  890:     %% when it's another process than the calling one which is
  891:     %% registered under that name
  892:     register(armitage, self()),
  893:     ?line {ok, Pid1} =
  894: 	start_link(spec_init_local, [{not_ok, armitage}, []]),
  895:     receive
  896: 	{'EXIT', Pid1, process_not_registered} ->
  897: 	    ok
  898:     after 1000 ->
  899: 	    ?line test_server:fail(gen_server_started)
  900:     end,
  901:     unregister(armitage),
  902: 
  903:     %% Make sure gen_server:enter_loop does not accept {global,Name}
  904:     %% when it's another process than the calling one which is
  905:     %% registered under that name
  906:     global:register_name(armitage, self()),
  907:     ?line {ok, Pid2} =
  908: 	start_link(spec_init_global, [{not_ok, armitage}, []]),
  909:     receive
  910: 	{'EXIT', Pid2, process_not_registered_globally} ->
  911: 	    ok
  912:     after 1000 ->
  913: 	    ?line test_server:fail(gen_server_started)
  914:     end,
  915:     global:unregister_name(armitage),
  916: 
  917:     %% (same for {via, Mod, Name})
  918:     dummy_via:register_name(armitage, self()),
  919:     ?line {ok, Pid3} =
  920: 	start_link(spec_init_via, [{not_ok, armitage}, []]),
  921:     receive
  922: 	{'EXIT', Pid3, {process_not_registered_via, dummy_via}} ->
  923: 	    ok
  924:     after 1000 ->
  925: 	    ?line test_server:fail(gen_server_started)
  926:     end,
  927:     dummy_via:unregister_name(armitage),
  928: 
  929:     process_flag(trap_exit, OldFlag),
  930:     ok.
  931: 
  932: %% If initialization fails (with ignore or {stop,Reason}),
  933: %% make sure that the process is not registered when gen_server:start()
  934: %% returns.
  935: 
  936: otp_7669(Config) when is_list(Config) ->
  937:     ?line ?t:do_times(100, fun do_otp_7669_local_ignore/0),
  938:     ?line ?t:do_times(100, fun do_otp_7669_global_ignore/0),
  939:     ?line ?t:do_times(10, fun do_otp_7669_stop/0),
  940:     ok.    
  941: 
  942: do_otp_7669_local_ignore() ->
  943:     %% The name should never be registered after the return
  944:     %% from gen_server:start/3.
  945:     ?line ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
  946:     ?line undefined = whereis(?MODULE),
  947:     ?line ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
  948:     ?line undefined = whereis(?MODULE),
  949:     ?line ignore = gen_server:start_link({local,?MODULE}, ?MODULE, ignore, []),
  950:     ?line undefined = whereis(?MODULE).
  951: 
  952: do_otp_7669_global_ignore() ->
  953:     ?line ignore = gen_server:start({global,?MODULE}, ?MODULE, ignore, []),
  954:     ?line undefined = global:whereis_name(?MODULE),
  955:     ?line ignore = gen_server:start_link({global,?MODULE}, ?MODULE, ignore, []),
  956:     ?line undefined = global:whereis_name(?MODULE).
  957: 
  958: do_otp_7669_stop() ->
  959:     %% The name should never be registered after the return
  960:     %% from gen_server:start/3.
  961:     ?line {error,stopped} = gen_server:start({local,?MODULE},
  962: 					     ?MODULE, stop, []),
  963:     ?line undefined = whereis(?MODULE),
  964: 
  965:     ?line {error,stopped} = gen_server:start({global,?MODULE},
  966: 					     ?MODULE, stop, []),
  967:     ?line undefined = global:whereis_name(?MODULE).
  968: 
  969: %% Verify that sys:get_status correctly calls our format_status/2 fun
  970: %%
  971: call_format_status(suite) ->
  972:     [];
  973: call_format_status(doc) ->
  974:     ["Test that sys:get_status/1,2 calls format_status/2"];
  975: call_format_status(Config) when is_list(Config) ->
  976:     ?line {ok, Pid} = gen_server:start_link({local, call_format_status},
  977: 					    ?MODULE, [], []),
  978:     ?line Status1 = sys:get_status(call_format_status),
  979:     ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data1]} = Status1,
  980:     ?line [format_status_called | _] = lists:reverse(Data1),
  981:     ?line Status2 = sys:get_status(call_format_status, 5000),
  982:     ?line {status, Pid, _Mod, [_PDict, running, _Parent, _, Data2]} = Status2,
  983:     ?line [format_status_called | _] = lists:reverse(Data2),
  984: 
  985:     %% check that format_status can handle a name being a pid (atom is
  986:     %% already checked by the previous test)
  987:     ?line {ok, Pid3} = gen_server:start_link(gen_server_SUITE, [], []),
  988:     ?line Status3 = sys:get_status(Pid3),
  989:     ?line {status, Pid3, _Mod, [_PDict3, running, _Parent, _, Data3]} = Status3,
  990:     ?line [format_status_called | _] = lists:reverse(Data3),
  991: 
  992:     %% check that format_status can handle a name being a term other than a
  993:     %% pid or atom
  994:     GlobalName1 = {global, "CallFormatStatus"},
  995:     ?line {ok, Pid4} = gen_server:start_link(GlobalName1,
  996: 					     gen_server_SUITE, [], []),
  997:     ?line Status4 = sys:get_status(Pid4),
  998:     ?line {status, Pid4, _Mod, [_PDict4, running, _Parent, _, Data4]} = Status4,
  999:     ?line [format_status_called | _] = lists:reverse(Data4),
 1000:     GlobalName2 = {global, {name, "term"}},
 1001:     ?line {ok, Pid5} = gen_server:start_link(GlobalName2,
 1002: 					     gen_server_SUITE, [], []),
 1003:     ?line Status5 = sys:get_status(GlobalName2),
 1004:     ?line {status, Pid5, _Mod, [_PDict5, running, _Parent, _, Data5]} = Status5,
 1005:     ?line [format_status_called | _] = lists:reverse(Data5),
 1006:     ok.
 1007: 
 1008: %% Verify that error termination correctly calls our format_status/2 fun
 1009: %%
 1010: error_format_status(suite) ->
 1011:     [];
 1012: error_format_status(doc) ->
 1013:     ["Test that an error termination calls format_status/2"];
 1014: error_format_status(Config) when is_list(Config) ->
 1015:     ?line error_logger_forwarder:register(),
 1016:     OldFl = process_flag(trap_exit, true),
 1017:     State = "called format_status",
 1018:     ?line {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []),
 1019:     ?line {'EXIT',{crashed,_}} = (catch gen_server:call(Pid, crash)),
 1020:     receive
 1021: 	{'EXIT', Pid, crashed} ->
 1022: 	    ok
 1023:     end,
 1024:     receive
 1025: 	{error,_GroupLeader,{Pid,
 1026: 			     "** Generic server"++_,
 1027: 			     [Pid,crash,State,crashed]}} ->
 1028: 	    ok;
 1029: 	Other ->
 1030: 	    ?line io:format("Unexpected: ~p", [Other]),
 1031: 	    ?line ?t:fail()
 1032:     end,
 1033:     ?t:messages_get(),
 1034:     process_flag(trap_exit, OldFl),
 1035:     ok.
 1036: 
 1037: %% Verify that sys:get_state correctly returns gen_server state
 1038: %%
 1039: get_state(suite) ->
 1040:     [];
 1041: get_state(doc) ->
 1042:     ["Test that sys:get_state/1,2 return the gen_server state"];
 1043: get_state(Config) when is_list(Config) ->
 1044:     State = self(),
 1045:     {ok, _Pid} = gen_server:start_link({local, get_state},
 1046:                                              ?MODULE, {state,State}, []),
 1047:     State = sys:get_state(get_state),
 1048:     State = sys:get_state(get_state, 5000),
 1049:     {ok, Pid} = gen_server:start_link(?MODULE, {state,State}, []),
 1050:     State = sys:get_state(Pid),
 1051:     State = sys:get_state(Pid, 5000),
 1052:     ok.
 1053: 
 1054: %% Verify that sys:replace_state correctly replaces gen_server state
 1055: %%
 1056: replace_state(suite) ->
 1057:     [];
 1058: replace_state(doc) ->
 1059:     ["Test that sys:replace_state/1,2 replace the gen_server state"];
 1060: replace_state(Config) when is_list(Config) ->
 1061:     State = self(),
 1062:     {ok, _Pid} = gen_server:start_link({local, replace_state},
 1063:                                              ?MODULE, {state,State}, []),
 1064:     State = sys:get_state(replace_state),
 1065:     NState1 = "replaced",
 1066:     Replace1 = fun(_) -> NState1 end,
 1067:     NState1 = sys:replace_state(replace_state, Replace1),
 1068:     NState1 = sys:get_state(replace_state),
 1069:     {ok, Pid} = gen_server:start_link(?MODULE, {state,NState1}, []),
 1070:     NState1 = sys:get_state(Pid),
 1071:     Suffix = " again",
 1072:     NState2 = NState1 ++ Suffix,
 1073:     Replace2 = fun(S) -> S ++ Suffix end,
 1074:     NState2 = sys:replace_state(Pid, Replace2, 5000),
 1075:     NState2 = sys:get_state(Pid, 5000),
 1076:     %% verify no change in state if replace function crashes
 1077:     Replace3 = fun(_) -> throw(fail) end,
 1078:     NState2 = sys:replace_state(Pid, Replace3),
 1079:     NState2 = sys:get_state(Pid, 5000),
 1080:     ok.
 1081: 
 1082: %% Test that the time for a huge message queue is not
 1083: %% significantly slower than with an empty message queue.
 1084: call_with_huge_message_queue(Config) when is_list(Config) ->
 1085:     case test_server:is_native(gen) of
 1086: 	true ->
 1087: 	    {skip,
 1088: 	     "gen is native - huge message queue optimization "
 1089: 	     "is not implemented"};
 1090: 	false ->
 1091: 	    do_call_with_huge_message_queue()
 1092: 		end.
 1093: 
 1094: do_call_with_huge_message_queue() ->
 1095:     ?line Pid = spawn_link(fun echo_loop/0),
 1096: 
 1097:     ?line {Time,ok} = tc(fun() -> calls(10000, Pid) end),
 1098: 
 1099:     ?line [self() ! {msg,N} || N <- lists:seq(1, 500000)],
 1100:     erlang:garbage_collect(),
 1101:     ?line {NewTime,ok} = tc(fun() -> calls(10000, Pid) end),
 1102:     io:format("Time for empty message queue: ~p", [Time]),
 1103:     io:format("Time for huge message queue: ~p", [NewTime]),
 1104: 
 1105:     IsCover = test_server:is_cover(),
 1106:     case (NewTime+1) / (Time+1) of
 1107: 	Q when Q < 10; IsCover ->
 1108: 	    ok;
 1109: 	Q ->
 1110: 	    io:format("Q = ~p", [Q]),
 1111: 	    ?line ?t:fail()
 1112:     end,
 1113:     ok.
 1114: 
 1115: calls(0, _) -> ok;
 1116: calls(N, Pid) ->
 1117:     {ultimate_answer,42} = call(Pid, {ultimate_answer,42}),
 1118:     calls(N-1, Pid).
 1119: 
 1120: call(Pid, Msg) ->
 1121:     gen_server:call(Pid, Msg, infinity).
 1122: 
 1123: tc(Fun) ->
 1124:     timer:tc(erlang, apply, [Fun,[]]).
 1125: 
 1126: echo_loop() ->
 1127:     receive
 1128: 	{'$gen_call',{Pid,Ref},Msg} ->
 1129: 	    Pid ! {Ref,Msg},
 1130: 	    echo_loop()
 1131:     end.
 1132: 
 1133: %%--------------------------------------------------------------
 1134: %% Help functions to spec_init_*
 1135: start_link(Init, Options) ->
 1136:     proc_lib:start_link(?MODULE, Init, Options).
 1137: 
 1138: spec_init_local({ok, Name}, Options) ->
 1139:     process_flag(trap_exit, true),
 1140:     register(Name, self()),
 1141:     proc_lib:init_ack({ok, self()}),
 1142:     %% Supervised init can occur here  ...
 1143:     gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity);
 1144: 
 1145: spec_init_local({not_ok, Name}, Options) ->
 1146:     process_flag(trap_exit, true),
 1147:     proc_lib:init_ack({ok, self()}),
 1148:     %% Supervised init can occur here  ...
 1149:     gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity).
 1150: 
 1151: spec_init_global({ok, Name}, Options) ->
 1152:     process_flag(trap_exit, true),
 1153:     global:register_name(Name, self()),
 1154:     proc_lib:init_ack({ok, self()}),
 1155:     %% Supervised init can occur here  ...
 1156:     gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity);
 1157: 
 1158: spec_init_global({not_ok, Name}, Options) ->
 1159:     process_flag(trap_exit, true),
 1160:     proc_lib:init_ack({ok, self()}),
 1161:     %% Supervised init can occur here  ...
 1162:     gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity).
 1163: 
 1164: spec_init_via({ok, Name}, Options) ->
 1165:     process_flag(trap_exit, true),
 1166:     dummy_via:register_name(Name, self()),
 1167:     proc_lib:init_ack({ok, self()}),
 1168:     %% Supervised init can occur here  ...
 1169:     gen_server:enter_loop(?MODULE, Options, {},
 1170: 			  {via, dummy_via, Name}, infinity);
 1171: 
 1172: spec_init_via({not_ok, Name}, Options) ->
 1173:     process_flag(trap_exit, true),
 1174:     proc_lib:init_ack({ok, self()}),
 1175:     %% Supervised init can occur here  ...
 1176:     gen_server:enter_loop(?MODULE, Options, {},
 1177: 			  {via, dummy_via, Name}, infinity).
 1178: 
 1179: spec_init_default_timeout({ok, Name}, Options) ->
 1180:     process_flag(trap_exit, true),
 1181:     register(Name, self()),
 1182:     proc_lib:init_ack({ok, self()}),
 1183:     %% Supervised init can occur here  ...
 1184:     gen_server:enter_loop(?MODULE, Options, {}, {local, Name}).
 1185: 
 1186: %% OTP-10130, A bug was introduced where global scope was not matched when
 1187: %% enter_loop/4 was called (no timeout).
 1188: spec_init_global_default_timeout({ok, Name}, Options) ->
 1189:     process_flag(trap_exit, true),
 1190:     global:register_name(Name, self()),
 1191:     proc_lib:init_ack({ok, self()}),
 1192:     %% Supervised init can occur here  ...
 1193:     gen_server:enter_loop(?MODULE, Options, {}, {global, Name}).
 1194: 
 1195: spec_init_anonymous(Options) ->
 1196:     process_flag(trap_exit, true),
 1197:     proc_lib:init_ack({ok, self()}),
 1198:     %% Supervised init can occur here  ...
 1199:     gen_server:enter_loop(?MODULE, Options, {}, infinity).
 1200: 
 1201: spec_init_anonymous_default_timeout(Options) ->
 1202:     process_flag(trap_exit, true),
 1203:     proc_lib:init_ack({ok, self()}),
 1204:     %% Supervised init can occur here  ...
 1205:     gen_server:enter_loop(?MODULE, Options, {}).
 1206: 
 1207: spec_init_not_proc_lib(Options) ->
 1208:     gen_server:enter_loop(?MODULE, Options, {}, infinity).
 1209: 
 1210: %%% --------------------------------------------------------
 1211: %%% Here is the tested gen_server behaviour.
 1212: %%% --------------------------------------------------------
 1213: 
 1214: init([]) ->
 1215:     {ok, []};
 1216: init(ignore) ->
 1217:     ignore;
 1218: init(stop) ->
 1219:     {stop, stopped};
 1220: init(hibernate) ->
 1221:     {ok,[],hibernate};
 1222: init(sleep) ->
 1223:     test_server:sleep(1000),
 1224:     {ok, []};
 1225: init({state,State}) ->
 1226:     {ok, State}.
 1227: 
 1228: handle_call(started_p, _From, State) ->
 1229:     io:format("FROZ"),
 1230:     {reply,ok,State};
 1231: handle_call({delayed_answer, T}, From, _State) ->
 1232:     {noreply,{reply_to,From},T};
 1233: handle_call({call_within, T}, _From, _) ->
 1234:     {reply,ok,call_within,T};
 1235: handle_call(next_call, _From, call_within) ->
 1236:     {reply,ok,[]};
 1237: handle_call(next_call, _From, State) ->
 1238:     {reply,false,State};
 1239: handle_call(badreturn, _From, _State) ->
 1240:     badreturn;
 1241: handle_call(hibernate, _From, _State) ->
 1242:     {reply,true,[],hibernate};
 1243: handle_call({hibernate_noreply,Pid}, From, _State) ->
 1244:     Pid ! go,
 1245:     {noreply,From,hibernate};
 1246: handle_call(stop, _From, State) ->
 1247:     {stop,stopped,ok,State};
 1248: handle_call(crash, _From, _State) ->
 1249:     exit(crashed);
 1250: handle_call(exit_shutdown, _From, _State) ->
 1251:     exit(shutdown);
 1252: handle_call(stop_shutdown, _From, State) ->
 1253:     {stop,shutdown,State};
 1254: handle_call(shutdown_reason, _From, _State) ->
 1255:     exit({shutdown,reason});
 1256: handle_call(stop_shutdown_reason, _From, State) ->
 1257:     {stop,{shutdown,stop_reason},State}.
 1258: 
 1259: handle_cast({From,handle_cast}, State) ->
 1260:     From ! {self(), handled_cast},
 1261:     {noreply, State};
 1262: handle_cast({From,delayed_cast,T}, _State) ->
 1263:     {noreply, {delayed_cast,From}, T};
 1264: handle_cast(hibernate_now, _State) ->
 1265:     {noreply, [], hibernate};
 1266: handle_cast(hibernate_later, _State) ->
 1267:     timer:send_after(1000,self(),hibernate_now),
 1268:     {noreply, []};
 1269: handle_cast({From, stop}, State) ->
 1270:     io:format("BAZ"),
 1271:     {stop, {From,stopped}, State}.
 1272: 
 1273: handle_info(timeout, {reply_to, From}) ->
 1274:     gen_server:reply(From, delayed),
 1275:     {noreply, []};
 1276: handle_info(timeout, hibernate_me) -> % Arrive here from 
 1277: 				      % handle_info(hibernate_later,...)
 1278:     {noreply, [], hibernate};
 1279: handle_info(hibernate_now, _State) ->  % Arrive here from 
 1280: 				       % handle_cast({_,hibernate_later},...)
 1281: 				       % and by direct ! from testcase
 1282:     {noreply, [], hibernate};
 1283: handle_info(hibernate_later, _State) ->
 1284:     {noreply, hibernate_me, 1000};
 1285: handle_info(timeout, call_within) ->
 1286:     {noreply, []};
 1287: handle_info(timeout, {delayed_cast, From}) ->
 1288:     From ! {self(), delayed},
 1289:     {noreply, []};
 1290: handle_info(timeout, {delayed_info, From}) ->
 1291:     From ! {self(), delayed_info},
 1292:     {noreply, []};
 1293: handle_info({From, handle_info}, _State) ->
 1294:     From ! {self(), handled_info},
 1295:     {noreply, []};
 1296: handle_info({From, delayed_info, T}, _State) ->
 1297:     {noreply, {delayed_info, From}, T};
 1298: handle_info(continue, From) ->
 1299:     gen_server:reply(From,true),
 1300:     {noreply, []};
 1301: handle_info({From, stop}, State) ->
 1302:     {stop, {From,stopped_info}, State};
 1303: handle_info(_Info, State) ->
 1304:     {noreply, State}.
 1305: 
 1306: terminate({From, stopped}, _State) ->
 1307:     io:format("FOOBAR"),
 1308:     From ! {self(), stopped},
 1309:     ok;
 1310: terminate({From, stopped_info}, _State) ->
 1311:     From ! {self(), stopped_info},
 1312:     ok;
 1313: terminate(_Reason, _State) ->
 1314:     ok.
 1315: 
 1316: format_status(terminate, [_PDict, State]) ->
 1317:     State;
 1318: format_status(normal, [_PDict, _State]) ->
 1319:     format_status_called.