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].