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_fsm_SUITE).
   20: 
   21: -include_lib("test_server/include/test_server.hrl").
   22: 
   23: %% Test cases
   24: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
   25: 	 init_per_group/2,end_per_group/2]).
   26: 
   27: -export([start1/1, start2/1, start3/1, start4/1, start5/1, start6/1,
   28: 	 start7/1, start8/1, start9/1, start10/1, start11/1, start12/1]).
   29: 
   30: -export([ abnormal1/1, abnormal2/1]).
   31: 
   32: -export([shutdown/1]).
   33: 
   34: -export([ sys1/1, call_format_status/1, error_format_status/1, get_state/1, replace_state/1]).
   35: 
   36: -export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
   37: 
   38: -export([enter_loop/1]).
   39: 
   40: %% Exports for apply
   41: -export([do_msg/1, do_sync_msg/1]).
   42: -export([enter_loop/2]).
   43: 
   44: % The gen_fsm behaviour
   45: -export([init/1, handle_event/3, handle_sync_event/4, terminate/3,
   46: 	 handle_info/3, format_status/2]).
   47: -export([idle/2,	idle/3,
   48: 	 timeout/2,
   49: 	 wfor_conf/2,	wfor_conf/3,
   50: 	 connected/2,	connected/3]).
   51: -export([state0/3]).
   52: 	 
   53: 
   54: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   55: 
   56: 
   57: suite() -> [{ct_hooks,[ts_install_cth]}].
   58: 
   59: all() ->
   60:     [{group, start}, {group, abnormal}, shutdown,
   61:      {group, sys}, hibernate, enter_loop].
   62: 
   63: groups() ->
   64:     [{start, [],
   65:       [start1, start2, start3, start4, start5, start6, start7,
   66:        start8, start9, start10, start11, start12]},
   67:      {abnormal, [], [abnormal1, abnormal2]},
   68:      {sys, [],
   69:       [sys1, call_format_status, error_format_status, get_state, replace_state]}].
   70: 
   71: init_per_suite(Config) ->
   72:     Config.
   73: 
   74: end_per_suite(_Config) ->
   75:     ok.
   76: 
   77: init_per_group(_GroupName, Config) ->
   78:     Config.
   79: 
   80: end_per_group(_GroupName, Config) ->
   81:     Config.
   82: 
   83: %% anonymous
   84: start1(Config) when is_list(Config) ->
   85:     %%OldFl = process_flag(trap_exit, true),
   86: 
   87:     ?line {ok, Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
   88:     ?line ok = do_func_test(Pid0),
   89:     ?line ok = do_sync_func_test(Pid0),
   90:     stop_it(Pid0),
   91: %%    ?line stopped = gen_fsm:sync_send_all_state_event(Pid0, stop),
   92: %%    ?line {'EXIT', {timeout,_}} = 
   93: %%	(catch gen_fsm:sync_send_event(Pid0, hej)),
   94: 
   95:     ?line test_server:messages_get(),
   96:     %%process_flag(trap_exit, OldFl),
   97:    ok.
   98: 
   99: %% anonymous w. shutdown
  100: start2(Config) when is_list(Config) ->
  101:     %% Dont link when shutdown
  102:     ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], []),
  103:     ?line ok = do_func_test(Pid0),
  104:     ?line ok = do_sync_func_test(Pid0),
  105:     ?line shutdown_stopped = 
  106: 	gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown),
  107:     ?line {'EXIT', {noproc,_}} = 
  108: 	(catch gen_fsm:sync_send_event(Pid0, hej)),
  109: 
  110:     ?line test_server:messages_get(),
  111:     ok.
  112: 
  113: %% anonymous with timeout
  114: start3(Config) when is_list(Config) ->
  115:     %%OldFl = process_flag(trap_exit, true),
  116: 
  117:     ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], [{timeout,5}]),
  118:     ?line ok = do_func_test(Pid0),
  119:     ?line ok = do_sync_func_test(Pid0),
  120:     ?line stop_it(Pid0),
  121:     
  122:     ?line {error, timeout} = gen_fsm:start(gen_fsm_SUITE, sleep,
  123: 					   [{timeout,5}]),
  124: 
  125:     test_server:messages_get(),
  126:     %%process_flag(trap_exit, OldFl),
  127:     ok.
  128: 
  129: %% anonymous with ignore
  130: start4(suite) -> [];
  131: start4(Config) when is_list(Config) ->
  132:     OldFl = process_flag(trap_exit, true),
  133: 
  134:     ?line ignore = gen_fsm:start(gen_fsm_SUITE, ignore, []),
  135: 
  136:     test_server:messages_get(),
  137:     process_flag(trap_exit, OldFl),
  138:     ok.
  139: 
  140: %% anonymous with stop
  141: start5(suite) -> [];
  142: start5(Config) when is_list(Config) ->
  143:     OldFl = process_flag(trap_exit, true),
  144: 
  145:     ?line {error, stopped} = gen_fsm:start(gen_fsm_SUITE, stop, []),
  146: 
  147:     test_server:messages_get(),
  148:     process_flag(trap_exit, OldFl),
  149:     ok.
  150: 
  151: %% anonymous linked
  152: start6(Config) when is_list(Config) ->
  153:     ?line {ok, Pid} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
  154:     ?line ok = do_func_test(Pid),
  155:     ?line ok = do_sync_func_test(Pid),
  156:     ?line stop_it(Pid),
  157: 
  158:     test_server:messages_get(),
  159: 
  160:     ok.
  161: 
  162: %% global register linked
  163: start7(Config) when is_list(Config) ->
  164:     ?line {ok, Pid} = 
  165: 	gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
  166:     ?line {error, {already_started, Pid}} =
  167: 	gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
  168:     ?line {error, {already_started, Pid}} =
  169: 	gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
  170:     
  171:     ?line ok = do_func_test(Pid),
  172:     ?line ok = do_sync_func_test(Pid),
  173:     ?line ok = do_func_test({global, my_fsm}),
  174:     ?line ok = do_sync_func_test({global, my_fsm}),
  175:     ?line stop_it({global, my_fsm}),
  176:     
  177:     test_server:messages_get(),
  178:     ok.
  179: 
  180: 
  181: %% local register
  182: start8(Config) when is_list(Config) ->
  183:     %%OldFl = process_flag(trap_exit, true),
  184: 
  185:     ?line {ok, Pid} = 
  186: 	gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
  187:     ?line {error, {already_started, Pid}} =
  188: 	gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
  189: 
  190:     ?line ok = do_func_test(Pid),
  191:     ?line ok = do_sync_func_test(Pid),
  192:     ?line ok = do_func_test(my_fsm),
  193:     ?line ok = do_sync_func_test(my_fsm),
  194:     ?line stop_it(Pid),
  195:     
  196:     test_server:messages_get(),
  197:     %%process_flag(trap_exit, OldFl),
  198:     ok.
  199: 
  200: %% local register linked
  201: start9(Config) when is_list(Config) ->
  202:     %%OldFl = process_flag(trap_exit, true),
  203: 
  204:     ?line {ok, Pid} = 
  205: 	gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
  206:     ?line {error, {already_started, Pid}} =
  207: 	gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
  208: 
  209:     ?line ok = do_func_test(Pid),
  210:     ?line ok = do_sync_func_test(Pid),
  211:     ?line ok = do_func_test(my_fsm),
  212:     ?line ok = do_sync_func_test(my_fsm),
  213:     ?line stop_it(Pid),
  214:     
  215:     test_server:messages_get(),
  216:     %%process_flag(trap_exit, OldFl),
  217:     ok.
  218: 
  219: %% global register
  220: start10(Config) when is_list(Config) ->
  221:     ?line {ok, Pid} = 
  222: 	gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
  223:     ?line {error, {already_started, Pid}} =
  224: 	gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
  225:     ?line {error, {already_started, Pid}} =
  226: 	gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
  227:     
  228:     ?line ok = do_func_test(Pid),
  229:     ?line ok = do_sync_func_test(Pid),
  230:     ?line ok = do_func_test({global, my_fsm}),
  231:     ?line ok = do_sync_func_test({global, my_fsm}),
  232:     ?line stop_it({global, my_fsm}),
  233:     
  234:     test_server:messages_get(),
  235:     ok.
  236: 
  237: 
  238: %% Stop registered processes
  239: start11(Config) when is_list(Config) ->
  240:     ?line {ok, Pid} = 
  241: 	gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
  242:     ?line stop_it(Pid),
  243: 
  244:     ?line {ok, _Pid1} = 
  245: 	gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
  246:     ?line stop_it(my_fsm),
  247:     
  248:     ?line {ok, Pid2} = 
  249: 	gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
  250:     ?line stop_it(Pid2),
  251:     receive after 1 -> true end,
  252:     ?line Result = 
  253: 	gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
  254:     io:format("Result = ~p~n",[Result]),
  255:     ?line {ok, _Pid3} = Result, 
  256:     ?line stop_it({global, my_fsm}),
  257: 
  258:     test_server:messages_get(),
  259:     ok.
  260: 
  261: %% Via register linked
  262: start12(Config) when is_list(Config) ->
  263:     ?line dummy_via:reset(),
  264:     ?line {ok, Pid} =
  265: 	gen_fsm:start_link({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
  266:     ?line {error, {already_started, Pid}} =
  267: 	gen_fsm:start_link({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
  268:     ?line {error, {already_started, Pid}} =
  269: 	gen_fsm:start({via, dummy_via, my_fsm}, gen_fsm_SUITE, [], []),
  270: 
  271:     ?line ok = do_func_test(Pid),
  272:     ?line ok = do_sync_func_test(Pid),
  273:     ?line ok = do_func_test({via, dummy_via, my_fsm}),
  274:     ?line ok = do_sync_func_test({via, dummy_via, my_fsm}),
  275:     ?line stop_it({via, dummy_via, my_fsm}),
  276: 
  277:     test_server:messages_get(),
  278:     ok.
  279: 
  280: 
  281: %% Check that time outs in calls work
  282: abnormal1(suite) -> [];
  283: abnormal1(Config) when is_list(Config) ->
  284:     {ok, _Pid} = gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
  285: 
  286:     %% timeout call.
  287:     delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100),
  288:     {'EXIT',{timeout,_}} =
  289:     (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1)),
  290:     test_server:messages_get(),
  291:     ok.
  292: 
  293: %% Check that bad return values makes the fsm crash. Note that we must
  294: %% trap exit since we must link to get the real bad_return_ error
  295: abnormal2(suite) -> [];
  296: abnormal2(Config) when is_list(Config) ->
  297:     OldFl = process_flag(trap_exit, true),
  298:     ?line {ok, Pid} = 
  299: 	gen_fsm:start_link(gen_fsm_SUITE, [], []),
  300: 
  301:     %% bad return value in the gen_fsm loop
  302:     ?line {'EXIT',{{bad_return_value, badreturn},_}} =
  303: 	(catch gen_fsm:sync_send_event(Pid, badreturn)),
  304:     
  305:     test_server:messages_get(),
  306:     process_flag(trap_exit, OldFl),
  307:     ok.
  308: 
  309: shutdown(Config) when is_list(Config) ->
  310:     ?line error_logger_forwarder:register(),
  311: 
  312:     process_flag(trap_exit, true),
  313: 
  314:     ?line {ok,Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
  315:     ?line ok = do_func_test(Pid0),
  316:     ?line ok = do_sync_func_test(Pid0),
  317:     ?line {shutdown,reason} = 
  318: 	gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown_reason),
  319:     receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
  320:     process_flag(trap_exit, false),
  321: 
  322:     ?line {'EXIT', {noproc,_}} = 
  323: 	(catch gen_fsm:sync_send_event(Pid0, hej)),
  324: 
  325:     receive
  326: 	Any ->
  327: 	    ?line io:format("Unexpected: ~p", [Any]),
  328: 	    ?line ?t:fail()
  329:     after 500 ->
  330: 	    ok
  331:     end,
  332: 
  333:     ok.
  334: 
  335: 
  336: 
  337: sys1(Config) when is_list(Config) ->
  338:     ?line {ok, Pid} = 
  339: 	gen_fsm:start(gen_fsm_SUITE, [], []),
  340:     ?line {status, Pid, {module,gen_fsm}, _} = sys:get_status(Pid),
  341:     ?line sys:suspend(Pid),
  342:     ?line {'EXIT', {timeout,_}} = 
  343: 	(catch gen_fsm:sync_send_event(Pid, hej)),
  344:     ?line sys:resume(Pid),
  345:     ?line stop_it(Pid).
  346: 
  347: call_format_status(Config) when is_list(Config) ->
  348:     ?line {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, [], []),
  349:     ?line Status = sys:get_status(Pid),
  350:     ?line {status, Pid, _Mod, [_PDict, running, _, _, Data]} = Status,
  351:     ?line [format_status_called | _] = lists:reverse(Data),
  352:     ?line stop_it(Pid),
  353: 
  354:     %% check that format_status can handle a name being an atom (pid is
  355:     %% already checked by the previous test)
  356:     ?line {ok, Pid2} = gen_fsm:start({local, gfsm}, gen_fsm_SUITE, [], []),
  357:     ?line Status2 = sys:get_status(gfsm),
  358:     ?line {status, Pid2, _Mod, [_PDict2, running, _, _, Data2]} = Status2,
  359:     ?line [format_status_called | _] = lists:reverse(Data2),
  360:     ?line stop_it(Pid2),
  361: 
  362:     %% check that format_status can handle a name being a term other than a
  363:     %% pid or atom
  364:     GlobalName1 = {global, "CallFormatStatus"},
  365:     ?line {ok, Pid3} = gen_fsm:start(GlobalName1, gen_fsm_SUITE, [], []),
  366:     ?line Status3 = sys:get_status(GlobalName1),
  367:     ?line {status, Pid3, _Mod, [_PDict3, running, _, _, Data3]} = Status3,
  368:     ?line [format_status_called | _] = lists:reverse(Data3),
  369:     ?line stop_it(Pid3),
  370:     GlobalName2 = {global, {name, "term"}},
  371:     ?line {ok, Pid4} = gen_fsm:start(GlobalName2, gen_fsm_SUITE, [], []),
  372:     ?line Status4 = sys:get_status(GlobalName2),
  373:     ?line {status, Pid4, _Mod, [_PDict4, running, _, _, Data4]} = Status4,
  374:     ?line [format_status_called | _] = lists:reverse(Data4),
  375:     ?line stop_it(Pid4),
  376: 
  377:     %% check that format_status can handle a name being a term other than a
  378:     %% pid or atom
  379:     ?line dummy_via:reset(),
  380:     ViaName1 = {via, dummy_via, "CallFormatStatus"},
  381:     ?line {ok, Pid5} = gen_fsm:start(ViaName1, gen_fsm_SUITE, [], []),
  382:     ?line Status5 = sys:get_status(ViaName1),
  383:     ?line {status, Pid5, _Mod, [_PDict5, running, _, _, Data5]} = Status5,
  384:     ?line [format_status_called | _] = lists:reverse(Data5),
  385:     ?line stop_it(Pid5),
  386:     ViaName2 = {via, dummy_via, {name, "term"}},
  387:     ?line {ok, Pid6} = gen_fsm:start(ViaName2, gen_fsm_SUITE, [], []),
  388:     ?line Status6 = sys:get_status(ViaName2),
  389:     ?line {status, Pid6, _Mod, [_PDict6, running, _, _, Data6]} = Status6,
  390:     ?line [format_status_called | _] = lists:reverse(Data6),
  391:     ?line stop_it(Pid6).
  392: 
  393: 
  394: 
  395: error_format_status(Config) when is_list(Config) ->
  396:     ?line error_logger_forwarder:register(),
  397:     OldFl = process_flag(trap_exit, true),
  398:     StateData = "called format_status",
  399:     ?line {ok, Pid} = gen_fsm:start(gen_fsm_SUITE, {state_data, StateData}, []),
  400:     %% bad return value in the gen_fsm loop
  401:     ?line {'EXIT',{{bad_return_value, badreturn},_}} =
  402: 	(catch gen_fsm:sync_send_event(Pid, badreturn)),
  403:     receive
  404: 	{error,_GroupLeader,{Pid,
  405: 			     "** State machine"++_,
  406: 			     [Pid,{_,_,badreturn},idle,StateData,_]}} ->
  407: 	    ok;
  408: 	Other ->
  409: 	    ?line io:format("Unexpected: ~p", [Other]),
  410: 	    ?line ?t:fail()
  411:     end,
  412:     ?t:messages_get(),
  413:     process_flag(trap_exit, OldFl),
  414:     ok.
  415: 
  416: get_state(Config) when is_list(Config) ->
  417:     State = self(),
  418:     {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
  419:     {idle, State} = sys:get_state(Pid),
  420:     {idle, State} = sys:get_state(Pid, 5000),
  421:     stop_it(Pid),
  422: 
  423:     %% check that get_state can handle a name being an atom (pid is
  424:     %% already checked by the previous test)
  425:     {ok, Pid2} = gen_fsm:start({local, gfsm}, gen_fsm_SUITE, {state_data, State}, []),
  426:     {idle, State} = sys:get_state(gfsm),
  427:     {idle, State} = sys:get_state(gfsm, 5000),
  428:     stop_it(Pid2),
  429:     ok.
  430: 
  431: replace_state(Config) when is_list(Config) ->
  432:     State = self(),
  433:     {ok, Pid} = gen_fsm:start(?MODULE, {state_data, State}, []),
  434:     {idle, State} = sys:get_state(Pid),
  435:     NState1 = "replaced",
  436:     Replace1 = fun({StateName, _}) -> {StateName, NState1} end,
  437:     {idle, NState1} = sys:replace_state(Pid, Replace1),
  438:     {idle, NState1} = sys:get_state(Pid),
  439:     NState2 = "replaced again",
  440:     Replace2 = fun({idle, _}) -> {state0, NState2} end,
  441:     {state0, NState2} = sys:replace_state(Pid, Replace2, 5000),
  442:     {state0, NState2} = sys:get_state(Pid),
  443:     %% verify no change in state if replace function crashes
  444:     Replace3 = fun(_) -> error(fail) end,
  445:     {state0, NState2} = sys:replace_state(Pid, Replace3),
  446:     {state0, NState2} = sys:get_state(Pid),
  447:     stop_it(Pid),
  448:     ok.
  449: 
  450: %% Hibernation
  451: hibernate(suite) -> [];
  452: hibernate(Config) when is_list(Config) ->
  453:     OldFl = process_flag(trap_exit, true),
  454: 
  455:     ?line {ok, Pid0} = gen_fsm:start_link(?MODULE, hiber_now, []),
  456:     ?line receive after 1000 -> ok end,
  457:     ?line {current_function,{erlang,hibernate,3}} = 
  458: 	erlang:process_info(Pid0,current_function),
  459:     ?line stop_it(Pid0),
  460:     test_server:messages_get(),
  461: 
  462: 
  463:     ?line {ok, Pid} = gen_fsm:start_link(?MODULE, hiber, []),
  464:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  465:     ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
  466:     ?line receive after 1000 -> ok end,
  467:     ?line {current_function,{erlang,hibernate,3}} = 
  468: 	erlang:process_info(Pid,current_function),
  469:     ?line good_morning  = gen_fsm:sync_send_event(Pid,wakeup_sync),
  470:     ?line receive after 1000 -> ok end,
  471:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  472:     ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
  473:     ?line receive after 1000 -> ok end,
  474:     ?line {current_function,{erlang,hibernate,3}} = 
  475: 	erlang:process_info(Pid,current_function),
  476:     ?line five_more  = gen_fsm:sync_send_event(Pid,snooze_sync),
  477:     ?line receive after 1000 -> ok end,
  478:     ?line {current_function,{erlang,hibernate,3}} = 
  479: 	erlang:process_info(Pid,current_function),
  480:     ?line good_morning  = gen_fsm:sync_send_event(Pid,wakeup_sync),
  481:     ?line receive after 1000 -> ok end,
  482:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  483:     ?line ok = gen_fsm:send_event(Pid,hibernate_async),
  484:     ?line receive after 1000 -> ok end,
  485:     ?line {current_function,{erlang,hibernate,3}} = 
  486: 	erlang:process_info(Pid,current_function),
  487:     ?line ok  = gen_fsm:send_event(Pid,wakeup_async),
  488:     ?line receive after 1000 -> ok end,
  489:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  490:     ?line ok = gen_fsm:send_event(Pid,hibernate_async),
  491:     ?line receive after 1000 -> ok end,
  492:     ?line {current_function,{erlang,hibernate,3}} = 
  493: 	erlang:process_info(Pid,current_function),
  494:     ?line ok  = gen_fsm:send_event(Pid,snooze_async),
  495:     ?line receive after 1000 -> ok end,
  496:     ?line {current_function,{erlang,hibernate,3}} = 
  497: 	erlang:process_info(Pid,current_function),
  498:     ?line ok = gen_fsm:send_event(Pid,wakeup_async),
  499:     ?line receive after 1000 -> ok end,
  500:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  501:     ?line Pid ! hibernate_later,
  502:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  503:     ?line receive after 2000 -> ok end,
  504:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  505:     ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
  506:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  507:     ?line Pid ! hibernate_now,
  508:     ?line receive after 1000 -> ok end,
  509:     ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
  510:     ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
  511:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  512:     
  513: 
  514:     ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
  515:     ?line receive after 1000 -> ok end,
  516:     ?line {current_function,{erlang,hibernate,3}} = 
  517: 	erlang:process_info(Pid,current_function),
  518:     ?line good_morning  = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
  519:     ?line receive after 1000 -> ok end,
  520:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  521:     ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
  522:     ?line receive after 1000 -> ok end,
  523:     ?line {current_function,{erlang,hibernate,3}} = 
  524: 	erlang:process_info(Pid,current_function),
  525:     ?line five_more  = gen_fsm:sync_send_all_state_event(Pid,snooze_sync),
  526:     ?line receive after 1000 -> ok end,
  527:     ?line {current_function,{erlang,hibernate,3}} = 
  528: 	erlang:process_info(Pid,current_function),
  529:     ?line good_morning  = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
  530:     ?line receive after 1000 -> ok end,
  531:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  532:     ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
  533:     ?line receive after 1000 -> ok end,
  534:     ?line {current_function,{erlang,hibernate,3}} = 
  535: 	erlang:process_info(Pid,current_function),
  536:     ?line ok  = gen_fsm:send_all_state_event(Pid,wakeup_async),
  537:     ?line receive after 1000 -> ok end,
  538:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  539:     ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
  540:     ?line receive after 1000 -> ok end,
  541:     ?line {current_function,{erlang,hibernate,3}} = 
  542: 	erlang:process_info(Pid,current_function),
  543:     ?line ok  = gen_fsm:send_all_state_event(Pid,snooze_async),
  544:     ?line receive after 1000 -> ok end,
  545:     ?line {current_function,{erlang,hibernate,3}} = 
  546: 	erlang:process_info(Pid,current_function),
  547:     ?line ok = gen_fsm:send_all_state_event(Pid,wakeup_async),
  548:     ?line receive after 1000 -> ok end,
  549:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  550: 
  551:     ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
  552:     ?line receive after 1000 -> ok end,
  553:     ?line {current_function,{erlang,hibernate,3}} = 
  554: 	erlang:process_info(Pid,current_function),
  555:     ?line sys:suspend(Pid),
  556:     ?line receive after 1000 -> ok end,
  557:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  558:     ?line sys:resume(Pid),
  559:     ?line receive after 1000 -> ok end,
  560:     ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
  561: 
  562:     ?line receive after 1000 -> ok end,
  563:     ?line {current_function,{erlang,hibernate,3}} = 
  564: 	erlang:process_info(Pid,current_function),
  565:     ?line good_morning  = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
  566:     ?line receive after 1000 -> ok end,
  567:     ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
  568:     ?line stop_it(Pid),
  569:     test_server:messages_get(),
  570:     process_flag(trap_exit, OldFl),
  571:     ok.
  572: 
  573: 
  574: 
  575: %%sys1(suite) -> [];
  576: %%sys1(_) ->
  577: 
  578: enter_loop(suite) ->
  579:     [];
  580: enter_loop(doc) ->
  581:     ["Test gen_fsm:enter_loop/4,5,6"];
  582: enter_loop(Config) when is_list(Config) ->
  583:     OldFlag = process_flag(trap_exit, true),
  584: 
  585:     ?line dummy_via:reset(),
  586: 
  587:     %% Locally registered process + {local, Name}
  588:     ?line {ok, Pid1a} =
  589: 	proc_lib:start_link(?MODULE, enter_loop, [local, local]),
  590:     ?line yes = gen_fsm:sync_send_event(Pid1a, 'alive?'),
  591:     ?line stopped = gen_fsm:sync_send_event(Pid1a, stop),
  592:     receive
  593: 	{'EXIT', Pid1a, normal} ->
  594: 	    ok
  595:     after 5000 ->
  596: 	    ?line test_server:fail(gen_fsm_did_not_die)
  597:     end,
  598: 
  599:     %% Unregistered process + {local, Name}
  600:     ?line {ok, Pid1b} =
  601: 	proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
  602:     receive
  603: 	{'EXIT', Pid1b, process_not_registered} ->
  604: 	    ok
  605:     after 5000 ->
  606: 	    ?line test_server:fail(gen_fsm_did_not_die)
  607:     end,
  608: 
  609:     %% Globally registered process + {global, Name}
  610:     ?line {ok, Pid2a} =
  611: 	proc_lib:start_link(?MODULE, enter_loop, [global, global]),
  612:     ?line yes = gen_fsm:sync_send_event(Pid2a, 'alive?'),
  613:     ?line stopped = gen_fsm:sync_send_event(Pid2a, stop),
  614:     receive
  615: 	{'EXIT', Pid2a, normal} ->
  616: 	    ok
  617:     after 5000 ->
  618: 	    ?line test_server:fail(gen_fsm_did_not_die)
  619:     end,
  620: 
  621:     %% Unregistered process + {global, Name}
  622:     ?line {ok, Pid2b} =
  623: 	proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
  624:     receive
  625: 	{'EXIT', Pid2b, process_not_registered_globally} ->
  626: 	    ok
  627:     after 5000 ->
  628: 	    ?line test_server:fail(gen_fsm_did_not_die)
  629:     end,
  630: 
  631:     %% Unregistered process + no name
  632:     ?line {ok, Pid3} =
  633: 	proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
  634:     ?line yes = gen_fsm:sync_send_event(Pid3, 'alive?'),
  635:     ?line stopped = gen_fsm:sync_send_event(Pid3, stop),
  636:     receive
  637: 	{'EXIT', Pid3, normal} ->
  638: 	    ok
  639:     after 5000 ->
  640: 	    ?line test_server:fail(gen_fsm_did_not_die)
  641:     end,
  642: 
  643:     %% Process not started using proc_lib
  644:     ?line Pid4 =
  645: 	spawn_link(gen_fsm, enter_loop, [?MODULE, [], state0, []]),
  646:     receive
  647: 	{'EXIT', Pid4, process_was_not_started_by_proc_lib} ->
  648: 	    ok
  649:     after 5000 ->
  650: 	    ?line test_server:fail(gen_fsm_did_not_die)
  651:     end,
  652: 
  653:     %% Make sure I am the parent, ie that ordering a shutdown will
  654:     %% result in the process terminating with Reason==shutdown
  655:     ?line {ok, Pid5} =
  656: 	proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
  657:     ?line yes = gen_fsm:sync_send_event(Pid5, 'alive?'),
  658:     ?line exit(Pid5, shutdown),
  659:     receive
  660: 	{'EXIT', Pid5, shutdown} ->
  661: 	    ok
  662:     after 5000 ->
  663: 	    ?line test_server:fail(gen_fsm_did_not_die)
  664:     end,
  665: 
  666:     %% Make sure gen_fsm:enter_loop does not accept {local,Name}
  667:     %% when it's another process than the calling one which is
  668:     %% registered under that name
  669:     register(armitage, self()),
  670:     ?line {ok, Pid6a} =
  671: 	proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
  672:     receive
  673: 	{'EXIT', Pid6a, process_not_registered} ->
  674: 	    ok
  675:     after 1000 ->
  676: 	    ?line test_server:fail(gen_fsm_started)
  677:     end,
  678:     unregister(armitage),
  679: 
  680:     %% Make sure gen_fsm:enter_loop does not accept {global,Name}
  681:     %% when it's another process than the calling one which is
  682:     %% registered under that name
  683:     global:register_name(armitage, self()),
  684:     ?line {ok, Pid6b} =
  685: 	proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
  686:     receive
  687: 	{'EXIT', Pid6b, process_not_registered_globally} ->
  688: 	    ok
  689:     after 1000 ->
  690: 	    ?line test_server:fail(gen_fsm_started)
  691:     end,
  692:     global:unregister_name(armitage),
  693: 
  694:     dummy_via:register_name(armitage, self()),
  695:     ?line {ok, Pid6c} =
  696: 	proc_lib:start_link(?MODULE, enter_loop, [anon, via]),
  697:     receive
  698: 	{'EXIT', Pid6c, {process_not_registered_via, dummy_via}} ->
  699: 	    ok
  700:     after 1000 ->
  701: 	    ?line test_server:fail({gen_fsm_started, process_info(self(),
  702: 								 messages)})
  703:     end,
  704:     dummy_via:unregister_name(armitage),
  705: 
  706:     process_flag(trap_exit, OldFlag),
  707:     ok.
  708: 
  709: enter_loop(Reg1, Reg2) ->
  710:     process_flag(trap_exit, true),
  711:     case Reg1 of
  712: 	local -> register(armitage, self());
  713: 	global -> global:register_name(armitage, self());
  714: 	via -> dummy_via:register_name(armitage, self());
  715: 	anon -> ignore
  716:     end,
  717:     proc_lib:init_ack({ok, self()}),
  718:     case Reg2 of
  719: 	local ->
  720: 	    gen_fsm:enter_loop(?MODULE, [], state0, [], {local,armitage});
  721: 	global ->
  722: 	    gen_fsm:enter_loop(?MODULE, [], state0, [], {global,armitage});
  723: 	via ->
  724: 	    gen_fsm:enter_loop(?MODULE, [], state0, [],
  725: 			       {via, dummy_via, armitage});
  726: 	anon ->
  727: 	    gen_fsm:enter_loop(?MODULE, [], state0, [])
  728:     end.
  729: 
  730: %%
  731: %% Functionality check
  732: %%
  733: 
  734: wfor(Msg) ->
  735:     receive 
  736: 	Msg -> ok
  737:     after 5000 -> 
  738: 	    throw(timeout)
  739:     end.
  740: 
  741: 
  742: stop_it(FSM) ->
  743:     ?line stopped = gen_fsm:sync_send_all_state_event(FSM, stop),
  744:     ?line {'EXIT',_} = 	(catch gen_fsm:sync_send_event(FSM, hej)),
  745:     ok.
  746: 
  747: 
  748: 
  749: do_func_test(FSM) ->
  750:     ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
  751:     wfor(yes),
  752:     ok = do_connect(FSM),
  753:     ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
  754:     wfor(yes),
  755:     test_server:do_times(3, ?MODULE, do_msg, [FSM]),
  756:     ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
  757:     wfor(yes),
  758:     ok = do_disconnect(FSM),
  759:     ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
  760:     wfor(yes),
  761:     ok.
  762: 
  763: 
  764: do_connect(FSM) ->
  765:     check_state(FSM, idle),
  766:     gen_fsm:send_event(FSM, {connect, self()}),
  767:     wfor(accept),
  768:     check_state(FSM, wfor_conf),
  769:     gen_fsm:send_event(FSM, confirmation),
  770:     check_state(FSM, connected),
  771:     ok.
  772: 
  773: do_msg(FSM) ->
  774:     check_state(FSM, connected),
  775:     R = make_ref(),
  776:     ok = gen_fsm:send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
  777:     wfor({ak, R}).
  778: 
  779: 
  780: do_disconnect(FSM) ->
  781:     ok = gen_fsm:send_event(FSM, disconnect),
  782:     check_state(FSM, idle).
  783: 
  784: check_state(FSM, State) ->
  785:     case gen_fsm:sync_send_all_state_event(FSM, {get, self()}) of
  786: 	{state, State, _} -> ok
  787:     end.
  788: 
  789: do_sync_func_test(FSM) ->
  790:     yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
  791:     ok = do_sync_connect(FSM),
  792:     yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
  793:     test_server:do_times(3, ?MODULE, do_sync_msg, [FSM]),
  794:     yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
  795:     ok = do_sync_disconnect(FSM),
  796:     yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
  797:     check_state(FSM, idle),
  798:     ok = gen_fsm:sync_send_event(FSM, {timeout,200}),
  799:     yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
  800:     check_state(FSM, idle),
  801:     ok.
  802: 
  803: 
  804: do_sync_connect(FSM) ->
  805:     check_state(FSM, idle),
  806:     accept = gen_fsm:sync_send_event(FSM, {connect, self()}),
  807:     check_state(FSM, wfor_conf),
  808:     yes = gen_fsm:sync_send_event(FSM, confirmation),
  809:     check_state(FSM, connected),
  810:     ok.
  811: 
  812: do_sync_msg(FSM) ->
  813:     check_state(FSM, connected),
  814:     R = make_ref(),
  815:     Res = gen_fsm:sync_send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
  816:     if  Res == {ak, R} ->
  817: 	    ok
  818:     end.
  819: 
  820: do_sync_disconnect(FSM) ->
  821:     yes = gen_fsm:sync_send_event(FSM, disconnect),
  822:     check_state(FSM, idle).
  823: 
  824:     
  825: 
  826: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  827: %%
  828: %% The Finite State Machine
  829: %%
  830: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  831: 
  832: init(ignore) ->
  833:     ignore;
  834: init(stop) ->
  835:     {stop, stopped};
  836: init(stop_shutdown) ->
  837:     {stop, shutdown};
  838: init(sleep) ->
  839:     test_server:sleep(1000),
  840:     {ok, idle, data};
  841: init({timeout, T}) ->
  842:     {ok, idle, state, T};
  843: init(hiber) ->
  844:     {ok, hiber_idle, []};
  845: init(hiber_now) ->
  846:     {ok, hiber_idle, [], hibernate};
  847: init({state_data, StateData}) ->
  848:     {ok, idle, StateData};
  849: init(_) ->
  850:     {ok, idle, state_data}.
  851: 
  852: 
  853: terminate({From, stopped}, State, _Data) ->
  854:     From ! {self(), {stopped, State}},
  855:     ok;
  856: terminate(_Reason, _State, _Data) ->
  857:     ok.
  858: 
  859: 
  860: idle({connect, Pid}, Data) ->
  861:     Pid ! accept,
  862:     {next_state, wfor_conf, Data};
  863: idle(badreturn, _Data) ->
  864:     badreturn;
  865: idle(_, Data) ->
  866:     {next_state, idle, Data}.
  867: 
  868: idle({connect, _Pid}, _From, Data) ->
  869:     {reply, accept, wfor_conf, Data};
  870: idle({delayed_answer, T}, _From, Data) ->
  871:     test_server:sleep(T),
  872:     {reply, delayed, idle, Data};
  873: idle(badreturn, _From, _Data) ->
  874:     badreturn;
  875: idle({timeout,Time}, From, _Data) ->
  876:     gen_fsm:send_event_after(Time, {timeout,Time}),
  877:     {next_state, timeout, From};
  878: idle(_, _From, Data) ->
  879:     {reply, 'eh?', idle, Data}.
  880: 
  881: timeout({timeout,Time}, From) ->
  882:     Ref = gen_fsm:start_timer(Time, {timeout,Time}),
  883:     {next_state, timeout, {From,Ref}};
  884: timeout({timeout,Ref,{timeout,Time}}, {From,Ref}) ->
  885:     Ref2 = gen_fsm:start_timer(Time, ok),
  886:     Cref = gen_fsm:start_timer(Time, cancel),
  887:     Time4 = Time*4,
  888:     receive after Time4 -> ok end,
  889:     gen_fsm:cancel_timer(Cref),
  890:     {next_state, timeout, {From,Ref2}};
  891: timeout({timeout,Ref2,ok},{From,Ref2}) ->
  892:     gen_fsm:reply(From, ok),
  893:     {next_state, idle, state}.
  894: 
  895: wfor_conf(confirmation, Data) ->
  896:     {next_state, connected, Data};
  897: wfor_conf(_, Data) ->
  898:     {next_state, idle, Data}.
  899: 
  900: wfor_conf(confirmation, _From, Data) ->
  901:     {reply, yes, connected, Data};
  902: wfor_conf(_, _From, Data) ->
  903:     {reply, 'eh?', idle, Data}.
  904: 
  905: connected({msg, Ref, From, _Msg}, Data) ->
  906:     From ! {ak, Ref},
  907:     {next_state, connected, Data};
  908: connected(disconnect, Data) ->
  909:     {next_state, idle, Data};
  910: connected(_, Data) ->
  911:     {next_state, connected, Data}.
  912: 
  913: connected({msg, Ref, _From, _Msg}, _, Data) ->
  914:     {reply, {ak, Ref}, connected, Data};
  915: connected(disconnect, _From, Data) ->
  916:     {reply, yes, idle, Data};
  917: connected(_, _, Data) ->
  918:     {reply, 'eh?', connected, Data}.
  919: 
  920: state0('alive?', _From, Data) ->
  921:     {reply, yes, state0, Data};
  922: state0(stop, _From, Data) ->
  923:     {stop, normal, stopped, Data}.
  924: 
  925: hiber_idle('alive?', _From, Data) ->
  926:     {reply, 'alive!', hiber_idle, Data};
  927: hiber_idle(hibernate_sync, _From, Data) ->
  928:     {reply, hibernating, hiber_wakeup, Data,hibernate}.
  929: hiber_idle(timeout, hibernate_me) ->  % Arrive here from 
  930: 				              % handle_info(hibernate_later,...)
  931:     {next_state, hiber_idle, [], hibernate};
  932: hiber_idle(hibernate_async, Data) ->
  933:     {next_state,hiber_wakeup, Data, hibernate}.
  934: 
  935: hiber_wakeup(wakeup_sync,_From,Data) ->
  936:     {reply,good_morning,hiber_idle,Data};
  937: hiber_wakeup(snooze_sync,_From,Data) ->
  938:     {reply,five_more,hiber_wakeup,Data,hibernate}.
  939: hiber_wakeup(wakeup_async,Data) ->
  940:     {next_state,hiber_idle,Data};
  941: hiber_wakeup(snooze_async,Data) ->
  942:     {next_state,hiber_wakeup,Data,hibernate}.
  943:     
  944: 
  945: handle_info(hibernate_now, _SName, _State) ->  % Arrive here from by direct ! from testcase
  946:     {next_state, hiber_idle, [], hibernate};
  947: handle_info(hibernate_later, _SName, _State) ->
  948:     {next_state, hiber_idle, hibernate_me, 1000};
  949: 
  950: handle_info(Info, _State, Data) ->
  951:     {stop, {unexpected,Info}, Data}.
  952: 
  953: handle_event(hibernate_async, hiber_idle, Data) ->
  954:     {next_state,hiber_wakeup, Data, hibernate};
  955: handle_event(wakeup_async,hiber_wakeup,Data) ->
  956:     {next_state,hiber_idle,Data};
  957: handle_event(snooze_async,hiber_wakeup,Data) ->
  958:     {next_state,hiber_wakeup,Data,hibernate};
  959: handle_event({get, Pid}, State, Data) ->
  960:     Pid ! {state, State, Data},
  961:     {next_state, State, Data};
  962: handle_event(stop, _State, Data) ->
  963:     {stop, normal, Data};
  964: handle_event(stop_shutdown, _State, Data) ->
  965:     {stop, shutdown, Data};
  966: handle_event(stop_shutdown_reason, _State, Data) ->
  967:     {stop, shutdown, Data};
  968: handle_event({'alive?', Pid}, State, Data) ->
  969:     Pid ! yes,
  970:     {next_state, State, Data}.
  971: 
  972: handle_sync_event(hibernate_sync, _From, hiber_idle, Data) ->
  973:     {reply, hibernating, hiber_wakeup, Data, hibernate};
  974: handle_sync_event(wakeup_sync,_From,hiber_wakeup, Data) ->
  975:     {reply,good_morning,hiber_idle,Data};
  976: handle_sync_event(snooze_sync,_From,hiber_wakeup,Data) ->
  977:     {reply,five_more,hiber_wakeup,Data,hibernate};
  978: handle_sync_event('alive?', _From, State, Data) ->
  979:     {reply, yes, State, Data};
  980: handle_sync_event(stop, _From, _State, Data) ->
  981:     {stop, normal, stopped, Data};
  982: handle_sync_event(stop_shutdown, _From, _State, Data) ->
  983:     {stop, shutdown, shutdown_stopped, Data};
  984: handle_sync_event(stop_shutdown_reason, _From, _State, Data) ->
  985:     {stop, {shutdown,reason}, {shutdown,reason}, Data};
  986: handle_sync_event({get, _Pid}, _From, State, Data) ->
  987:     {reply, {state, State, Data}, State, Data}.
  988: 
  989: format_status(terminate, [_Pdict, StateData]) ->
  990:     StateData;
  991: format_status(normal, [_Pdict, _StateData]) ->
  992:     [format_status_called].