aboutsummaryrefslogtreecommitdiffstats
path: root/lib/stdlib/test/gen_fsm_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/stdlib/test/gen_fsm_SUITE.erl')
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl838
1 files changed, 838 insertions, 0 deletions
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
new file mode 100644
index 0000000000..62f8b2f9dd
--- /dev/null
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -0,0 +1,838 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(gen_fsm_SUITE).
+
+-include("test_server.hrl").
+
+%% Test cases
+-export([all/1]).
+
+-export([start/1, start1/1, start2/1, start3/1, start4/1 , start5/1, start6/1,
+ start7/1, start8/1, start9/1, start10/1, start11/1]).
+
+-export([abnormal/1, abnormal1/1, abnormal2/1]).
+
+-export([shutdown/1]).
+
+-export([sys/1, sys1/1]).
+
+-export([hibernate/1,hiber_idle/3,hiber_wakeup/3,hiber_idle/2,hiber_wakeup/2]).
+
+-export([enter_loop/1]).
+
+%% Exports for apply
+-export([do_msg/1, do_sync_msg/1]).
+-export([enter_loop/2]).
+
+% The gen_fsm behaviour
+-export([init/1, handle_event/3, handle_sync_event/4, terminate/3,
+ handle_info/3]).
+-export([idle/2, idle/3,
+ timeout/2,
+ wfor_conf/2, wfor_conf/3,
+ connected/2, connected/3]).
+-export([state0/3]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+all(suite) ->
+ [start, abnormal, shutdown, sys, hibernate, enter_loop].
+
+
+
+start(suite) -> [start1, start2, start3, start4, start5, start6, start7,
+ start8, start9, start10, start11].
+
+%% anonymous
+start1(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ stop_it(Pid0),
+%% ?line stopped = gen_fsm:sync_send_all_state_event(Pid0, stop),
+%% ?line {'EXIT', {timeout,_}} =
+%% (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ ?line test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous w. shutdown
+start2(Config) when is_list(Config) ->
+ %% Dont link when shutdown
+ ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line shutdown_stopped =
+ gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown),
+ ?line {'EXIT', {noproc,_}} =
+ (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ ?line test_server:messages_get(),
+ ok.
+
+%% anonymous with timeout
+start3(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], [{timeout,5}]),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line stop_it(Pid0),
+
+ ?line {error, timeout} = gen_fsm:start(gen_fsm_SUITE, sleep,
+ [{timeout,5}]),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous with ignore
+start4(suite) -> [];
+start4(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line ignore = gen_fsm:start(gen_fsm_SUITE, ignore, []),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous with stop
+start5(suite) -> [];
+start5(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {error, stopped} = gen_fsm:start(gen_fsm_SUITE, stop, []),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+%% anonymous linked
+start6(Config) when is_list(Config) ->
+ ?line {ok, Pid} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+
+ ok.
+
+%% global register linked
+start7(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test({global, my_fsm}),
+ ?line ok = do_sync_func_test({global, my_fsm}),
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+
+%% local register
+start8(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test(my_fsm),
+ ?line ok = do_sync_func_test(my_fsm),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% local register linked
+start9(Config) when is_list(Config) ->
+ %%OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test(my_fsm),
+ ?line ok = do_sync_func_test(my_fsm),
+ ?line stop_it(Pid),
+
+ test_server:messages_get(),
+ %%process_flag(trap_exit, OldFl),
+ ok.
+
+%% global register
+start10(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line {error, {already_started, Pid}} =
+ gen_fsm:start_link({global, my_fsm}, gen_fsm_SUITE, [], []),
+
+ ?line ok = do_func_test(Pid),
+ ?line ok = do_sync_func_test(Pid),
+ ?line ok = do_func_test({global, my_fsm}),
+ ?line ok = do_sync_func_test({global, my_fsm}),
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+
+%% Stop registered processes
+start11(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(Pid),
+
+ ?line {ok, _Pid1} =
+ gen_fsm:start_link({local, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(my_fsm),
+
+ ?line {ok, Pid2} =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ ?line stop_it(Pid2),
+ receive after 1 -> true end,
+ ?line Result =
+ gen_fsm:start({global, my_fsm}, gen_fsm_SUITE, [], []),
+ io:format("Result = ~p~n",[Result]),
+ ?line {ok, _Pid3} = Result,
+ ?line stop_it({global, my_fsm}),
+
+ test_server:messages_get(),
+ ok.
+
+abnormal(suite) -> [abnormal1, abnormal2].
+
+%% Check that time outs in calls work
+abnormal1(suite) -> [];
+abnormal1(Config) when is_list(Config) ->
+ ?line {ok, _Pid} =
+ gen_fsm:start({local, my_fsm}, gen_fsm_SUITE, [], []),
+
+ %% timeout call.
+ case os:type() of
+ vxworks ->
+ %% timeout call for VxWorks must be in 16ms increments.
+ ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 17),
+ ?line {'EXIT',{timeout,_}} =
+ (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,17}, 1));
+ _ ->
+ ?line delayed = gen_fsm:sync_send_event(my_fsm, {delayed_answer,1}, 100),
+ ?line {'EXIT',{timeout,_}} =
+ (catch gen_fsm:sync_send_event(my_fsm, {delayed_answer,10}, 1))
+ end,
+ test_server:messages_get(),
+ ok.
+
+%% Check that bad return values makes the fsm crash. Note that we must
+%% trap exit since we must link to get the real bad_return_ error
+abnormal2(suite) -> [];
+abnormal2(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+ ?line {ok, Pid} =
+ gen_fsm:start_link(gen_fsm_SUITE, [], []),
+
+ %% bad return value in the gen_fsm loop
+ ?line {'EXIT',{{bad_return_value, badreturn},_}} =
+ (catch gen_fsm:sync_send_event(Pid, badreturn)),
+
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+shutdown(Config) when is_list(Config) ->
+ ?line error_logger_forwarder:register(),
+
+ process_flag(trap_exit, true),
+
+ ?line {ok,Pid0} = gen_fsm:start_link(gen_fsm_SUITE, [], []),
+ ?line ok = do_func_test(Pid0),
+ ?line ok = do_sync_func_test(Pid0),
+ ?line {shutdown,reason} =
+ gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown_reason),
+ receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
+ process_flag(trap_exit, false),
+
+ ?line {'EXIT', {noproc,_}} =
+ (catch gen_fsm:sync_send_event(Pid0, hej)),
+
+ receive
+ Any ->
+ ?line io:format("Unexpected: ~p", [Any]),
+ ?line ?t:fail()
+ after 500 ->
+ ok
+ end,
+
+ ok.
+
+
+sys(suite) -> [sys1].
+
+sys1(Config) when is_list(Config) ->
+ ?line {ok, Pid} =
+ gen_fsm:start(gen_fsm_SUITE, [], []),
+ ?line {status, Pid, {module,gen_fsm}, _} = sys:get_status(Pid),
+ ?line sys:suspend(Pid),
+ ?line {'EXIT', {timeout,_}} =
+ (catch gen_fsm:sync_send_event(Pid, hej)),
+ ?line sys:resume(Pid),
+ ?line stop_it(Pid).
+
+
+%% Hibernation
+hibernate(suite) -> [];
+hibernate(Config) when is_list(Config) ->
+ OldFl = process_flag(trap_exit, true),
+
+ ?line {ok, Pid0} = gen_fsm:start_link(?MODULE, hiber_now, []),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid0,current_function),
+ ?line stop_it(Pid0),
+ test_server:messages_get(),
+
+
+ ?line {ok, Pid} = gen_fsm:start_link(?MODULE, hiber, []),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line five_more = gen_fsm:sync_send_event(Pid,snooze_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,snooze_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_later,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line receive after 2000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line Pid ! hibernate_now,
+ ?line receive after 1000 -> ok end,
+ ?line ({current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function)),
+ ?line 'alive!' = gen_fsm:sync_send_event(Pid,'alive?'),
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+
+
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line five_more = gen_fsm:sync_send_all_state_event(Pid,snooze_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line ok = gen_fsm:send_all_state_event(Pid,hibernate_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,snooze_async),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line ok = gen_fsm:send_all_state_event(Pid,wakeup_async),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+
+ ?line hibernating = gen_fsm:sync_send_all_state_event(Pid,hibernate_sync),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line sys:suspend(Pid),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+ ?line sys:resume(Pid),
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} = erlang:process_info(Pid,current_function),
+
+ ?line receive after 1000 -> ok end,
+ ?line {current_function,{erlang,hibernate,3}} =
+ erlang:process_info(Pid,current_function),
+ ?line good_morning = gen_fsm:sync_send_all_state_event(Pid,wakeup_sync),
+ ?line receive after 1000 -> ok end,
+ ?line true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
+ ?line stop_it(Pid),
+ test_server:messages_get(),
+ process_flag(trap_exit, OldFl),
+ ok.
+
+
+
+%%sys1(suite) -> [];
+%%sys1(_) ->
+
+enter_loop(suite) ->
+ [];
+enter_loop(doc) ->
+ ["Test gen_fsm:enter_loop/4,5,6"];
+enter_loop(Config) when is_list(Config) ->
+ OldFlag = process_flag(trap_exit, true),
+
+ %% Locally registered process + {local, Name}
+ ?line {ok, Pid1a} =
+ proc_lib:start_link(?MODULE, enter_loop, [local, local]),
+ ?line yes = gen_fsm:sync_send_event(Pid1a, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid1a, stop),
+ receive
+ {'EXIT', Pid1a, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + {local, Name}
+ ?line {ok, Pid1b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
+ receive
+ {'EXIT', Pid1b, process_not_registered} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Globally registered process + {global, Name}
+ ?line {ok, Pid2a} =
+ proc_lib:start_link(?MODULE, enter_loop, [global, global]),
+ ?line yes = gen_fsm:sync_send_event(Pid2a, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid2a, stop),
+ receive
+ {'EXIT', Pid2a, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + {global, Name}
+ ?line {ok, Pid2b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
+ receive
+ {'EXIT', Pid2b, process_not_registered_globally} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Unregistered process + no name
+ ?line {ok, Pid3} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
+ ?line yes = gen_fsm:sync_send_event(Pid3, 'alive?'),
+ ?line stopped = gen_fsm:sync_send_event(Pid3, stop),
+ receive
+ {'EXIT', Pid3, normal} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Process not started using proc_lib
+ ?line Pid4 =
+ spawn_link(gen_fsm, enter_loop, [?MODULE, [], state0, []]),
+ receive
+ {'EXIT', Pid4, process_was_not_started_by_proc_lib} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Make sure I am the parent, ie that ordering a shutdown will
+ %% result in the process terminating with Reason==shutdown
+ ?line {ok, Pid5} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, anon]),
+ ?line yes = gen_fsm:sync_send_event(Pid5, 'alive?'),
+ ?line exit(Pid5, shutdown),
+ receive
+ {'EXIT', Pid5, shutdown} ->
+ ok
+ after 5000 ->
+ ?line test_server:fail(gen_fsm_did_not_die)
+ end,
+
+ %% Make sure gen_fsm:enter_loop does not accept {local,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ register(armitage, self()),
+ ?line {ok, Pid6a} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, local]),
+ receive
+ {'EXIT', Pid6a, process_not_registered} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_fsm_started)
+ end,
+ unregister(armitage),
+
+ %% Make sure gen_fsm:enter_loop does not accept {global,Name}
+ %% when it's another process than the calling one which is
+ %% registered under that name
+ global:register_name(armitage, self()),
+ ?line {ok, Pid6b} =
+ proc_lib:start_link(?MODULE, enter_loop, [anon, global]),
+ receive
+ {'EXIT', Pid6b, process_not_registered_globally} ->
+ ok
+ after 1000 ->
+ ?line test_server:fail(gen_server_started)
+ end,
+ global:unregister_name(armitage),
+
+ process_flag(trap_exit, OldFlag),
+ ok.
+
+enter_loop(Reg1, Reg2) ->
+ process_flag(trap_exit, true),
+ case Reg1 of
+ local -> register(armitage, self());
+ global -> global:register_name(armitage, self());
+ anon -> ignore
+ end,
+ proc_lib:init_ack({ok, self()}),
+ case Reg2 of
+ local ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [], {local,armitage});
+ global ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [], {global,armitage});
+ anon ->
+ gen_fsm:enter_loop(?MODULE, [], state0, [])
+ end.
+
+%%
+%% Functionality check
+%%
+
+wfor(Msg) ->
+ receive
+ Msg -> ok
+ after 5000 ->
+ throw(timeout)
+ end.
+
+
+stop_it(FSM) ->
+ ?line stopped = gen_fsm:sync_send_all_state_event(FSM, stop),
+ ?line {'EXIT',_} = (catch gen_fsm:sync_send_event(FSM, hej)),
+ ok.
+
+
+
+do_func_test(FSM) ->
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok = do_connect(FSM),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ test_server:do_times(3, ?MODULE, do_msg, [FSM]),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok = do_disconnect(FSM),
+ ok = gen_fsm:send_all_state_event(FSM, {'alive?', self()}),
+ wfor(yes),
+ ok.
+
+
+do_connect(FSM) ->
+ check_state(FSM, idle),
+ gen_fsm:send_event(FSM, {connect, self()}),
+ wfor(accept),
+ check_state(FSM, wfor_conf),
+ gen_fsm:send_event(FSM, confirmation),
+ check_state(FSM, connected),
+ ok.
+
+do_msg(FSM) ->
+ check_state(FSM, connected),
+ R = make_ref(),
+ ok = gen_fsm:send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
+ wfor({ak, R}).
+
+
+do_disconnect(FSM) ->
+ ok = gen_fsm:send_event(FSM, disconnect),
+ check_state(FSM, idle).
+
+check_state(FSM, State) ->
+ case gen_fsm:sync_send_all_state_event(FSM, {get, self()}) of
+ {state, State, _} -> ok
+ end.
+
+do_sync_func_test(FSM) ->
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ ok = do_sync_connect(FSM),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ test_server:do_times(3, ?MODULE, do_sync_msg, [FSM]),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ ok = do_sync_disconnect(FSM),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ check_state(FSM, idle),
+ ok = gen_fsm:sync_send_event(FSM, {timeout,200}),
+ yes = gen_fsm:sync_send_all_state_event(FSM, 'alive?'),
+ check_state(FSM, idle),
+ ok.
+
+
+do_sync_connect(FSM) ->
+ check_state(FSM, idle),
+ accept = gen_fsm:sync_send_event(FSM, {connect, self()}),
+ check_state(FSM, wfor_conf),
+ yes = gen_fsm:sync_send_event(FSM, confirmation),
+ check_state(FSM, connected),
+ ok.
+
+do_sync_msg(FSM) ->
+ check_state(FSM, connected),
+ R = make_ref(),
+ Res = gen_fsm:sync_send_event(FSM, {msg, R, self(), hej_pa_dig_quasimodo}),
+ if Res == {ak, R} ->
+ ok
+ end.
+
+do_sync_disconnect(FSM) ->
+ yes = gen_fsm:sync_send_event(FSM, disconnect),
+ check_state(FSM, idle).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% The Finite State Machine
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(ignore) ->
+ ignore;
+init(stop) ->
+ {stop, stopped};
+init(stop_shutdown) ->
+ {stop, shutdown};
+init(sleep) ->
+ test_server:sleep(1000),
+ {ok, idle, data};
+init({timeout, T}) ->
+ {ok, idle, state, T};
+init(hiber) ->
+ {ok, hiber_idle, []};
+init(hiber_now) ->
+ {ok, hiber_idle, [], hibernate};
+init(_) ->
+ {ok, idle, state_data}.
+
+
+terminate({From, stopped}, State, _Data) ->
+ From ! {self(), {stopped, State}},
+ ok;
+terminate(_Reason, _State, _Data) ->
+ ok.
+
+
+idle({connect, Pid}, Data) ->
+ Pid ! accept,
+ {next_state, wfor_conf, Data};
+idle(badreturn, _Data) ->
+ badreturn;
+idle(_, Data) ->
+ {next_state, idle, Data}.
+
+idle({connect, _Pid}, _From, Data) ->
+ {reply, accept, wfor_conf, Data};
+idle({delayed_answer, T}, _From, Data) ->
+ test_server:sleep(T),
+ {reply, delayed, idle, Data};
+idle(badreturn, _From, _Data) ->
+ badreturn;
+idle({timeout,Time}, From, _Data) ->
+ gen_fsm:send_event_after(Time, {timeout,Time}),
+ {next_state, timeout, From};
+idle(_, _From, Data) ->
+ {reply, 'eh?', idle, Data}.
+
+timeout({timeout,Time}, From) ->
+ Ref = gen_fsm:start_timer(Time, {timeout,Time}),
+ {next_state, timeout, {From,Ref}};
+timeout({timeout,Ref,{timeout,Time}}, {From,Ref}) ->
+ Ref2 = gen_fsm:start_timer(Time, ok),
+ Cref = gen_fsm:start_timer(Time, cancel),
+ Time4 = Time*4,
+ receive after Time4 -> ok end,
+ gen_fsm:cancel_timer(Cref),
+ {next_state, timeout, {From,Ref2}};
+timeout({timeout,Ref2,ok},{From,Ref2}) ->
+ gen_fsm:reply(From, ok),
+ {next_state, idle, state}.
+
+wfor_conf(confirmation, Data) ->
+ {next_state, connected, Data};
+wfor_conf(_, Data) ->
+ {next_state, idle, Data}.
+
+wfor_conf(confirmation, _From, Data) ->
+ {reply, yes, connected, Data};
+wfor_conf(_, _From, Data) ->
+ {reply, 'eh?', idle, Data}.
+
+connected({msg, Ref, From, _Msg}, Data) ->
+ From ! {ak, Ref},
+ {next_state, connected, Data};
+connected(disconnect, Data) ->
+ {next_state, idle, Data};
+connected(_, Data) ->
+ {next_state, connected, Data}.
+
+connected({msg, Ref, _From, _Msg}, _, Data) ->
+ {reply, {ak, Ref}, connected, Data};
+connected(disconnect, _From, Data) ->
+ {reply, yes, idle, Data};
+connected(_, _, Data) ->
+ {reply, 'eh?', connected, Data}.
+
+state0('alive?', _From, Data) ->
+ {reply, yes, state0, Data};
+state0(stop, _From, Data) ->
+ {stop, normal, stopped, Data}.
+
+hiber_idle('alive?', _From, Data) ->
+ {reply, 'alive!', hiber_idle, Data};
+hiber_idle(hibernate_sync, _From, Data) ->
+ {reply, hibernating, hiber_wakeup, Data,hibernate}.
+hiber_idle(timeout, hibernate_me) -> % Arrive here from
+ % handle_info(hibernate_later,...)
+ {next_state, hiber_idle, [], hibernate};
+hiber_idle(hibernate_async, Data) ->
+ {next_state,hiber_wakeup, Data, hibernate}.
+
+hiber_wakeup(wakeup_sync,_From,Data) ->
+ {reply,good_morning,hiber_idle,Data};
+hiber_wakeup(snooze_sync,_From,Data) ->
+ {reply,five_more,hiber_wakeup,Data,hibernate}.
+hiber_wakeup(wakeup_async,Data) ->
+ {next_state,hiber_idle,Data};
+hiber_wakeup(snooze_async,Data) ->
+ {next_state,hiber_wakeup,Data,hibernate}.
+
+
+handle_info(hibernate_now, _SName, _State) -> % Arrive here from by direct ! from testcase
+ {next_state, hiber_idle, [], hibernate};
+handle_info(hibernate_later, _SName, _State) ->
+ {next_state, hiber_idle, hibernate_me, 1000};
+
+handle_info(Info, _State, Data) ->
+ {stop, {unexpected,Info}, Data}.
+
+handle_event(hibernate_async, hiber_idle, Data) ->
+ {next_state,hiber_wakeup, Data, hibernate};
+handle_event(wakeup_async,hiber_wakeup,Data) ->
+ {next_state,hiber_idle,Data};
+handle_event(snooze_async,hiber_wakeup,Data) ->
+ {next_state,hiber_wakeup,Data,hibernate};
+handle_event({get, Pid}, State, Data) ->
+ Pid ! {state, State, Data},
+ {next_state, State, Data};
+handle_event(stop, _State, Data) ->
+ {stop, normal, Data};
+handle_event(stop_shutdown, _State, Data) ->
+ {stop, shutdown, Data};
+handle_event(stop_shutdown_reason, _State, Data) ->
+ {stop, shutdown, Data};
+handle_event({'alive?', Pid}, State, Data) ->
+ Pid ! yes,
+ {next_state, State, Data}.
+
+handle_sync_event(hibernate_sync, _From, hiber_idle, Data) ->
+ {reply, hibernating, hiber_wakeup, Data, hibernate};
+handle_sync_event(wakeup_sync,_From,hiber_wakeup, Data) ->
+ {reply,good_morning,hiber_idle,Data};
+handle_sync_event(snooze_sync,_From,hiber_wakeup,Data) ->
+ {reply,five_more,hiber_wakeup,Data,hibernate};
+handle_sync_event('alive?', _From, State, Data) ->
+ {reply, yes, State, Data};
+handle_sync_event(stop, _From, _State, Data) ->
+ {stop, normal, stopped, Data};
+handle_sync_event(stop_shutdown, _From, _State, Data) ->
+ {stop, shutdown, shutdown_stopped, Data};
+handle_sync_event(stop_shutdown_reason, _From, _State, Data) ->
+ {stop, {shutdown,reason}, {shutdown,reason}, Data};
+handle_sync_event({get, _Pid}, _From, State, Data) ->
+ {reply, {state, State, Data}, State, Data}.