From 6ace96d3e5c9ac8ace3d8967bcafb3e6a081d9be Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 26 Oct 2015 11:52:17 +0100 Subject: New state machine --- lib/stdlib/test/Makefile | 1 + lib/stdlib/test/error_logger_forwarder.erl | 8 +- lib/stdlib/test/gen_statem_SUITE.erl | 1250 ++++++++++++++++++++++++++++ 3 files changed, 1257 insertions(+), 2 deletions(-) create mode 100644 lib/stdlib/test/gen_statem_SUITE.erl (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile index e366c2b755..427d7fcaea 100644 --- a/lib/stdlib/test/Makefile +++ b/lib/stdlib/test/Makefile @@ -46,6 +46,7 @@ MODULES= \ gen_event_SUITE \ gen_fsm_SUITE \ gen_server_SUITE \ + gen_statem_SUITE \ id_transform_SUITE \ io_SUITE \ io_proto_SUITE \ diff --git a/lib/stdlib/test/error_logger_forwarder.erl b/lib/stdlib/test/error_logger_forwarder.erl index 7ac2cfce82..d34dde9def 100644 --- a/lib/stdlib/test/error_logger_forwarder.erl +++ b/lib/stdlib/test/error_logger_forwarder.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2015. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ -module(error_logger_forwarder). %% API. --export([register/0]). +-export([register/0, unregister/0]). %% Internal export for error_logger. -export([init/1, @@ -33,6 +33,10 @@ register() -> error_logger:add_report_handler(?MODULE, self()). +unregister() -> + Self = self(), + Self = error_logger:delete_report_handler(?MODULE). + init(Tester) -> {ok,Tester}. diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl new file mode 100644 index 0000000000..342be32acb --- /dev/null +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -0,0 +1,1250 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2016. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% +-module(gen_statem_SUITE). + +-include_lib("test_server/include/test_server.hrl"). + +-compile(export_all). +-behaviour(gen_statem). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [{group, start}, + {group, abnormal}, + shutdown, + {group, sys}, hibernate, enter_loop]. + +groups() -> + [{start, [], + [start1, start2, start3, start4, start5, start6, start7, + start8, start9, start10, start11, start12]}, + {stop, [], + [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]}, + {abnormal, [], [abnormal1, abnormal2]}, + {sys, [], + [sys1, + call_format_status, + error_format_status, terminate_crash_format, + get_state, replace_state]}]. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +init_per_testcase(_CaseName, Config) -> + ?t:messages_get(), + Dog = ?t:timetrap(?t:minutes(1)), +%%% dbg:tracer(), +%%% dbg:p(all, c), +%%% dbg:tpl(gen_statem, cx), + [{watchdog, Dog} | Config]. + +end_per_testcase(_CaseName, Config) -> +%%% dbg:stop(), + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + Config. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(EXPECT_FAILURE(Code, Reason), + try begin Code end of + _ -> + ?t:fail() + catch + error:Reason -> Reason; + exit:Reason -> Reason + end). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% anonymous +start1(Config) when is_list(Config) -> + %%OldFl = process_flag(trap_exit, true), + + {ok,Pid0} = gen_statem:start_link(?MODULE, [], []), + ok = do_func_test(Pid0), + ok = do_sync_func_test(Pid0), + stop_it(Pid0), +%% stopped = gen_statem:call(Pid0, stop), +%% timeout = +%% ?EXPECT_FAILURE(gen_statem:call(Pid0, hej), Reason), + + %%process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% anonymous w. shutdown +start2(Config) when is_list(Config) -> + %% Dont link when shutdown + {ok,Pid0} = gen_statem:start(?MODULE, [], []), + ok = do_func_test(Pid0), + ok = do_sync_func_test(Pid0), + stopped = gen_statem:call(Pid0, {stop,shutdown}), + check_stopped(Pid0), + ok = verify_empty_msgq(). + +%% anonymous with timeout +start3(Config) when is_list(Config) -> + %%OldFl = process_flag(trap_exit, true), + + {ok,Pid0} = gen_statem:start(?MODULE, [], [{timeout,5}]), + ok = do_func_test(Pid0), + ok = do_sync_func_test(Pid0), + stop_it(Pid0), + + {error,timeout} = gen_statem:start(?MODULE, sleep, + [{timeout,5}]), + + %%process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% anonymous with ignore +start4(Config) when is_list(Config) -> + OldFl = process_flag(trap_exit, true), + + ignore = gen_statem:start(?MODULE, ignore, []), + + process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% anonymous with stop +start5(suite) -> []; +start5(Config) when is_list(Config) -> + OldFl = process_flag(trap_exit, true), + + {error,stopped} = gen_statem:start(?MODULE, stop, []), + + process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% anonymous linked +start6(Config) when is_list(Config) -> + {ok,Pid} = gen_statem:start_link(?MODULE, [], []), + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + stop_it(Pid), + + ok = verify_empty_msgq(). + +%% global register linked +start7(Config) when is_list(Config) -> + STM = {global,my_stm}, + + {ok,Pid} = + gen_statem:start_link(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start_link(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start(STM, ?MODULE, [], []), + + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + ok = do_func_test(STM), + ok = do_sync_func_test(STM), + stop_it(STM), + + ok = verify_empty_msgq(). + + +%% local register +start8(Config) when is_list(Config) -> + %%OldFl = process_flag(trap_exit, true), + Name = my_stm, + STM = {local,Name}, + + {ok,Pid} = + gen_statem:start(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start(STM, ?MODULE, [], []), + + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + ok = do_func_test(Name), + ok = do_sync_func_test(Name), + stop_it(Pid), + + %%process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% local register linked +start9(Config) when is_list(Config) -> + %%OldFl = process_flag(trap_exit, true), + Name = my_stm, + STM = {local,Name}, + + {ok,Pid} = + gen_statem:start_link(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start(STM, ?MODULE, [], []), + + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + ok = do_func_test(Name), + ok = do_sync_func_test(Name), + stop_it(Pid), + + %%process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +%% global register +start10(Config) when is_list(Config) -> + STM = {global,my_stm}, + + {ok,Pid} = + gen_statem:start(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start(STM, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start_link(STM, ?MODULE, [], []), + + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + ok = do_func_test(STM), + ok = do_sync_func_test(STM), + stop_it(STM), + + ok = verify_empty_msgq(). + +%% Stop registered processes +start11(Config) when is_list(Config) -> + Name = my_stm, + LocalSTM = {local,Name}, + GlobalSTM = {global,Name}, + + {ok,Pid} = + gen_statem:start_link(LocalSTM, ?MODULE, [], []), + stop_it(Pid), + + {ok,_Pid1} = + gen_statem:start_link(LocalSTM, ?MODULE, [], []), + stop_it(Name), + + {ok,Pid2} = + gen_statem:start(GlobalSTM, ?MODULE, [], []), + stop_it(Pid2), + receive after 1 -> true end, + Result = + gen_statem:start(GlobalSTM, ?MODULE, [], []), + io:format("Result = ~p~n",[Result]), + {ok,_Pid3} = Result, + stop_it(GlobalSTM), + + ok = verify_empty_msgq(). + +%% Via register linked +start12(Config) when is_list(Config) -> + dummy_via:reset(), + VIA = {via,dummy_via,my_stm}, + + {ok,Pid} = + gen_statem:start_link(VIA, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start_link(VIA, ?MODULE, [], []), + {error,{already_started,Pid}} = + gen_statem:start(VIA, ?MODULE, [], []), + + ok = do_func_test(Pid), + ok = do_sync_func_test(Pid), + ok = do_func_test(VIA), + ok = do_sync_func_test(VIA), + stop_it(VIA), + + ok = verify_empty_msgq(). + + +%% Anonymous, reason 'normal' +stop1(_Config) -> + {ok,Pid} = gen_statem:start(?MODULE, [], []), + ok = gen_statem:stop(Pid), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason). + +%% Anonymous, other reason +stop2(_Config) -> + {ok,Pid} = gen_statem:start(?MODULE, [], []), + ok = gen_statem:stop(Pid, other_reason, infinity), + false = erlang:is_process_alive(Pid), + ok. + +%% Anonymous, invalid timeout +stop3(_Config) -> + {ok,Pid} = gen_statem:start(?MODULE, [], []), + _ = + ?EXPECT_FAILURE( + gen_statem:stop(Pid, other_reason, invalid_timeout), + Reason), + true = erlang:is_process_alive(Pid), + ok = gen_statem:stop(Pid), + false = erlang:is_process_alive(Pid), + ok. + +%% Registered name +stop4(_Config) -> + {ok,Pid} = gen_statem:start({local,to_stop},?MODULE, [], []), + ok = gen_statem:stop(to_stop), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(to_stop), Reason), + ok. + +%% Registered name and local node +stop5(_Config) -> + Name = to_stop, + {ok,Pid} = gen_statem:start({local,Name},?MODULE, [], []), + ok = gen_statem:stop({Name,node()}), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop({Name,node()}), Reason), + ok. + +%% Globally registered name +stop6(_Config) -> + STM = {global,to_stop}, + {ok,Pid} = gen_statem:start(STM, ?MODULE, [], []), + ok = gen_statem:stop(STM), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason), + ok. + +%% 'via' registered name +stop7(_Config) -> + VIA = {via,dummy_via,to_stop}, + dummy_via:reset(), + {ok,Pid} = gen_statem:start(VIA, + ?MODULE, [], []), + ok = gen_statem:stop(VIA), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(VIA), Reason), + ok. + +%% Anonymous on remote node +stop8(_Config) -> + {ok,Node} = ?t:start_node(gen_statem_stop8, slave, []), + Dir = filename:dirname(code:which(?MODULE)), + rpc:call(Node, code, add_path, [Dir]), + {ok,Pid} = rpc:call(Node, gen_statem,start, [?MODULE,[],[]]), + ok = gen_statem:stop(Pid), + false = rpc:call(Node, erlang, is_process_alive, [Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason1), + true = ?t:stop_node(Node), + {nodedown,Node} = + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason2), + ok. + +%% Registered name on remote node +stop9(_Config) -> + Name = to_stop, + LocalSTM = {local,Name}, + {ok,Node} = ?t:start_node(gen_statem__stop9, slave, []), + STM = {Name,Node}, + Dir = filename:dirname(code:which(?MODULE)), + rpc:call(Node, code, add_path, [Dir]), + {ok,Pid} = rpc:call(Node, gen_statem, start, [LocalSTM,?MODULE,[],[]]), + ok = gen_statem:stop(STM), + undefined = rpc:call(Node,erlang,whereis,[Name]), + false = rpc:call(Node,erlang,is_process_alive,[Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), + true = ?t:stop_node(Node), + {nodedown,Node} = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), + ok. + +%% Globally registered name on remote node +stop10(_Config) -> + STM = {global,to_stop}, + {ok,Node} = ?t:start_node(gen_statem_stop10, slave, []), + Dir = filename:dirname(code:which(?MODULE)), + rpc:call(Node,code,add_path,[Dir]), + {ok,Pid} = rpc:call(Node, gen_statem, start, [STM,?MODULE,[],[]]), + global:sync(), + ok = gen_statem:stop(STM), + false = rpc:call(Node, erlang, is_process_alive, [Pid]), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), + true = ?t:stop_node(Node), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), + ok. + +%% Check that time outs in calls work +abnormal1(Config) when is_list(Config) -> + Name = abnormal1, + LocalSTM = {local,Name}, + + {ok, _Pid} = gen_statem:start(LocalSTM, ?MODULE, [], []), + + %% timeout call. + delayed = gen_statem:call(Name, {delayed_answer,1}, 100), + {timeout,_} = + ?EXPECT_FAILURE( + gen_statem:call(Name, {delayed_answer,1000}, 10), + Reason), + ok = verify_empty_msgq(). + +%% Check that bad return values makes the stm crash. Note that we must +%% trap exit since we must link to get the real bad_return_ error +abnormal2(Config) when is_list(Config) -> + OldFl = process_flag(trap_exit, true), + {ok,Pid} = gen_statem:start_link(?MODULE, [], []), + + %% bad return value in the gen_statem loop + {{bad_return_value,badreturn},_} = + ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), + receive + {'EXIT',Pid,{bad_return_value,badreturn}} -> ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + process_flag(trap_exit, OldFl), + ok = verify_empty_msgq(). + +shutdown(Config) when is_list(Config) -> + process_flag(trap_exit, true), + + {ok,Pid0} = gen_statem:start_link(?MODULE, [], []), + ok = do_func_test(Pid0), + ok = do_sync_func_test(Pid0), + stopped = gen_statem:call(Pid0, {stop,{shutdown,reason}}), + receive {'EXIT',Pid0,{shutdown,reason}} -> ok end, + process_flag(trap_exit, false), + + {noproc,_} = + ?EXPECT_FAILURE(gen_statem:call(Pid0, hej), Reason), + + receive + Any -> + io:format("Unexpected: ~p", [Any]), + ?t:fail() + after 500 -> + ok + end. + + + +sys1(Config) when is_list(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, [], []), + {status, Pid, {module,gen_statem}, _} = sys:get_status(Pid), + sys:suspend(Pid), + Parent = self(), + Tag = make_ref(), + Caller = + spawn( + fun () -> + Parent ! {Tag,gen_statem:call(Pid, hej)} + end), + receive + {Tag,_} -> + ?t:fail() + after 3000 -> + exit(Caller, ok) + end, + + %% {timeout,_} = + %% ?EXPECT_FAILURE(gen_statem:call(Pid, hej), Reason), + sys:resume(Pid), + stop_it(Pid). + +call_format_status(Config) when is_list(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, [], []), + Status = sys:get_status(Pid), + {status,Pid,_Mod,[_PDict,running,_,_, Data]} = Status, + [format_status_called|_] = lists:reverse(Data), + stop_it(Pid), + + %% check that format_status can handle a name being an atom (pid is + %% already checked by the previous test) + {ok, Pid2} = gen_statem:start({local, gstm}, ?MODULE, [], []), + Status2 = sys:get_status(gstm), + {status,Pid2,_Mod,[_PDict2,running,_,_,Data2]} = Status2, + [format_status_called|_] = lists:reverse(Data2), + stop_it(Pid2), + + %% check that format_status can handle a name being a term other than a + %% pid or atom + GlobalName1 = {global,"CallFormatStatus"}, + {ok,Pid3} = gen_statem:start(GlobalName1, ?MODULE, [], []), + Status3 = sys:get_status(GlobalName1), + {status,Pid3,_Mod,[_PDict3,running,_,_,Data3]} = Status3, + [format_status_called|_] = lists:reverse(Data3), + stop_it(Pid3), + GlobalName2 = {global,{name, "term"}}, + {ok,Pid4} = gen_statem:start(GlobalName2, ?MODULE, [], []), + Status4 = sys:get_status(GlobalName2), + {status,Pid4,_Mod,[_PDict4,running,_,_, Data4]} = Status4, + [format_status_called|_] = lists:reverse(Data4), + stop_it(Pid4), + + %% check that format_status can handle a name being a term other than a + %% pid or atom + dummy_via:reset(), + ViaName1 = {via,dummy_via,"CallFormatStatus"}, + {ok,Pid5} = gen_statem:start(ViaName1, ?MODULE, [], []), + Status5 = sys:get_status(ViaName1), + {status,Pid5,_Mod, [_PDict5,running,_,_, Data5]} = Status5, + [format_status_called|_] = lists:reverse(Data5), + stop_it(Pid5), + ViaName2 = {via,dummy_via,{name,"term"}}, + {ok, Pid6} = gen_statem:start(ViaName2, ?MODULE, [], []), + Status6 = sys:get_status(ViaName2), + {status,Pid6,_Mod,[_PDict6,running,_,_,Data6]} = Status6, + [format_status_called|_] = lists:reverse(Data6), + stop_it(Pid6). + + + +error_format_status(Config) when is_list(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + StateData = "called format_status", + {ok,Pid} = gen_statem:start(?MODULE, {state_data,StateData}, []), + %% bad return value in the gen_statem loop + {{bad_return_value,badreturn},_} = + ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), + receive + {error,_, + {Pid, + "** State machine"++_, + [Pid,{{call,_},badreturn}, + {formatted,idle,StateData}, + exit,{bad_return_value,badreturn}|_]}} -> + ok; + Other when is_tuple(Other), element(1, Other) =:= error -> + error_logger_forwarder:unregister(), + ?t:fail({unexpected,Other}) + after 1000 -> + error_logger_forwarder:unregister(), + ?t:fail() + end, + process_flag(trap_exit, OldFl), + error_logger_forwarder:unregister(), + receive + %% Comes with SASL + {error_report,_,{Pid,crash_report,_}} -> + ok + after 500 -> + ok + end, + ok = verify_empty_msgq(). + +terminate_crash_format(Config) when is_list(Config) -> + error_logger_forwarder:register(), + OldFl = process_flag(trap_exit, true), + StateData = crash_terminate, + {ok,Pid} = gen_statem:start(?MODULE, {state_data,StateData}, []), + stop_it(Pid), + Self = self(), + receive + {error,_GroupLeader, + {Pid, + "** State machine"++_, + [Pid, + {{call,{Self,_}},stop}, + {formatted,idle,StateData}, + exit,{crash,terminate}|_]}} -> + ok; + Other when is_tuple(Other), element(1, Other) =:= error -> + error_logger_forwarder:unregister(), + ?t:fail({unexpected,Other}) + after 1000 -> + error_logger_forwarder:unregister(), + ?t:fail() + end, + process_flag(trap_exit, OldFl), + error_logger_forwarder:unregister(), + receive + %% Comes with SASL + {error_report,_,{Pid,crash_report,_}} -> + ok + after 500 -> + ok + end, + ok = verify_empty_msgq(). + + +get_state(Config) when is_list(Config) -> + State = self(), + {ok,Pid} = gen_statem:start(?MODULE, {state_data,State}, []), + {idle,State} = sys:get_state(Pid), + {idle,State} = sys:get_state(Pid, 5000), + stop_it(Pid), + + %% check that get_state can handle a name being an atom (pid is + %% already checked by the previous test) + {ok,Pid2} = + gen_statem:start({local,gstm}, ?MODULE, {state_data,State}, []), + {idle,State} = sys:get_state(gstm), + {idle,State} = sys:get_state(gstm, 5000), + stop_it(Pid2), + + %% check that get_state works when pid is sys suspended + {ok,Pid3} = gen_statem:start(?MODULE, {state_data,State}, []), + {idle,State} = sys:get_state(Pid3), + ok = sys:suspend(Pid3), + {idle,State} = sys:get_state(Pid3, 5000), + ok = sys:resume(Pid3), + stop_it(Pid3), + ok = verify_empty_msgq(). + +replace_state(Config) when is_list(Config) -> + State = self(), + {ok, Pid} = gen_statem:start(?MODULE, {state_data,State}, []), + {idle,State} = sys:get_state(Pid), + NState1 = "replaced", + Replace1 = fun({StateName, _}) -> {StateName,NState1} end, + {idle,NState1} = sys:replace_state(Pid, Replace1), + {idle,NState1} = sys:get_state(Pid), + NState2 = "replaced again", + Replace2 = fun({idle, _}) -> {state0,NState2} end, + {state0,NState2} = sys:replace_state(Pid, Replace2, 5000), + {state0,NState2} = sys:get_state(Pid), + %% verify no change in state if replace function crashes + Replace3 = fun(_) -> error(fail) end, + {callback_failed, + {gen_statem,system_replace_state},{error,fail}} = + ?EXPECT_FAILURE(sys:replace_state(Pid, Replace3), Reason), + {state0, NState2} = sys:get_state(Pid), + %% verify state replaced if process sys suspended + ok = sys:suspend(Pid), + Suffix2 = " and again", + NState3 = NState2 ++ Suffix2, + Replace4 = fun({StateName, _}) -> {StateName, NState3} end, + {state0,NState3} = sys:replace_state(Pid, Replace4), + ok = sys:resume(Pid), + {state0,NState3} = sys:get_state(Pid, 5000), + stop_it(Pid), + ok = verify_empty_msgq(). + +%% Hibernation +hibernate(Config) when is_list(Config) -> + OldFl = process_flag(trap_exit, true), + + {ok,Pid0} = gen_statem:start_link(?MODULE, hiber_now, []), + is_in_erlang_hibernate(Pid0), + stop_it(Pid0), + receive + {'EXIT',Pid0,normal} -> ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + {ok,Pid} = gen_statem:start_link(?MODULE, hiber, []), + true = ({current_function,{erlang,hibernate,3}} =/= + erlang:process_info(Pid,current_function)), + hibernating = gen_statem:call(Pid, hibernate_sync), + is_in_erlang_hibernate(Pid), + good_morning = gen_statem:call(Pid, wakeup_sync), + is_not_in_erlang_hibernate(Pid), + hibernating = gen_statem:call(Pid, hibernate_sync), + is_in_erlang_hibernate(Pid), + please_just_five_more = gen_statem:call(Pid, snooze_sync), + is_in_erlang_hibernate(Pid), + good_morning = gen_statem:call(Pid, wakeup_sync), + is_not_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, hibernate_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, wakeup_async), + is_not_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, hibernate_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, snooze_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, wakeup_async), + is_not_in_erlang_hibernate(Pid), + + Pid ! hibernate_later, + true = + ({current_function,{erlang,hibernate,3}} =/= + erlang:process_info(Pid, current_function)), + is_in_erlang_hibernate(Pid), + + 'alive!' = gen_statem:call(Pid, 'alive?'), + true = + ({current_function,{erlang,hibernate,3}} =/= + erlang:process_info(Pid, current_function)), + Pid ! hibernate_now, + is_in_erlang_hibernate(Pid), + + 'alive!' = gen_statem:call(Pid, 'alive?'), + true = + ({current_function,{erlang,hibernate,3}} =/= + erlang:process_info(Pid, current_function)), + + hibernating = gen_statem:call(Pid, hibernate_sync), + is_in_erlang_hibernate(Pid), + good_morning = gen_statem:call(Pid, wakeup_sync), + is_not_in_erlang_hibernate(Pid), + hibernating = gen_statem:call(Pid, hibernate_sync), + is_in_erlang_hibernate(Pid), + please_just_five_more = gen_statem:call(Pid, snooze_sync), + is_in_erlang_hibernate(Pid), + good_morning = gen_statem:call(Pid, wakeup_sync), + is_not_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, hibernate_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, wakeup_async), + is_not_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, hibernate_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, snooze_async), + is_in_erlang_hibernate(Pid), + ok = gen_statem:cast(Pid, wakeup_async), + is_not_in_erlang_hibernate(Pid), + + hibernating = gen_statem:call(Pid, hibernate_sync), + is_in_erlang_hibernate(Pid), + sys:suspend(Pid), + is_in_erlang_hibernate(Pid), + sys:resume(Pid), + is_in_erlang_hibernate(Pid), + receive after 1000 -> ok end, + is_in_erlang_hibernate(Pid), + + good_morning = gen_statem:call(Pid, wakeup_sync), + is_not_in_erlang_hibernate(Pid), + stop_it(Pid), + process_flag(trap_exit, OldFl), + receive + {'EXIT',Pid,normal} -> ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + ok = verify_empty_msgq(). + +is_in_erlang_hibernate(Pid) -> + receive after 1 -> ok end, + is_in_erlang_hibernate_1(200, Pid). + +is_in_erlang_hibernate_1(0, Pid) -> + io:format("~p\n", [erlang:process_info(Pid, current_function)]), + ?t:fail(not_in_erlang_hibernate_3); +is_in_erlang_hibernate_1(N, Pid) -> + {current_function,MFA} = erlang:process_info(Pid, current_function), + case MFA of + {erlang,hibernate,3} -> + ok; + _ -> + receive after 10 -> ok end, + is_in_erlang_hibernate_1(N-1, Pid) + end. + +is_not_in_erlang_hibernate(Pid) -> + receive after 1 -> ok end, + is_not_in_erlang_hibernate_1(200, Pid). + +is_not_in_erlang_hibernate_1(0, Pid) -> + io:format("~p\n", [erlang:process_info(Pid, current_function)]), + ?t:fail(not_in_erlang_hibernate_3); +is_not_in_erlang_hibernate_1(N, Pid) -> + {current_function,MFA} = erlang:process_info(Pid, current_function), + case MFA of + {erlang,hibernate,3} -> + receive after 10 -> ok end, + is_not_in_erlang_hibernate_1(N-1, Pid); + _ -> + ok + end. + +%%sys1(suite) -> []; +%%sys1(_) -> + +enter_loop(Config) when is_list(Config) -> + OldFlag = process_flag(trap_exit, true), + + dummy_via:reset(), + + %% Locally registered process + {local,Name} + {ok,Pid1a} = + proc_lib:start_link(?MODULE, enter_loop, [local,local]), + yes = gen_statem:call(Pid1a, 'alive?'), + stopped = gen_statem:call(Pid1a, stop), + receive + {'EXIT',Pid1a,normal} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Unregistered process + {local,Name} + {ok,Pid1b} = + proc_lib:start_link(?MODULE, enter_loop, [anon,local]), + receive + {'EXIT',Pid1b,process_not_registered} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Globally registered process + {global,Name} + {ok,Pid2a} = + proc_lib:start_link(?MODULE, enter_loop, [global,global]), + yes = gen_statem:call(Pid2a, 'alive?'), + stopped = gen_statem:call(Pid2a, stop), + receive + {'EXIT',Pid2a,normal} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Unregistered process + {global,Name} + {ok,Pid2b} = + proc_lib:start_link(?MODULE, enter_loop, [anon,global]), + receive + {'EXIT',Pid2b,process_not_registered_globally} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Unregistered process + no name + {ok,Pid3} = + proc_lib:start_link(?MODULE, enter_loop, [anon,anon]), + yes = gen_statem:call(Pid3, 'alive?'), + stopped = gen_statem:call(Pid3, stop), + receive + {'EXIT',Pid3,normal} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Process not started using proc_lib + Pid4 = + spawn_link(gen_statem, enter_loop, [?MODULE,[],state0,[]]), + receive + {'EXIT',Pid4,process_was_not_started_by_proc_lib} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Make sure I am the parent, ie that ordering a shutdown will + %% result in the process terminating with Reason==shutdown + {ok,Pid5} = + proc_lib:start_link(?MODULE, enter_loop, [anon,anon]), + yes = gen_statem:call(Pid5, 'alive?'), + exit(Pid5, shutdown), + receive + {'EXIT',Pid5,shutdown} -> + ok + after 5000 -> + ?t:fail(gen_statem_did_not_die) + end, + + %% Make sure gen_statem: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()), + {ok,Pid6a} = + proc_lib:start_link(?MODULE, enter_loop, [anon,local]), + receive + {'EXIT',Pid6a,process_not_registered} -> + ok + after 1000 -> + ?t:fail(gen_statem_started) + end, + unregister(armitage), + + %% Make sure gen_statem: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()), + {ok,Pid6b} = + proc_lib:start_link(?MODULE, enter_loop, [anon,global]), + receive + {'EXIT',Pid6b,process_not_registered_globally} -> + ok + after 1000 -> + ?t:fail(gen_statem_started) + end, + global:unregister_name(armitage), + + dummy_via:register_name(armitage, self()), + {ok,Pid6c} = + proc_lib:start_link(?MODULE, enter_loop, [anon,via]), + receive + {'EXIT',Pid6c,{process_not_registered_via,dummy_via}} -> + ok + after 1000 -> + ?t:fail( + {gen_statem_started, + process_info(self(), messages)}) + end, + dummy_via:unregister_name(armitage), + + process_flag(trap_exit, OldFlag), + ok = verify_empty_msgq(). + +enter_loop(Reg1, Reg2) -> + process_flag(trap_exit, true), + case Reg1 of + local -> register(armitage, self()); + global -> global:register_name(armitage, self()); + via -> dummy_via:register_name(armitage, self()); + anon -> ignore + end, + proc_lib:init_ack({ok, self()}), + case Reg2 of + local -> + gen_statem:enter_loop(?MODULE, [], state0, [], {local,armitage}); + global -> + gen_statem:enter_loop(?MODULE, [], state0, [], {global,armitage}); + via -> + gen_statem:enter_loop(?MODULE, [], state0, [], + {via, dummy_via, armitage}); + anon -> + gen_statem:enter_loop(?MODULE, [], state0, []) + end. + +%% +%% Functionality check +%% + +wfor(Msg) -> + receive + Msg -> ok + after 5000 -> + error(timeout) + end. + + +stop_it(STM) -> + stopped = gen_statem:call(STM, stop), + check_stopped(STM). + + +check_stopped(STM) -> + Call = there_you_are, + {_,{gen_statem,call,[_,Call,infinity]}} = + ?EXPECT_FAILURE(gen_statem:call(STM, Call), Reason), + ok. + + +do_func_test(STM) -> + ok = gen_statem:cast(STM, {'alive?',self()}), + wfor(yes), + ok = do_connect(STM), + ok = gen_statem:cast(STM, {'alive?',self()}), + wfor(yes), + ?t:do_times(3, ?MODULE, do_msg, [STM]), + ok = gen_statem:cast(STM, {'alive?',self()}), + wfor(yes), + ok = do_disconnect(STM), + ok = gen_statem:cast(STM, {'alive?',self()}), + wfor(yes), + ok. + + +do_connect(STM) -> + check_state(STM, idle), + gen_statem:cast(STM, {connect,self()}), + wfor(accept), + check_state(STM, wfor_conf), + gen_statem:cast(STM, confirm), + check_state(STM, connected), + ok. + +do_msg(STM) -> + check_state(STM, connected), + R = make_ref(), + ok = gen_statem:cast(STM, {msg,self(),R}), + wfor({ack,R}). + + +do_disconnect(STM) -> + ok = gen_statem:cast(STM, disconnect), + check_state(STM, idle). + +check_state(STM, State) -> + case gen_statem:call(STM, get) of + {state, State, _} -> ok + end. + +do_sync_func_test(STM) -> + yes = gen_statem:call(STM, 'alive?'), + ok = do_sync_connect(STM), + yes = gen_statem:call(STM, 'alive?'), + ?t:do_times(3, ?MODULE, do_sync_msg, [STM]), + yes = gen_statem:call(STM, 'alive?'), + ok = do_sync_disconnect(STM), + yes = gen_statem:call(STM, 'alive?'), + check_state(STM, idle), + ok = gen_statem:call(STM, {timeout,200}), + yes = gen_statem:call(STM, 'alive?'), + check_state(STM, idle), + ok. + + +do_sync_connect(STM) -> + check_state(STM, idle), + accept = gen_statem:call(STM, connect), + check_state(STM, wfor_conf), + yes = gen_statem:call(STM, confirm), + check_state(STM, connected), + ok. + +do_sync_msg(STM) -> + check_state(STM, connected), + R = make_ref(), + {ack,R} = gen_statem:call(STM, {msg,R}), + ok. + +do_sync_disconnect(STM) -> + yes = gen_statem:call(STM, disconnect), + check_state(STM, idle). + + +verify_empty_msgq() -> + receive after 500 -> ok end, + [] = ?t:messages_get(), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% The State Machine +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +init(ignore) -> + ignore; +init(stop) -> + {stop,stopped}; +init(stop_shutdown) -> + {stop,shutdown}; +init(sleep) -> + ?t:sleep(1000), + {ok,idle,data}; +init(hiber) -> + {ok,hiber_idle,[]}; +init(hiber_now) -> + {ok,hiber_idle,[],[hibernate]}; +init({state_data, StateData}) -> + {ok,idle,StateData}; +init(_) -> + {ok,idle,state_data}. + +terminate(_, _State, crash_terminate) -> + exit({crash,terminate}); +terminate({From,stopped}, State, _Data) -> + From ! {self(),{stopped,State}}, + ok; +terminate(_Reason, _State, _Data) -> + ok. + + +%% State functions + +idle(cast, {connect,Pid}, _, _, Data) -> + Pid ! accept, + {wfor_conf,Data}; +idle({call,From}, connect, _, _, Data) -> + {wfor_conf,Data,[{reply,From,accept}]}; +idle(cast, badreturn, _, _, _Data) -> + badreturn; +idle({call,_From}, badreturn, _, _, _Data) -> + badreturn; +idle({call,From}, {delayed_answer,T}, _, _, _Data) -> + receive + after T -> + [{reply,From,delayed}] + end; +idle({call,From}, {timeout,Time}, _, State, _Data) -> + {timeout, {From,Time}, [{timeout,Time,State}]}; +idle(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + case Type of + {call,From} -> + {State,Data,[{reply,From,'eh?'}]}; + _ -> + {State,Data, + [{stop,{unexpected,State,PrevState,Type,Content}}]} + end; + Result -> + Result + end. + +timeout(timeout, idle, idle, timeout, {From,Time}) -> + TRef2 = erlang:start_timer(Time, self(), ok), + TRefC1 = erlang:start_timer(Time, self(), cancel1), + TRefC2 = erlang:start_timer(Time, self(), cancel2), + {timeout2, + {From, Time, TRef2}, + [{cancel_timer, TRefC1}, + {insert_event,internal,{cancel_timer,TRefC2}}]}; +timeout(_, _, _, _, Data) -> + {Data}. + +timeout2( + internal, {cancel_timer,TRefC2}, timeout, _, {From,Time,TRef2}) -> + Time4 = Time * 4, + receive after Time4 -> ok end, + {timeout3,{From,TRef2},[{cancel_timer,TRefC2}]}; +timeout2(_, _, _, _, Data) -> + {Data}. + +timeout3(info, {timeout,TRef2,Result}, _, _, {From,TRef2}) -> + {idle,state,[{reply,From,Result}]}; +timeout3(_, _, _, _, Data) -> + {Data}. + +wfor_conf({call,From}, confirm, _, _, Data) -> + {connected,Data,[{reply,From,yes}]}; +wfor_conf(cast, confirm, _, _, Data) -> + {connected,Data}; +wfor_conf(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + case Type of + {call,From} -> + {idle,Data,[{reply,From,'eh?'}]}; + _ -> + {Data} + end; + Result -> + Result + end. + +connected({call,From}, {msg,Ref}, _, State, Data) -> + {State,Data,[{reply,From,{ack,Ref}}]}; +connected(cast, {msg,From,Ref}, _, _, _Data) -> + From ! {ack,Ref}, + {}; +connected({call,From}, disconnect, _, _, Data) -> + {idle,Data,[{reply,From,yes}]}; +connected(cast, disconnect, _, _, Data) -> + {idle,Data}; +connected(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + case Type of + {call,From} -> + [{reply,From,'eh?'}]; + _ -> + {Data} + end; + Result -> + Result + end. + +state0({call,From}, stop, _, State, Data) -> + {State,Data, + [{reply,From,stopped}, + {stop,normal}]}; +state0(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + {Data}; + Result -> + Result + end. + +hiber_idle({call,From}, 'alive?', _, _, _) -> + [{reply,From,'alive!'}]; +hiber_idle({call,From}, hibernate_sync, _, _, Data) -> + {hiber_wakeup,Data, + [{reply,From,hibernating}, + hibernate]}; +hiber_idle(info, hibernate_later, _, State, _) -> + Tref = erlang:start_timer(1000, self(), hibernate), + {State,Tref}; +hiber_idle(info, hibernate_now, _, State, Data) -> + {State,Data,[hibernate]}; +hiber_idle(info, {timeout,Tref,hibernate}, _, State, Tref) -> + {State,[], + [hibernate]}; +hiber_idle(cast, hibernate_async, _, _, Data) -> + {hiber_wakeup,Data, + [hibernate]}; +hiber_idle(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + {Data}; + Result -> + Result + end. + +hiber_wakeup({call,From}, wakeup_sync, _, _, Data) -> + {hiber_idle,Data,[{reply,From,good_morning}]}; +hiber_wakeup({call,From}, snooze_sync, _, State, Data) -> + {State,Data, + [{reply,From,please_just_five_more}, + hibernate]}; +hiber_wakeup(cast, wakeup_async, _, _, Data) -> + {hiber_idle,Data}; +hiber_wakeup(cast, snooze_async, _, _, _Data) -> + [hibernate]; +hiber_wakeup(Type, Content, PrevState, State, Data) -> + case handle_common_events(Type, Content, PrevState, State, Data) of + [] -> + {Data}; + Result -> + Result + end. + + +handle_common_events({call,From}, get, _, State, Data) -> + [{reply,From,{state,State,Data}}]; +handle_common_events(cast, {get,Pid}, _, State, Data) -> + Pid ! {state,State,Data}, + {}; +handle_common_events({call,From}, stop, _, _, _) -> + [{reply,From,stopped}, + {stop,normal}]; +handle_common_events(cast, stop, _, State, Data) -> + {State,Data, + [{stop,normal}]}; +handle_common_events({call,From}, {stop,Reason}, _, State, Data) -> + {State,Data, + [{reply,From,stopped}, + {stop,Reason}]}; +handle_common_events(cast, {stop,Reason}, _, _, _) -> + [{stop,Reason}]; +handle_common_events({call,From}, 'alive?', _, State, Data) -> + {State,Data, + [{reply,From,yes}]}; +handle_common_events(cast, {'alive?',Pid}, _, State, Data) -> + Pid ! yes, + {State,Data}; +handle_common_events(_, _, _, _, _) -> + []. + +code_change(_OldVsn, State, StateData, _Extra) -> + {ok,State,StateData}. + +format_status(terminate, [_Pdict,State,StateData]) -> + {formatted,State,StateData}; +format_status(normal, [_Pdict,_State,_StateData]) -> + [format_status_called]. -- cgit v1.2.3 From 3815de0c7337058991066454c246587c0dbaa664 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 16 Feb 2016 10:51:39 +0100 Subject: Change to {next_state,...} and {stop,...} return format --- lib/stdlib/test/gen_statem_SUITE.erl | 148 ++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 71 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 342be32acb..51e08f5ec1 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1068,29 +1068,30 @@ terminate(_Reason, _State, _Data) -> idle(cast, {connect,Pid}, _, _, Data) -> Pid ! accept, - {wfor_conf,Data}; + {next_state,wfor_conf,Data}; idle({call,From}, connect, _, _, Data) -> - {wfor_conf,Data,[{reply,From,accept}]}; + {next_state,wfor_conf,Data,[{reply,From,accept}]}; idle(cast, badreturn, _, _, _Data) -> badreturn; idle({call,_From}, badreturn, _, _, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, _, _Data) -> +idle({call,From}, {delayed_answer,T}, _, State, Data) -> receive after T -> - [{reply,From,delayed}] + {next_state,State,Data, + [{reply,From,delayed}]} end; idle({call,From}, {timeout,Time}, _, State, _Data) -> - {timeout, {From,Time}, [{timeout,Time,State}]}; + {next_state,timeout,{From,Time}, + [{timeout,Time,State}]}; idle(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> + undefined -> case Type of {call,From} -> - {State,Data,[{reply,From,'eh?'}]}; + {next_state,State,Data,[{reply,From,'eh?'}]}; _ -> - {State,Data, - [{stop,{unexpected,State,PrevState,Type,Content}}]} + {stop,{unexpected,State,PrevState,Type,Content},Data} end; Result -> Result @@ -1100,146 +1101,151 @@ timeout(timeout, idle, idle, timeout, {From,Time}) -> TRef2 = erlang:start_timer(Time, self(), ok), TRefC1 = erlang:start_timer(Time, self(), cancel1), TRefC2 = erlang:start_timer(Time, self(), cancel2), - {timeout2, - {From, Time, TRef2}, + {next_state,timeout2,{From,Time,TRef2}, [{cancel_timer, TRefC1}, {insert_event,internal,{cancel_timer,TRefC2}}]}; -timeout(_, _, _, _, Data) -> - {Data}. +timeout(_, _, _, State, Data) -> + {next_state,State,Data}. timeout2( internal, {cancel_timer,TRefC2}, timeout, _, {From,Time,TRef2}) -> Time4 = Time * 4, receive after Time4 -> ok end, - {timeout3,{From,TRef2},[{cancel_timer,TRefC2}]}; -timeout2(_, _, _, _, Data) -> - {Data}. + {next_state,timeout3,{From,TRef2}, + [{cancel_timer,TRefC2}]}; +timeout2(_, _, _, State, Data) -> + {next_state,State,Data}. timeout3(info, {timeout,TRef2,Result}, _, _, {From,TRef2}) -> - {idle,state,[{reply,From,Result}]}; -timeout3(_, _, _, _, Data) -> - {Data}. + {next_state,idle,state, + [{reply,From,Result}]}; +timeout3(_, _, _, State, Data) -> + {next_state,State,Data}. wfor_conf({call,From}, confirm, _, _, Data) -> - {connected,Data,[{reply,From,yes}]}; + {next_state,connected,Data, + [{reply,From,yes}]}; wfor_conf(cast, confirm, _, _, Data) -> - {connected,Data}; + {next_state,connected,Data}; wfor_conf(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> + undefined -> case Type of {call,From} -> - {idle,Data,[{reply,From,'eh?'}]}; + {next_state,idle,Data, + [{reply,From,'eh?'}]}; _ -> - {Data} + {next_state,State,Data} end; Result -> Result end. connected({call,From}, {msg,Ref}, _, State, Data) -> - {State,Data,[{reply,From,{ack,Ref}}]}; -connected(cast, {msg,From,Ref}, _, _, _Data) -> + {next_state,State,Data, + [{reply,From,{ack,Ref}}]}; +connected(cast, {msg,From,Ref}, _, State, Data) -> From ! {ack,Ref}, - {}; + {next_state,State,Data}; connected({call,From}, disconnect, _, _, Data) -> - {idle,Data,[{reply,From,yes}]}; + {next_state,idle,Data, + [{reply,From,yes}]}; connected(cast, disconnect, _, _, Data) -> - {idle,Data}; + {next_state,idle,Data}; connected(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> + undefined -> case Type of {call,From} -> - [{reply,From,'eh?'}]; + {next_state,State,Data, + [{reply,From,'eh?'}]}; _ -> - {Data} + {next_state,State,Data} end; Result -> Result end. -state0({call,From}, stop, _, State, Data) -> - {State,Data, - [{reply,From,stopped}, - {stop,normal}]}; +state0({call,From}, stop, _, _, Data) -> + {stop,normal,[{reply,From,stopped}],Data}; state0(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> - {Data}; + undefined -> + {next_state,State,Data}; Result -> Result end. -hiber_idle({call,From}, 'alive?', _, _, _) -> - [{reply,From,'alive!'}]; +hiber_idle({call,From}, 'alive?', _, State, Data) -> + {next_state,State,Data, + [{reply,From,'alive!'}]}; hiber_idle({call,From}, hibernate_sync, _, _, Data) -> - {hiber_wakeup,Data, + {next_state,hiber_wakeup,Data, [{reply,From,hibernating}, hibernate]}; hiber_idle(info, hibernate_later, _, State, _) -> Tref = erlang:start_timer(1000, self(), hibernate), - {State,Tref}; + {next_state,State,Tref}; hiber_idle(info, hibernate_now, _, State, Data) -> - {State,Data,[hibernate]}; + {next_state,State,Data, + [hibernate]}; hiber_idle(info, {timeout,Tref,hibernate}, _, State, Tref) -> - {State,[], + {next_state,State,[], [hibernate]}; hiber_idle(cast, hibernate_async, _, _, Data) -> - {hiber_wakeup,Data, + {next_state,hiber_wakeup,Data, [hibernate]}; hiber_idle(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> - {Data}; + undefined -> + {next_state,State,Data}; Result -> Result end. hiber_wakeup({call,From}, wakeup_sync, _, _, Data) -> - {hiber_idle,Data,[{reply,From,good_morning}]}; + {next_state,hiber_idle,Data, + [{reply,From,good_morning}]}; hiber_wakeup({call,From}, snooze_sync, _, State, Data) -> - {State,Data, + {next_state,State,Data, [{reply,From,please_just_five_more}, hibernate]}; hiber_wakeup(cast, wakeup_async, _, _, Data) -> - {hiber_idle,Data}; -hiber_wakeup(cast, snooze_async, _, _, _Data) -> - [hibernate]; + {next_state,hiber_idle,Data}; +hiber_wakeup(cast, snooze_async, _, State, Data) -> + {next_state,State,Data, + [hibernate]}; hiber_wakeup(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of - [] -> - {Data}; + undefined -> + {next_state,State,Data}; Result -> Result end. handle_common_events({call,From}, get, _, State, Data) -> - [{reply,From,{state,State,Data}}]; + {next_state,State,Data, + [{reply,From,{state,State,Data}}]}; handle_common_events(cast, {get,Pid}, _, State, Data) -> Pid ! {state,State,Data}, - {}; -handle_common_events({call,From}, stop, _, _, _) -> - [{reply,From,stopped}, - {stop,normal}]; -handle_common_events(cast, stop, _, State, Data) -> - {State,Data, - [{stop,normal}]}; -handle_common_events({call,From}, {stop,Reason}, _, State, Data) -> - {State,Data, - [{reply,From,stopped}, - {stop,Reason}]}; -handle_common_events(cast, {stop,Reason}, _, _, _) -> - [{stop,Reason}]; + {next_state,State,Data}; +handle_common_events({call,From}, stop, _, _, Data) -> + {stop,normal,[{reply,From,stopped}],Data}; +handle_common_events(cast, stop, _, _, Data) -> + {stop,normal,Data}; +handle_common_events({call,From}, {stop,Reason}, _, _, Data) -> + {stop,Reason,{reply,From,stopped},Data}; +handle_common_events(cast, {stop,Reason}, _, _, Data) -> + {stop,Reason,Data}; handle_common_events({call,From}, 'alive?', _, State, Data) -> - {State,Data, + {next_state,State,Data, [{reply,From,yes}]}; handle_common_events(cast, {'alive?',Pid}, _, State, Data) -> Pid ! yes, - {State,Data}; + {next_state,State,Data}; handle_common_events(_, _, _, _, _) -> - []. + undefined. code_change(_OldVsn, State, StateData, _Extra) -> {ok,State,StateData}. -- cgit v1.2.3 From 99d48f5921f95073c8e46280494746b0e1a2c375 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 16 Feb 2016 17:54:15 +0100 Subject: Implement option callback_mode --- lib/stdlib/test/gen_statem_SUITE.erl | 242 +++++++++++++++++++++++++---------- 1 file changed, 174 insertions(+), 68 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 51e08f5ec1..8a96f0e8e2 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -19,7 +19,7 @@ %% -module(gen_statem_SUITE). --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -compile(export_all). -behaviour(gen_statem). @@ -30,7 +30,11 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, start}, + {group, start_handle_event}, + {group, stop}, + {group, stop_handle_event}, {group, abnormal}, + {group, abnormal_handle_event}, shutdown, {group, sys}, hibernate, enter_loop]. @@ -38,10 +42,21 @@ groups() -> [{start, [], [start1, start2, start3, start4, start5, start6, start7, start8, start9, start10, start11, start12]}, + {start_handle_event, [], + [start1, start2, start3, start4, start5, start6, start7, + start8, start9, start10, start11, start12]}, {stop, [], [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]}, + {stop_handle_event, [], + [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]}, {abnormal, [], [abnormal1, abnormal2]}, + {abnormal_handle_event, [], [abnormal1, abnormal2]}, {sys, [], + [sys1, + call_format_status, + error_format_status, terminate_crash_format, + get_state, replace_state]}, + {sys_handle_event, [], [sys1, call_format_status, error_format_status, terminate_crash_format, @@ -53,6 +68,12 @@ init_per_suite(Config) -> end_per_suite(_Config) -> ok. +init_per_group(GroupName, Config) + when GroupName =:= start_handle_event; + GroupName =:= stop_handle_event; + GroupName =:= abnormal_handle_event; + GroupName =:= sys_handle_event -> + [{init_ops,[{callback_mode,handle_event_function}]}|Config]; init_per_group(_GroupName, Config) -> Config. @@ -65,6 +86,7 @@ init_per_testcase(_CaseName, Config) -> %%% dbg:tracer(), %%% dbg:p(all, c), %%% dbg:tpl(gen_statem, cx), +%%% dbg:tpl(sys, cx), [{watchdog, Dog} | Config]. end_per_testcase(_CaseName, Config) -> @@ -88,7 +110,7 @@ end_per_testcase(_CaseName, Config) -> start1(Config) when is_list(Config) -> %%OldFl = process_flag(trap_exit, true), - {ok,Pid0} = gen_statem:start_link(?MODULE, [], []), + {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid0), ok = do_sync_func_test(Pid0), stop_it(Pid0), @@ -102,7 +124,7 @@ start1(Config) when is_list(Config) -> %% anonymous w. shutdown start2(Config) when is_list(Config) -> %% Dont link when shutdown - {ok,Pid0} = gen_statem:start(?MODULE, [], []), + {ok,Pid0} = gen_statem:start(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid0), ok = do_sync_func_test(Pid0), stopped = gen_statem:call(Pid0, {stop,shutdown}), @@ -113,13 +135,15 @@ start2(Config) when is_list(Config) -> start3(Config) when is_list(Config) -> %%OldFl = process_flag(trap_exit, true), - {ok,Pid0} = gen_statem:start(?MODULE, [], [{timeout,5}]), + {ok,Pid0} = + gen_statem:start(?MODULE, start_arg(Config, []), [{timeout,5}]), ok = do_func_test(Pid0), ok = do_sync_func_test(Pid0), stop_it(Pid0), - {error,timeout} = gen_statem:start(?MODULE, sleep, - [{timeout,5}]), + {error,timeout} = + gen_statem:start( + ?MODULE, start_arg(Config, sleep), [{timeout,5}]), %%process_flag(trap_exit, OldFl), ok = verify_empty_msgq(). @@ -128,7 +152,7 @@ start3(Config) when is_list(Config) -> start4(Config) when is_list(Config) -> OldFl = process_flag(trap_exit, true), - ignore = gen_statem:start(?MODULE, ignore, []), + ignore = gen_statem:start(?MODULE, start_arg(Config, ignore), []), process_flag(trap_exit, OldFl), ok = verify_empty_msgq(). @@ -138,14 +162,14 @@ start5(suite) -> []; start5(Config) when is_list(Config) -> OldFl = process_flag(trap_exit, true), - {error,stopped} = gen_statem:start(?MODULE, stop, []), + {error,stopped} = gen_statem:start(?MODULE, start_arg(Config, stop), []), process_flag(trap_exit, OldFl), ok = verify_empty_msgq(). %% anonymous linked start6(Config) when is_list(Config) -> - {ok,Pid} = gen_statem:start_link(?MODULE, [], []), + {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), stop_it(Pid), @@ -157,11 +181,11 @@ start7(Config) when is_list(Config) -> STM = {global,my_stm}, {ok,Pid} = - gen_statem:start_link(STM, ?MODULE, [], []), + gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start_link(STM, ?MODULE, [], []), + gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -179,9 +203,9 @@ start8(Config) when is_list(Config) -> STM = {local,Name}, {ok,Pid} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -199,9 +223,9 @@ start9(Config) when is_list(Config) -> STM = {local,Name}, {ok,Pid} = - gen_statem:start_link(STM, ?MODULE, [], []), + gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -217,11 +241,11 @@ start10(Config) when is_list(Config) -> STM = {global,my_stm}, {ok,Pid} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start(STM, ?MODULE, [], []), + gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start_link(STM, ?MODULE, [], []), + gen_statem:start_link(STM, ?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -238,19 +262,19 @@ start11(Config) when is_list(Config) -> GlobalSTM = {global,Name}, {ok,Pid} = - gen_statem:start_link(LocalSTM, ?MODULE, [], []), + gen_statem:start_link(LocalSTM, ?MODULE, start_arg(Config, []), []), stop_it(Pid), {ok,_Pid1} = - gen_statem:start_link(LocalSTM, ?MODULE, [], []), + gen_statem:start_link(LocalSTM, ?MODULE, start_arg(Config, []), []), stop_it(Name), {ok,Pid2} = - gen_statem:start(GlobalSTM, ?MODULE, [], []), + gen_statem:start(GlobalSTM, ?MODULE, start_arg(Config, []), []), stop_it(Pid2), receive after 1 -> true end, Result = - gen_statem:start(GlobalSTM, ?MODULE, [], []), + gen_statem:start(GlobalSTM, ?MODULE, start_arg(Config, []), []), io:format("Result = ~p~n",[Result]), {ok,_Pid3} = Result, stop_it(GlobalSTM), @@ -263,11 +287,11 @@ start12(Config) when is_list(Config) -> VIA = {via,dummy_via,my_stm}, {ok,Pid} = - gen_statem:start_link(VIA, ?MODULE, [], []), + gen_statem:start_link(VIA, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start_link(VIA, ?MODULE, [], []), + gen_statem:start_link(VIA, ?MODULE, start_arg(Config, []), []), {error,{already_started,Pid}} = - gen_statem:start(VIA, ?MODULE, [], []), + gen_statem:start(VIA, ?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -279,23 +303,23 @@ start12(Config) when is_list(Config) -> %% Anonymous, reason 'normal' -stop1(_Config) -> - {ok,Pid} = gen_statem:start(?MODULE, [], []), +stop1(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), ok = gen_statem:stop(Pid), false = erlang:is_process_alive(Pid), noproc = ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason). %% Anonymous, other reason -stop2(_Config) -> - {ok,Pid} = gen_statem:start(?MODULE, [], []), +stop2(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), ok = gen_statem:stop(Pid, other_reason, infinity), false = erlang:is_process_alive(Pid), ok. %% Anonymous, invalid timeout -stop3(_Config) -> - {ok,Pid} = gen_statem:start(?MODULE, [], []), +stop3(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), _ = ?EXPECT_FAILURE( gen_statem:stop(Pid, other_reason, invalid_timeout), @@ -306,8 +330,10 @@ stop3(_Config) -> ok. %% Registered name -stop4(_Config) -> - {ok,Pid} = gen_statem:start({local,to_stop},?MODULE, [], []), +stop4(Config) -> + {ok,Pid} = + gen_statem:start( + {local,to_stop},?MODULE, start_arg(Config, []), []), ok = gen_statem:stop(to_stop), false = erlang:is_process_alive(Pid), noproc = @@ -315,9 +341,11 @@ stop4(_Config) -> ok. %% Registered name and local node -stop5(_Config) -> +stop5(Config) -> Name = to_stop, - {ok,Pid} = gen_statem:start({local,Name},?MODULE, [], []), + {ok,Pid} = + gen_statem:start( + {local,Name},?MODULE, start_arg(Config, []), []), ok = gen_statem:stop({Name,node()}), false = erlang:is_process_alive(Pid), noproc = @@ -325,9 +353,9 @@ stop5(_Config) -> ok. %% Globally registered name -stop6(_Config) -> +stop6(Config) -> STM = {global,to_stop}, - {ok,Pid} = gen_statem:start(STM, ?MODULE, [], []), + {ok,Pid} = gen_statem:start(STM, ?MODULE, start_arg(Config, []), []), ok = gen_statem:stop(STM), false = erlang:is_process_alive(Pid), noproc = @@ -335,11 +363,10 @@ stop6(_Config) -> ok. %% 'via' registered name -stop7(_Config) -> +stop7(Config) -> VIA = {via,dummy_via,to_stop}, dummy_via:reset(), - {ok,Pid} = gen_statem:start(VIA, - ?MODULE, [], []), + {ok,Pid} = gen_statem:start(VIA, ?MODULE, start_arg(Config, []), []), ok = gen_statem:stop(VIA), false = erlang:is_process_alive(Pid), noproc = @@ -347,46 +374,55 @@ stop7(_Config) -> ok. %% Anonymous on remote node -stop8(_Config) -> +stop8(Config) -> {ok,Node} = ?t:start_node(gen_statem_stop8, slave, []), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node, code, add_path, [Dir]), - {ok,Pid} = rpc:call(Node, gen_statem,start, [?MODULE,[],[]]), + {ok,Pid} = + rpc:call( + Node, gen_statem,start, + [?MODULE,start_arg(Config, []),[]]), ok = gen_statem:stop(Pid), false = rpc:call(Node, erlang, is_process_alive, [Pid]), noproc = ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason1), true = ?t:stop_node(Node), - {nodedown,Node} = + {{nodedown,Node},{sys,terminate,_}} = ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason2), ok. %% Registered name on remote node -stop9(_Config) -> +stop9(Config) -> Name = to_stop, LocalSTM = {local,Name}, {ok,Node} = ?t:start_node(gen_statem__stop9, slave, []), STM = {Name,Node}, Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node, code, add_path, [Dir]), - {ok,Pid} = rpc:call(Node, gen_statem, start, [LocalSTM,?MODULE,[],[]]), + {ok,Pid} = + rpc:call( + Node, gen_statem, start, + [LocalSTM,?MODULE,start_arg(Config, []),[]]), ok = gen_statem:stop(STM), undefined = rpc:call(Node,erlang,whereis,[Name]), false = rpc:call(Node,erlang,is_process_alive,[Pid]), noproc = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), true = ?t:stop_node(Node), - {nodedown,Node} = + {{nodedown,Node},{sys,terminate,_}} = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), ok. %% Globally registered name on remote node -stop10(_Config) -> +stop10(Config) -> STM = {global,to_stop}, {ok,Node} = ?t:start_node(gen_statem_stop10, slave, []), Dir = filename:dirname(code:which(?MODULE)), rpc:call(Node,code,add_path,[Dir]), - {ok,Pid} = rpc:call(Node, gen_statem, start, [STM,?MODULE,[],[]]), + {ok,Pid} = + rpc:call( + Node, gen_statem, start, + [STM,?MODULE,start_arg(Config, []),[]]), global:sync(), ok = gen_statem:stop(STM), false = rpc:call(Node, erlang, is_process_alive, [Pid]), @@ -402,7 +438,8 @@ abnormal1(Config) when is_list(Config) -> Name = abnormal1, LocalSTM = {local,Name}, - {ok, _Pid} = gen_statem:start(LocalSTM, ?MODULE, [], []), + {ok, _Pid} = + gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []), %% timeout call. delayed = gen_statem:call(Name, {delayed_answer,1}, 100), @@ -410,13 +447,14 @@ abnormal1(Config) when is_list(Config) -> ?EXPECT_FAILURE( gen_statem:call(Name, {delayed_answer,1000}, 10), Reason), + ok = gen_statem:stop(Name), ok = verify_empty_msgq(). %% Check that bad return values makes the stm crash. Note that we must %% trap exit since we must link to get the real bad_return_ error abnormal2(Config) when is_list(Config) -> OldFl = process_flag(trap_exit, true), - {ok,Pid} = gen_statem:start_link(?MODULE, [], []), + {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), %% bad return value in the gen_statem loop {{bad_return_value,badreturn},_} = @@ -433,7 +471,7 @@ abnormal2(Config) when is_list(Config) -> shutdown(Config) when is_list(Config) -> process_flag(trap_exit, true), - {ok,Pid0} = gen_statem:start_link(?MODULE, [], []), + {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid0), ok = do_sync_func_test(Pid0), stopped = gen_statem:call(Pid0, {stop,{shutdown,reason}}), @@ -454,7 +492,7 @@ shutdown(Config) when is_list(Config) -> sys1(Config) when is_list(Config) -> - {ok,Pid} = gen_statem:start(?MODULE, [], []), + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), {status, Pid, {module,gen_statem}, _} = sys:get_status(Pid), sys:suspend(Pid), Parent = self(), @@ -477,7 +515,7 @@ sys1(Config) when is_list(Config) -> stop_it(Pid). call_format_status(Config) when is_list(Config) -> - {ok,Pid} = gen_statem:start(?MODULE, [], []), + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), Status = sys:get_status(Pid), {status,Pid,_Mod,[_PDict,running,_,_, Data]} = Status, [format_status_called|_] = lists:reverse(Data), @@ -485,7 +523,9 @@ call_format_status(Config) when is_list(Config) -> %% check that format_status can handle a name being an atom (pid is %% already checked by the previous test) - {ok, Pid2} = gen_statem:start({local, gstm}, ?MODULE, [], []), + {ok, Pid2} = + gen_statem:start( + {local, gstm}, ?MODULE, start_arg(Config, []), []), Status2 = sys:get_status(gstm), {status,Pid2,_Mod,[_PDict2,running,_,_,Data2]} = Status2, [format_status_called|_] = lists:reverse(Data2), @@ -494,13 +534,17 @@ call_format_status(Config) when is_list(Config) -> %% check that format_status can handle a name being a term other than a %% pid or atom GlobalName1 = {global,"CallFormatStatus"}, - {ok,Pid3} = gen_statem:start(GlobalName1, ?MODULE, [], []), + {ok,Pid3} = + gen_statem:start( + GlobalName1, ?MODULE, start_arg(Config, []), []), Status3 = sys:get_status(GlobalName1), {status,Pid3,_Mod,[_PDict3,running,_,_,Data3]} = Status3, [format_status_called|_] = lists:reverse(Data3), stop_it(Pid3), GlobalName2 = {global,{name, "term"}}, - {ok,Pid4} = gen_statem:start(GlobalName2, ?MODULE, [], []), + {ok,Pid4} = + gen_statem:start( + GlobalName2, ?MODULE, start_arg(Config, []), []), Status4 = sys:get_status(GlobalName2), {status,Pid4,_Mod,[_PDict4,running,_,_, Data4]} = Status4, [format_status_called|_] = lists:reverse(Data4), @@ -510,13 +554,15 @@ call_format_status(Config) when is_list(Config) -> %% pid or atom dummy_via:reset(), ViaName1 = {via,dummy_via,"CallFormatStatus"}, - {ok,Pid5} = gen_statem:start(ViaName1, ?MODULE, [], []), + {ok,Pid5} = gen_statem:start(ViaName1, ?MODULE, start_arg(Config, []), []), Status5 = sys:get_status(ViaName1), {status,Pid5,_Mod, [_PDict5,running,_,_, Data5]} = Status5, [format_status_called|_] = lists:reverse(Data5), stop_it(Pid5), ViaName2 = {via,dummy_via,{name,"term"}}, - {ok, Pid6} = gen_statem:start(ViaName2, ?MODULE, [], []), + {ok, Pid6} = + gen_statem:start( + ViaName2, ?MODULE, start_arg(Config, []), []), Status6 = sys:get_status(ViaName2), {status,Pid6,_Mod,[_PDict6,running,_,_,Data6]} = Status6, [format_status_called|_] = lists:reverse(Data6), @@ -528,7 +574,9 @@ error_format_status(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), StateData = "called format_status", - {ok,Pid} = gen_statem:start(?MODULE, {state_data,StateData}, []), + {ok,Pid} = + gen_statem:start( + ?MODULE, start_arg(Config, {state_data,StateData}), []), %% bad return value in the gen_statem loop {{bad_return_value,badreturn},_} = ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), @@ -562,7 +610,9 @@ terminate_crash_format(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), StateData = crash_terminate, - {ok,Pid} = gen_statem:start(?MODULE, {state_data,StateData}, []), + {ok,Pid} = + gen_statem:start( + ?MODULE, start_arg(Config, {state_data,StateData}), []), stop_it(Pid), Self = self(), receive @@ -595,7 +645,9 @@ terminate_crash_format(Config) when is_list(Config) -> get_state(Config) when is_list(Config) -> State = self(), - {ok,Pid} = gen_statem:start(?MODULE, {state_data,State}, []), + {ok,Pid} = + gen_statem:start( + ?MODULE, start_arg(Config, {state_data,State}), []), {idle,State} = sys:get_state(Pid), {idle,State} = sys:get_state(Pid, 5000), stop_it(Pid), @@ -603,13 +655,16 @@ get_state(Config) when is_list(Config) -> %% check that get_state can handle a name being an atom (pid is %% already checked by the previous test) {ok,Pid2} = - gen_statem:start({local,gstm}, ?MODULE, {state_data,State}, []), + gen_statem:start( + {local,gstm}, ?MODULE, start_arg(Config, {state_data,State}), []), {idle,State} = sys:get_state(gstm), {idle,State} = sys:get_state(gstm, 5000), stop_it(Pid2), %% check that get_state works when pid is sys suspended - {ok,Pid3} = gen_statem:start(?MODULE, {state_data,State}, []), + {ok,Pid3} = + gen_statem:start( + ?MODULE, start_arg(Config, {state_data,State}), []), {idle,State} = sys:get_state(Pid3), ok = sys:suspend(Pid3), {idle,State} = sys:get_state(Pid3, 5000), @@ -619,7 +674,9 @@ get_state(Config) when is_list(Config) -> replace_state(Config) when is_list(Config) -> State = self(), - {ok, Pid} = gen_statem:start(?MODULE, {state_data,State}, []), + {ok, Pid} = + gen_statem:start( + ?MODULE, start_arg(Config, {state_data,State}), []), {idle,State} = sys:get_state(Pid), NState1 = "replaced", Replace1 = fun({StateName, _}) -> {StateName,NState1} end, @@ -650,7 +707,9 @@ replace_state(Config) when is_list(Config) -> hibernate(Config) when is_list(Config) -> OldFl = process_flag(trap_exit, true), - {ok,Pid0} = gen_statem:start_link(?MODULE, hiber_now, []), + {ok,Pid0} = + gen_statem:start_link( + ?MODULE, start_arg(Config, hiber_now), []), is_in_erlang_hibernate(Pid0), stop_it(Pid0), receive @@ -659,7 +718,8 @@ hibernate(Config) when is_list(Config) -> ?t:fail(gen_statem_did_not_die) end, - {ok,Pid} = gen_statem:start_link(?MODULE, hiber, []), + {ok,Pid} = + gen_statem:start_link(?MODULE, start_arg(Config, hiber), []), true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), @@ -1031,6 +1091,14 @@ verify_empty_msgq() -> [] = ?t:messages_get(), ok. +start_arg(Config, Arg) -> + case lists:keyfind(init_ops, 1, Config) of + {_,Ops} -> + {init_ops,Arg,Ops}; + false -> + Arg + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% The State Machine @@ -1052,7 +1120,16 @@ init(hiber_now) -> {ok,hiber_idle,[],[hibernate]}; init({state_data, StateData}) -> {ok,idle,StateData}; -init(_) -> +init({init_ops,Arg,InitOps}) -> + case init(Arg) of + {ok,State,Data,Ops} -> + {ok,State,Data,InitOps++Ops}; + {ok,State,Data} -> + {ok,State,Data,InitOps}; + Other -> + Other + end; +init([]) -> {ok,idle,state_data}. terminate(_, _State, crash_terminate) -> @@ -1247,6 +1324,35 @@ handle_common_events(cast, {'alive?',Pid}, _, State, Data) -> handle_common_events(_, _, _, _, _) -> undefined. +%% Dispatcher to test callback_mode handle_event_function +%% +%% Wrap the state in a 1 element list just to test non-atom +%% states. Note that the state from init/1 is not wrapped +%% so both atom and non-atom states are tested. +handle_event(Type, Event, PrevState, State, Data) -> + PrevStateName = unwrap(PrevState), + StateName = unwrap(State), + case + ?MODULE:StateName( + Type, Event, PrevStateName, StateName, Data) of + {next_state,NewState,NewStateData} -> + {next_state,wrap(NewState),NewStateData}; + {next_state,NewState,NewStateData,StateOps} -> + {next_state,wrap(NewState),NewStateData,StateOps}; + Other -> + Other + end. + +unwrap([State]) -> + State; +unwrap(State) -> + State. + +wrap(State) -> + [State]. + + + code_change(_OldVsn, State, StateData, _Extra) -> {ok,State,StateData}. -- cgit v1.2.3 From 972a8fcb57a64c9a0dc7587e9072c15758e36da2 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 18 Feb 2016 10:22:50 +0100 Subject: Rename insert_event -> next_event --- lib/stdlib/test/gen_statem_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 8a96f0e8e2..facc36fb9f 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1180,7 +1180,7 @@ timeout(timeout, idle, idle, timeout, {From,Time}) -> TRefC2 = erlang:start_timer(Time, self(), cancel2), {next_state,timeout2,{From,Time,TRef2}, [{cancel_timer, TRefC1}, - {insert_event,internal,{cancel_timer,TRefC2}}]}; + {next_event,internal,{cancel_timer,TRefC2}}]}; timeout(_, _, _, State, Data) -> {next_state,State,Data}. -- cgit v1.2.3 From fdd72bc94149c7e279b5c4fd5a040af1886a4c72 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 18 Feb 2016 11:17:42 +0100 Subject: Rename retry -> postpone --- lib/stdlib/test/gen_statem_SUITE.erl | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index facc36fb9f..8b619b6a60 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1032,7 +1032,10 @@ do_connect(STM) -> gen_statem:cast(STM, {connect,self()}), wfor(accept), check_state(STM, wfor_conf), + Tag = make_ref(), + gen_statem:cast(STM, {ping,self(),Tag}), gen_statem:cast(STM, confirm), + wfor({pong,Tag}), check_state(STM, connected), ok. @@ -1071,7 +1074,10 @@ do_sync_connect(STM) -> check_state(STM, idle), accept = gen_statem:call(STM, connect), check_state(STM, wfor_conf), + Tag = make_ref(), + gen_statem:cast(STM, {ping,self(),Tag}), yes = gen_statem:call(STM, confirm), + wfor({pong,Tag}), check_state(STM, connected), ok. @@ -1202,6 +1208,8 @@ timeout3(_, _, _, State, Data) -> wfor_conf({call,From}, confirm, _, _, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; +wfor_conf(cast, {ping,_,_}, _, State, Data) -> + {next_state,State,Data,[postpone]}; wfor_conf(cast, confirm, _, _, Data) -> {next_state,connected,Data}; wfor_conf(Type, Content, PrevState, State, Data) -> @@ -1229,6 +1237,9 @@ connected({call,From}, disconnect, _, _, Data) -> [{reply,From,yes}]}; connected(cast, disconnect, _, _, Data) -> {next_state,idle,Data}; +connected(cast, {ping,Pid,Tag}, _, State, Data) -> + Pid ! {pong,Tag}, + {next_state,State,Data}; connected(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of undefined -> -- cgit v1.2.3 From 82f34a7a9de85b4afc0dac4c9c426939264c5039 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 18 Feb 2016 16:06:57 +0100 Subject: Write some convenience helpers --- lib/stdlib/test/gen_statem_SUITE.erl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 8b619b6a60..6249ada027 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1158,11 +1158,10 @@ idle(cast, badreturn, _, _, _Data) -> badreturn; idle({call,_From}, badreturn, _, _, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, State, Data) -> +idle({call,From}, {delayed_answer,T}, _, _, _) -> receive after T -> - {next_state,State,Data, - [{reply,From,delayed}]} + throw({next_state,{reply,From,delayed}}) end; idle({call,From}, {timeout,Time}, _, State, _Data) -> {next_state,timeout,{From,Time}, @@ -1172,9 +1171,10 @@ idle(Type, Content, PrevState, State, Data) -> undefined -> case Type of {call,From} -> - {next_state,State,Data,[{reply,From,'eh?'}]}; + throw({next_state,[{reply,From,'eh?'}]}); _ -> - {stop,{unexpected,State,PrevState,Type,Content},Data} + throw( + {stop,{unexpected,State,PrevState,Type,Content}}) end; Result -> Result @@ -1208,8 +1208,8 @@ timeout3(_, _, _, State, Data) -> wfor_conf({call,From}, confirm, _, _, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; -wfor_conf(cast, {ping,_,_}, _, State, Data) -> - {next_state,State,Data,[postpone]}; +wfor_conf(cast, {ping,_,_}, _, _, _) -> + {next_state,[postpone]}; wfor_conf(cast, confirm, _, _, Data) -> {next_state,connected,Data}; wfor_conf(Type, Content, PrevState, State, Data) -> @@ -1220,7 +1220,7 @@ wfor_conf(Type, Content, PrevState, State, Data) -> {next_state,idle,Data, [{reply,From,'eh?'}]}; _ -> - {next_state,State,Data} + throw({next_state,[]}) end; Result -> Result @@ -1320,12 +1320,12 @@ handle_common_events(cast, {get,Pid}, _, State, Data) -> {next_state,State,Data}; handle_common_events({call,From}, stop, _, _, Data) -> {stop,normal,[{reply,From,stopped}],Data}; -handle_common_events(cast, stop, _, _, Data) -> - {stop,normal,Data}; +handle_common_events(cast, stop, _, _, _) -> + {stop,normal}; handle_common_events({call,From}, {stop,Reason}, _, _, Data) -> {stop,Reason,{reply,From,stopped},Data}; -handle_common_events(cast, {stop,Reason}, _, _, Data) -> - {stop,Reason,Data}; +handle_common_events(cast, {stop,Reason}, _, _, _) -> + {stop,Reason}; handle_common_events({call,From}, 'alive?', _, State, Data) -> {next_state,State,Data, [{reply,From,yes}]}; -- cgit v1.2.3 From 65767cfc36cf8658b45d68b3c17d4bd612198165 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 19 Feb 2016 09:22:52 +0100 Subject: Add {keep_state,...} and {keep_state_and_data,...} --- lib/stdlib/test/gen_statem_SUITE.erl | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 6249ada027..92dc59e843 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1158,10 +1158,10 @@ idle(cast, badreturn, _, _, _Data) -> badreturn; idle({call,_From}, badreturn, _, _, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, _, _) -> +idle({call,From}, {delayed_answer,T}, _, _, Data) -> receive after T -> - throw({next_state,{reply,From,delayed}}) + throw({keep_state,Data,{reply,From,delayed}}) end; idle({call,From}, {timeout,Time}, _, State, _Data) -> {next_state,timeout,{From,Time}, @@ -1171,7 +1171,7 @@ idle(Type, Content, PrevState, State, Data) -> undefined -> case Type of {call,From} -> - throw({next_state,[{reply,From,'eh?'}]}); + throw({keep_state,Data,[{reply,From,'eh?'}]}); _ -> throw( {stop,{unexpected,State,PrevState,Type,Content}}) @@ -1209,7 +1209,7 @@ wfor_conf({call,From}, confirm, _, _, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; wfor_conf(cast, {ping,_,_}, _, _, _) -> - {next_state,[postpone]}; + {keep_state_and_data,[postpone]}; wfor_conf(cast, confirm, _, _, Data) -> {next_state,connected,Data}; wfor_conf(Type, Content, PrevState, State, Data) -> @@ -1220,7 +1220,7 @@ wfor_conf(Type, Content, PrevState, State, Data) -> {next_state,idle,Data, [{reply,From,'eh?'}]}; _ -> - throw({next_state,[]}) + throw({keep_state_and_data}) end; Result -> Result @@ -1341,26 +1341,32 @@ handle_common_events(_, _, _, _, _) -> %% states. Note that the state from init/1 is not wrapped %% so both atom and non-atom states are tested. handle_event(Type, Event, PrevState, State, Data) -> - PrevStateName = unwrap(PrevState), - StateName = unwrap(State), - case - ?MODULE:StateName( + PrevStateName = unwrap_state(PrevState), + StateName = unwrap_state(State), + try ?MODULE:StateName( Type, Event, PrevStateName, StateName, Data) of - {next_state,NewState,NewStateData} -> - {next_state,wrap(NewState),NewStateData}; - {next_state,NewState,NewStateData,StateOps} -> - {next_state,wrap(NewState),NewStateData,StateOps}; - Other -> - Other + Result -> + wrap_result(Result) + catch + throw:Result -> + erlang:raise( + throw, wrap_result(Result), erlang:get_stacktrace()) end. -unwrap([State]) -> +unwrap_state([State]) -> State; -unwrap(State) -> +unwrap_state(State) -> State. -wrap(State) -> - [State]. +wrap_result(Result) -> + case Result of + {next_state,NewState,NewStateData} -> + {next_state,[NewState],NewStateData}; + {next_state,NewState,NewStateData,StateOps} -> + {next_state,[NewState],NewStateData,StateOps}; + Other -> + Other + end. -- cgit v1.2.3 From fc1e649e3613f18dec8514921d0439ddcca73bdb Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 19 Feb 2016 09:39:46 +0100 Subject: Add reply([Reply]) --- lib/stdlib/test/gen_statem_SUITE.erl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 92dc59e843..4ac4acd189 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1153,7 +1153,8 @@ idle(cast, {connect,Pid}, _, _, Data) -> Pid ! accept, {next_state,wfor_conf,Data}; idle({call,From}, connect, _, _, Data) -> - {next_state,wfor_conf,Data,[{reply,From,accept}]}; + gen_statem:reply(From, accept), + {next_state,wfor_conf,Data}; idle(cast, badreturn, _, _, _Data) -> badreturn; idle({call,_From}, badreturn, _, _, _Data) -> @@ -1161,7 +1162,8 @@ idle({call,_From}, badreturn, _, _, _Data) -> idle({call,From}, {delayed_answer,T}, _, _, Data) -> receive after T -> - throw({keep_state,Data,{reply,From,delayed}}) + gen_statem:reply({reply,From,delayed}), + throw({keep_state,Data}) end; idle({call,From}, {timeout,Time}, _, State, _Data) -> {next_state,timeout,{From,Time}, @@ -1200,8 +1202,8 @@ timeout2(_, _, _, State, Data) -> {next_state,State,Data}. timeout3(info, {timeout,TRef2,Result}, _, _, {From,TRef2}) -> - {next_state,idle,state, - [{reply,From,Result}]}; + gen_statem:reply([{reply,From,Result}]), + {next_state,idle,state}; timeout3(_, _, _, State, Data) -> {next_state,State,Data}. -- cgit v1.2.3 From 898e66f07dce8b7b33874255bb3ea1c6f5534d34 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 19 Feb 2016 15:26:33 +0100 Subject: Update terminology to data(), transition_op(), etc --- lib/stdlib/test/gen_statem_SUITE.erl | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 4ac4acd189..65a8d35645 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -573,10 +573,10 @@ call_format_status(Config) when is_list(Config) -> error_format_status(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), - StateData = "called format_status", + Data = "called format_status", {ok,Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {state_data,StateData}), []), + ?MODULE, start_arg(Config, {data,Data}), []), %% bad return value in the gen_statem loop {{bad_return_value,badreturn},_} = ?EXPECT_FAILURE(gen_statem:call(Pid, badreturn), Reason), @@ -585,7 +585,7 @@ error_format_status(Config) when is_list(Config) -> {Pid, "** State machine"++_, [Pid,{{call,_},badreturn}, - {formatted,idle,StateData}, + {formatted,idle,Data}, exit,{bad_return_value,badreturn}|_]}} -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> @@ -609,10 +609,10 @@ error_format_status(Config) when is_list(Config) -> terminate_crash_format(Config) when is_list(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), - StateData = crash_terminate, + Data = crash_terminate, {ok,Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {state_data,StateData}), []), + ?MODULE, start_arg(Config, {data,Data}), []), stop_it(Pid), Self = self(), receive @@ -621,7 +621,7 @@ terminate_crash_format(Config) when is_list(Config) -> "** State machine"++_, [Pid, {{call,{Self,_}},stop}, - {formatted,idle,StateData}, + {formatted,idle,Data}, exit,{crash,terminate}|_]}} -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> @@ -647,7 +647,7 @@ get_state(Config) when is_list(Config) -> State = self(), {ok,Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {state_data,State}), []), + ?MODULE, start_arg(Config, {data,State}), []), {idle,State} = sys:get_state(Pid), {idle,State} = sys:get_state(Pid, 5000), stop_it(Pid), @@ -656,7 +656,7 @@ get_state(Config) when is_list(Config) -> %% already checked by the previous test) {ok,Pid2} = gen_statem:start( - {local,gstm}, ?MODULE, start_arg(Config, {state_data,State}), []), + {local,gstm}, ?MODULE, start_arg(Config, {data,State}), []), {idle,State} = sys:get_state(gstm), {idle,State} = sys:get_state(gstm, 5000), stop_it(Pid2), @@ -664,7 +664,7 @@ get_state(Config) when is_list(Config) -> %% check that get_state works when pid is sys suspended {ok,Pid3} = gen_statem:start( - ?MODULE, start_arg(Config, {state_data,State}), []), + ?MODULE, start_arg(Config, {data,State}), []), {idle,State} = sys:get_state(Pid3), ok = sys:suspend(Pid3), {idle,State} = sys:get_state(Pid3, 5000), @@ -676,7 +676,7 @@ replace_state(Config) when is_list(Config) -> State = self(), {ok, Pid} = gen_statem:start( - ?MODULE, start_arg(Config, {state_data,State}), []), + ?MODULE, start_arg(Config, {data,State}), []), {idle,State} = sys:get_state(Pid), NState1 = "replaced", Replace1 = fun({StateName, _}) -> {StateName,NState1} end, @@ -1124,8 +1124,8 @@ init(hiber) -> {ok,hiber_idle,[]}; init(hiber_now) -> {ok,hiber_idle,[],[hibernate]}; -init({state_data, StateData}) -> - {ok,idle,StateData}; +init({data, Data}) -> + {ok,idle,Data}; init({init_ops,Arg,InitOps}) -> case init(Arg) of {ok,State,Data,Ops} -> @@ -1136,7 +1136,7 @@ init({init_ops,Arg,InitOps}) -> Other end; init([]) -> - {ok,idle,state_data}. + {ok,idle,data}. terminate(_, _State, crash_terminate) -> exit({crash,terminate}); @@ -1362,20 +1362,20 @@ unwrap_state(State) -> wrap_result(Result) -> case Result of - {next_state,NewState,NewStateData} -> - {next_state,[NewState],NewStateData}; - {next_state,NewState,NewStateData,StateOps} -> - {next_state,[NewState],NewStateData,StateOps}; + {next_state,NewState,NewData} -> + {next_state,[NewState],NewData}; + {next_state,NewState,NewData,StateOps} -> + {next_state,[NewState],NewData,StateOps}; Other -> Other end. -code_change(_OldVsn, State, StateData, _Extra) -> - {ok,State,StateData}. +code_change(_OldVsn, State, Data, _Extra) -> + {ok,State,Data}. -format_status(terminate, [_Pdict,State,StateData]) -> - {formatted,State,StateData}; -format_status(normal, [_Pdict,_State,_StateData]) -> +format_status(terminate, [_Pdict,State,Data]) -> + {formatted,State,Data}; +format_status(normal, [_Pdict,_State,_Data]) -> [format_status_called]. -- cgit v1.2.3 From 759548838fa8b27eaa574233c9897d9578540a5a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 22 Feb 2016 14:55:52 +0100 Subject: Make callback_option() mandatory --- lib/stdlib/test/gen_statem_SUITE.erl | 53 ++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 21 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 65a8d35645..a8b4d16f23 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -36,7 +36,8 @@ all() -> {group, abnormal}, {group, abnormal_handle_event}, shutdown, - {group, sys}, hibernate, enter_loop]. + {group, sys}, + hibernate, enter_loop]. groups() -> [{start, [], @@ -73,7 +74,7 @@ init_per_group(GroupName, Config) GroupName =:= stop_handle_event; GroupName =:= abnormal_handle_event; GroupName =:= sys_handle_event -> - [{init_ops,[{callback_mode,handle_event_function}]}|Config]; + [{callback_mode,handle_event_function}|Config]; init_per_group(_GroupName, Config) -> Config. @@ -86,6 +87,8 @@ init_per_testcase(_CaseName, Config) -> %%% dbg:tracer(), %%% dbg:p(all, c), %%% dbg:tpl(gen_statem, cx), +%%% dbg:tpl(proc_lib, cx), +%%% dbg:tpl(gen, cx), %%% dbg:tpl(sys, cx), [{watchdog, Dog} | Config]. @@ -901,8 +904,11 @@ enter_loop(Config) when is_list(Config) -> end, %% Process not started using proc_lib + CallbackMode = state_functions, Pid4 = - spawn_link(gen_statem, enter_loop, [?MODULE,[],state0,[]]), + spawn_link( + gen_statem, enter_loop, + [?MODULE,[],CallbackMode,state0,[]]), receive {'EXIT',Pid4,process_was_not_started_by_proc_lib} -> ok @@ -976,16 +982,21 @@ enter_loop(Reg1, Reg2) -> anon -> ignore end, proc_lib:init_ack({ok, self()}), + CallbackMode = state_functions, case Reg2 of local -> - gen_statem:enter_loop(?MODULE, [], state0, [], {local,armitage}); + gen_statem:enter_loop( + ?MODULE, [], CallbackMode, state0, [], {local,armitage}); global -> - gen_statem:enter_loop(?MODULE, [], state0, [], {global,armitage}); + gen_statem:enter_loop( + ?MODULE, [], CallbackMode, state0, [], {global,armitage}); via -> - gen_statem:enter_loop(?MODULE, [], state0, [], - {via, dummy_via, armitage}); + gen_statem:enter_loop( + ?MODULE, [], CallbackMode, state0, [], + {via, dummy_via, armitage}); anon -> - gen_statem:enter_loop(?MODULE, [], state0, []) + gen_statem:enter_loop( + ?MODULE, [], CallbackMode, state0, []) end. %% @@ -1098,9 +1109,9 @@ verify_empty_msgq() -> ok. start_arg(Config, Arg) -> - case lists:keyfind(init_ops, 1, Config) of - {_,Ops} -> - {init_ops,Arg,Ops}; + case lists:keyfind(callback_mode, 1, Config) of + {_,CallbackMode} -> + {callback_mode,CallbackMode,Arg}; false -> Arg end. @@ -1119,24 +1130,24 @@ init(stop_shutdown) -> {stop,shutdown}; init(sleep) -> ?t:sleep(1000), - {ok,idle,data}; + {state_functions,idle,data}; init(hiber) -> - {ok,hiber_idle,[]}; + {state_functions,hiber_idle,[]}; init(hiber_now) -> - {ok,hiber_idle,[],[hibernate]}; + {state_functions,hiber_idle,[],[hibernate]}; init({data, Data}) -> - {ok,idle,Data}; -init({init_ops,Arg,InitOps}) -> + {state_functions,idle,Data}; +init({callback_mode,CallbackMode,Arg}) -> case init(Arg) of - {ok,State,Data,Ops} -> - {ok,State,Data,InitOps++Ops}; - {ok,State,Data} -> - {ok,State,Data,InitOps}; + {_,State,Data,Ops} -> + {CallbackMode,State,Data,Ops}; + {_,State,Data} -> + {CallbackMode,State,Data}; Other -> Other end; init([]) -> - {ok,idle,data}. + {state_functions,idle,data}. terminate(_, _State, crash_terminate) -> exit({crash,terminate}); -- cgit v1.2.3 From 2b3a82ae44b222ce1146badcff972abb539d40ca Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 23 Feb 2016 17:58:45 +0100 Subject: Add {stop_and_reply,Reason,Replies [,Data]) Cleanup some error handling --- lib/stdlib/test/gen_statem_SUITE.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index a8b4d16f23..81182eff71 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -589,7 +589,7 @@ error_format_status(Config) when is_list(Config) -> "** State machine"++_, [Pid,{{call,_},badreturn}, {formatted,idle,Data}, - exit,{bad_return_value,badreturn}|_]}} -> + error,{bad_return_value,badreturn}|_]}} -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> error_logger_forwarder:unregister(), @@ -1268,7 +1268,7 @@ connected(Type, Content, PrevState, State, Data) -> end. state0({call,From}, stop, _, _, Data) -> - {stop,normal,[{reply,From,stopped}],Data}; + {stop_and_reply,normal,[{reply,From,stopped}],Data}; state0(Type, Content, PrevState, State, Data) -> case handle_common_events(Type, Content, PrevState, State, Data) of undefined -> @@ -1332,11 +1332,11 @@ handle_common_events(cast, {get,Pid}, _, State, Data) -> Pid ! {state,State,Data}, {next_state,State,Data}; handle_common_events({call,From}, stop, _, _, Data) -> - {stop,normal,[{reply,From,stopped}],Data}; + {stop_and_reply,normal,[{reply,From,stopped}],Data}; handle_common_events(cast, stop, _, _, _) -> {stop,normal}; handle_common_events({call,From}, {stop,Reason}, _, _, Data) -> - {stop,Reason,{reply,From,stopped},Data}; + {stop_and_reply,Reason,{reply,From,stopped},Data}; handle_common_events(cast, {stop,Reason}, _, _, _) -> {stop,Reason}; handle_common_events({call,From}, 'alive?', _, State, Data) -> -- cgit v1.2.3 From 1958b93b4aa90883be5102d465f67f167549dea9 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 24 Feb 2016 09:41:34 +0100 Subject: Ditch State so StateName/5 -> StateName/4 --- lib/stdlib/test/gen_statem_SUITE.erl | 155 +++++++++++++++++------------------ 1 file changed, 77 insertions(+), 78 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 81182eff71..3302171329 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1160,73 +1160,73 @@ terminate(_Reason, _State, _Data) -> %% State functions -idle(cast, {connect,Pid}, _, _, Data) -> +idle(cast, {connect,Pid}, _, Data) -> Pid ! accept, {next_state,wfor_conf,Data}; -idle({call,From}, connect, _, _, Data) -> +idle({call,From}, connect, _, Data) -> gen_statem:reply(From, accept), {next_state,wfor_conf,Data}; -idle(cast, badreturn, _, _, _Data) -> +idle(cast, badreturn, _, _Data) -> badreturn; -idle({call,_From}, badreturn, _, _, _Data) -> +idle({call,_From}, badreturn, _, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, _, Data) -> +idle({call,From}, {delayed_answer,T}, _, Data) -> receive after T -> gen_statem:reply({reply,From,delayed}), throw({keep_state,Data}) end; -idle({call,From}, {timeout,Time}, _, State, _Data) -> +idle({call,From}, {timeout,Time}, _, _Data) -> {next_state,timeout,{From,Time}, - [{timeout,Time,State}]}; -idle(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of + [{timeout,Time,idle}]}; +idle(Type, Content, PrevState, Data) -> + case handle_common_events(Type, Content, idle, Data) of undefined -> case Type of {call,From} -> throw({keep_state,Data,[{reply,From,'eh?'}]}); _ -> throw( - {stop,{unexpected,State,PrevState,Type,Content}}) + {stop,{unexpected,idle,Type,Content,PrevState}}) end; Result -> Result end. -timeout(timeout, idle, idle, timeout, {From,Time}) -> +timeout(timeout, idle, idle, {From,Time}) -> TRef2 = erlang:start_timer(Time, self(), ok), TRefC1 = erlang:start_timer(Time, self(), cancel1), TRefC2 = erlang:start_timer(Time, self(), cancel2), {next_state,timeout2,{From,Time,TRef2}, [{cancel_timer, TRefC1}, {next_event,internal,{cancel_timer,TRefC2}}]}; -timeout(_, _, _, State, Data) -> - {next_state,State,Data}. +timeout(_, _, _, Data) -> + {keep_state,Data}. timeout2( - internal, {cancel_timer,TRefC2}, timeout, _, {From,Time,TRef2}) -> + internal, {cancel_timer,TRefC2}, timeout, {From,Time,TRef2}) -> Time4 = Time * 4, receive after Time4 -> ok end, {next_state,timeout3,{From,TRef2}, [{cancel_timer,TRefC2}]}; -timeout2(_, _, _, State, Data) -> - {next_state,State,Data}. +timeout2(_, _, _, Data) -> + {keep_state,Data}. -timeout3(info, {timeout,TRef2,Result}, _, _, {From,TRef2}) -> +timeout3(info, {timeout,TRef2,Result}, _, {From,TRef2}) -> gen_statem:reply([{reply,From,Result}]), {next_state,idle,state}; -timeout3(_, _, _, State, Data) -> - {next_state,State,Data}. +timeout3(_, _, _, Data) -> + {keep_state,Data}. -wfor_conf({call,From}, confirm, _, _, Data) -> +wfor_conf({call,From}, confirm, _, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; -wfor_conf(cast, {ping,_,_}, _, _, _) -> +wfor_conf(cast, {ping,_,_}, _, _) -> {keep_state_and_data,[postpone]}; -wfor_conf(cast, confirm, _, _, Data) -> +wfor_conf(cast, confirm, _, Data) -> {next_state,connected,Data}; -wfor_conf(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of +wfor_conf(Type, Content, _, Data) -> + case handle_common_events(Type, Content, wfor_conf, Data) of undefined -> case Type of {call,From} -> @@ -1239,113 +1239,113 @@ wfor_conf(Type, Content, PrevState, State, Data) -> Result end. -connected({call,From}, {msg,Ref}, _, State, Data) -> - {next_state,State,Data, +connected({call,From}, {msg,Ref}, _, Data) -> + {keep_state,Data, [{reply,From,{ack,Ref}}]}; -connected(cast, {msg,From,Ref}, _, State, Data) -> +connected(cast, {msg,From,Ref}, _, Data) -> From ! {ack,Ref}, - {next_state,State,Data}; -connected({call,From}, disconnect, _, _, Data) -> + {keep_state,Data}; +connected({call,From}, disconnect, _, Data) -> {next_state,idle,Data, [{reply,From,yes}]}; -connected(cast, disconnect, _, _, Data) -> +connected(cast, disconnect, _, Data) -> {next_state,idle,Data}; -connected(cast, {ping,Pid,Tag}, _, State, Data) -> +connected(cast, {ping,Pid,Tag}, _, Data) -> Pid ! {pong,Tag}, - {next_state,State,Data}; -connected(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of + {keep_state,Data}; +connected(Type, Content, _, Data) -> + case handle_common_events(Type, Content, connected, Data) of undefined -> case Type of {call,From} -> - {next_state,State,Data, + {keep_state,Data, [{reply,From,'eh?'}]}; _ -> - {next_state,State,Data} + {keep_state,Data} end; Result -> Result end. -state0({call,From}, stop, _, _, Data) -> +state0({call,From}, stop, _, Data) -> {stop_and_reply,normal,[{reply,From,stopped}],Data}; -state0(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of +state0(Type, Content, _, Data) -> + case handle_common_events(Type, Content, state0, Data) of undefined -> - {next_state,State,Data}; + {keep_state,Data}; Result -> Result end. -hiber_idle({call,From}, 'alive?', _, State, Data) -> - {next_state,State,Data, +hiber_idle({call,From}, 'alive?', _, Data) -> + {keep_state,Data, [{reply,From,'alive!'}]}; -hiber_idle({call,From}, hibernate_sync, _, _, Data) -> +hiber_idle({call,From}, hibernate_sync, _, Data) -> {next_state,hiber_wakeup,Data, [{reply,From,hibernating}, hibernate]}; -hiber_idle(info, hibernate_later, _, State, _) -> +hiber_idle(info, hibernate_later, _, _) -> Tref = erlang:start_timer(1000, self(), hibernate), - {next_state,State,Tref}; -hiber_idle(info, hibernate_now, _, State, Data) -> - {next_state,State,Data, + {keep_state,Tref}; +hiber_idle(info, hibernate_now, _, Data) -> + {keep_state,Data, [hibernate]}; -hiber_idle(info, {timeout,Tref,hibernate}, _, State, Tref) -> - {next_state,State,[], +hiber_idle(info, {timeout,Tref,hibernate}, _, Tref) -> + {keep_state,[], [hibernate]}; -hiber_idle(cast, hibernate_async, _, _, Data) -> +hiber_idle(cast, hibernate_async, _, Data) -> {next_state,hiber_wakeup,Data, [hibernate]}; -hiber_idle(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of +hiber_idle(Type, Content, _, Data) -> + case handle_common_events(Type, Content, hiber_idle, Data) of undefined -> - {next_state,State,Data}; + {keep_state,Data}; Result -> Result end. -hiber_wakeup({call,From}, wakeup_sync, _, _, Data) -> +hiber_wakeup({call,From}, wakeup_sync, _, Data) -> {next_state,hiber_idle,Data, [{reply,From,good_morning}]}; -hiber_wakeup({call,From}, snooze_sync, _, State, Data) -> - {next_state,State,Data, +hiber_wakeup({call,From}, snooze_sync, _, Data) -> + {keep_state,Data, [{reply,From,please_just_five_more}, hibernate]}; -hiber_wakeup(cast, wakeup_async, _, _, Data) -> +hiber_wakeup(cast, wakeup_async, _, Data) -> {next_state,hiber_idle,Data}; -hiber_wakeup(cast, snooze_async, _, State, Data) -> - {next_state,State,Data, +hiber_wakeup(cast, snooze_async, _, Data) -> + {keep_state,Data, [hibernate]}; -hiber_wakeup(Type, Content, PrevState, State, Data) -> - case handle_common_events(Type, Content, PrevState, State, Data) of +hiber_wakeup(Type, Content, _, Data) -> + case handle_common_events(Type, Content, hiber_wakeup, Data) of undefined -> - {next_state,State,Data}; + {keep_state,Data}; Result -> Result end. -handle_common_events({call,From}, get, _, State, Data) -> - {next_state,State,Data, +handle_common_events({call,From}, get, State, Data) -> + {keep_state,Data, [{reply,From,{state,State,Data}}]}; -handle_common_events(cast, {get,Pid}, _, State, Data) -> +handle_common_events(cast, {get,Pid}, State, Data) -> Pid ! {state,State,Data}, - {next_state,State,Data}; -handle_common_events({call,From}, stop, _, _, Data) -> + {keep_state,Data}; +handle_common_events({call,From}, stop, _, Data) -> {stop_and_reply,normal,[{reply,From,stopped}],Data}; -handle_common_events(cast, stop, _, _, _) -> +handle_common_events(cast, stop, _, _) -> {stop,normal}; -handle_common_events({call,From}, {stop,Reason}, _, _, Data) -> +handle_common_events({call,From}, {stop,Reason}, _, Data) -> {stop_and_reply,Reason,{reply,From,stopped},Data}; -handle_common_events(cast, {stop,Reason}, _, _, _) -> - {stop,Reason}; -handle_common_events({call,From}, 'alive?', _, State, Data) -> - {next_state,State,Data, +handle_common_events(cast, {stop,Reason}, _, _) -> + {stop,Reason}; +handle_common_events({call,From}, 'alive?', _, Data) -> + {keep_state,Data, [{reply,From,yes}]}; -handle_common_events(cast, {'alive?',Pid}, _, State, Data) -> +handle_common_events(cast, {'alive?',Pid}, _, Data) -> Pid ! yes, - {next_state,State,Data}; -handle_common_events(_, _, _, _, _) -> + {keep_state,Data}; +handle_common_events(_, _, _, _) -> undefined. %% Dispatcher to test callback_mode handle_event_function @@ -1356,8 +1356,7 @@ handle_common_events(_, _, _, _, _) -> handle_event(Type, Event, PrevState, State, Data) -> PrevStateName = unwrap_state(PrevState), StateName = unwrap_state(State), - try ?MODULE:StateName( - Type, Event, PrevStateName, StateName, Data) of + try ?MODULE:StateName(Type, Event, PrevStateName, Data) of Result -> wrap_result(Result) catch -- cgit v1.2.3 From 14028aee428c135211e33df77c1bee2fdc128f6e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Wed, 24 Feb 2016 16:36:24 +0100 Subject: Ditch PrevState StateName/4 -> StateName/3 handle_event/5 -> handle_event/4 --- lib/stdlib/test/gen_statem_SUITE.erl | 81 ++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 41 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 3302171329..27b042c0d8 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1160,26 +1160,26 @@ terminate(_Reason, _State, _Data) -> %% State functions -idle(cast, {connect,Pid}, _, Data) -> +idle(cast, {connect,Pid}, Data) -> Pid ! accept, {next_state,wfor_conf,Data}; -idle({call,From}, connect, _, Data) -> +idle({call,From}, connect, Data) -> gen_statem:reply(From, accept), {next_state,wfor_conf,Data}; -idle(cast, badreturn, _, _Data) -> +idle(cast, badreturn, _Data) -> badreturn; -idle({call,_From}, badreturn, _, _Data) -> +idle({call,_From}, badreturn, _Data) -> badreturn; -idle({call,From}, {delayed_answer,T}, _, Data) -> +idle({call,From}, {delayed_answer,T}, Data) -> receive after T -> gen_statem:reply({reply,From,delayed}), throw({keep_state,Data}) end; -idle({call,From}, {timeout,Time}, _, _Data) -> +idle({call,From}, {timeout,Time}, _Data) -> {next_state,timeout,{From,Time}, [{timeout,Time,idle}]}; -idle(Type, Content, PrevState, Data) -> +idle(Type, Content, Data) -> case handle_common_events(Type, Content, idle, Data) of undefined -> case Type of @@ -1187,45 +1187,45 @@ idle(Type, Content, PrevState, Data) -> throw({keep_state,Data,[{reply,From,'eh?'}]}); _ -> throw( - {stop,{unexpected,idle,Type,Content,PrevState}}) + {stop,{unexpected,idle,Type,Content}}) end; Result -> Result end. -timeout(timeout, idle, idle, {From,Time}) -> +timeout(timeout, idle, {From,Time}) -> TRef2 = erlang:start_timer(Time, self(), ok), TRefC1 = erlang:start_timer(Time, self(), cancel1), TRefC2 = erlang:start_timer(Time, self(), cancel2), {next_state,timeout2,{From,Time,TRef2}, [{cancel_timer, TRefC1}, {next_event,internal,{cancel_timer,TRefC2}}]}; -timeout(_, _, _, Data) -> +timeout(_, _, Data) -> {keep_state,Data}. timeout2( - internal, {cancel_timer,TRefC2}, timeout, {From,Time,TRef2}) -> + internal, {cancel_timer,TRefC2}, {From,Time,TRef2}) -> Time4 = Time * 4, receive after Time4 -> ok end, {next_state,timeout3,{From,TRef2}, [{cancel_timer,TRefC2}]}; -timeout2(_, _, _, Data) -> +timeout2(_, _, Data) -> {keep_state,Data}. -timeout3(info, {timeout,TRef2,Result}, _, {From,TRef2}) -> +timeout3(info, {timeout,TRef2,Result}, {From,TRef2}) -> gen_statem:reply([{reply,From,Result}]), {next_state,idle,state}; -timeout3(_, _, _, Data) -> +timeout3(_, _, Data) -> {keep_state,Data}. -wfor_conf({call,From}, confirm, _, Data) -> +wfor_conf({call,From}, confirm, Data) -> {next_state,connected,Data, [{reply,From,yes}]}; -wfor_conf(cast, {ping,_,_}, _, _) -> +wfor_conf(cast, {ping,_,_}, _) -> {keep_state_and_data,[postpone]}; -wfor_conf(cast, confirm, _, Data) -> +wfor_conf(cast, confirm, Data) -> {next_state,connected,Data}; -wfor_conf(Type, Content, _, Data) -> +wfor_conf(Type, Content, Data) -> case handle_common_events(Type, Content, wfor_conf, Data) of undefined -> case Type of @@ -1239,21 +1239,21 @@ wfor_conf(Type, Content, _, Data) -> Result end. -connected({call,From}, {msg,Ref}, _, Data) -> +connected({call,From}, {msg,Ref}, Data) -> {keep_state,Data, [{reply,From,{ack,Ref}}]}; -connected(cast, {msg,From,Ref}, _, Data) -> +connected(cast, {msg,From,Ref}, Data) -> From ! {ack,Ref}, {keep_state,Data}; -connected({call,From}, disconnect, _, Data) -> +connected({call,From}, disconnect, Data) -> {next_state,idle,Data, [{reply,From,yes}]}; -connected(cast, disconnect, _, Data) -> +connected(cast, disconnect, Data) -> {next_state,idle,Data}; -connected(cast, {ping,Pid,Tag}, _, Data) -> +connected(cast, {ping,Pid,Tag}, Data) -> Pid ! {pong,Tag}, {keep_state,Data}; -connected(Type, Content, _, Data) -> +connected(Type, Content, Data) -> case handle_common_events(Type, Content, connected, Data) of undefined -> case Type of @@ -1267,9 +1267,9 @@ connected(Type, Content, _, Data) -> Result end. -state0({call,From}, stop, _, Data) -> +state0({call,From}, stop, Data) -> {stop_and_reply,normal,[{reply,From,stopped}],Data}; -state0(Type, Content, _, Data) -> +state0(Type, Content, Data) -> case handle_common_events(Type, Content, state0, Data) of undefined -> {keep_state,Data}; @@ -1277,26 +1277,26 @@ state0(Type, Content, _, Data) -> Result end. -hiber_idle({call,From}, 'alive?', _, Data) -> +hiber_idle({call,From}, 'alive?', Data) -> {keep_state,Data, [{reply,From,'alive!'}]}; -hiber_idle({call,From}, hibernate_sync, _, Data) -> +hiber_idle({call,From}, hibernate_sync, Data) -> {next_state,hiber_wakeup,Data, [{reply,From,hibernating}, hibernate]}; -hiber_idle(info, hibernate_later, _, _) -> +hiber_idle(info, hibernate_later, _) -> Tref = erlang:start_timer(1000, self(), hibernate), {keep_state,Tref}; -hiber_idle(info, hibernate_now, _, Data) -> +hiber_idle(info, hibernate_now, Data) -> {keep_state,Data, [hibernate]}; -hiber_idle(info, {timeout,Tref,hibernate}, _, Tref) -> +hiber_idle(info, {timeout,Tref,hibernate}, Tref) -> {keep_state,[], [hibernate]}; -hiber_idle(cast, hibernate_async, _, Data) -> +hiber_idle(cast, hibernate_async, Data) -> {next_state,hiber_wakeup,Data, [hibernate]}; -hiber_idle(Type, Content, _, Data) -> +hiber_idle(Type, Content, Data) -> case handle_common_events(Type, Content, hiber_idle, Data) of undefined -> {keep_state,Data}; @@ -1304,19 +1304,19 @@ hiber_idle(Type, Content, _, Data) -> Result end. -hiber_wakeup({call,From}, wakeup_sync, _, Data) -> +hiber_wakeup({call,From}, wakeup_sync, Data) -> {next_state,hiber_idle,Data, [{reply,From,good_morning}]}; -hiber_wakeup({call,From}, snooze_sync, _, Data) -> +hiber_wakeup({call,From}, snooze_sync, Data) -> {keep_state,Data, [{reply,From,please_just_five_more}, hibernate]}; -hiber_wakeup(cast, wakeup_async, _, Data) -> +hiber_wakeup(cast, wakeup_async, Data) -> {next_state,hiber_idle,Data}; -hiber_wakeup(cast, snooze_async, _, Data) -> +hiber_wakeup(cast, snooze_async, Data) -> {keep_state,Data, [hibernate]}; -hiber_wakeup(Type, Content, _, Data) -> +hiber_wakeup(Type, Content, Data) -> case handle_common_events(Type, Content, hiber_wakeup, Data) of undefined -> {keep_state,Data}; @@ -1353,10 +1353,9 @@ handle_common_events(_, _, _, _) -> %% Wrap the state in a 1 element list just to test non-atom %% states. Note that the state from init/1 is not wrapped %% so both atom and non-atom states are tested. -handle_event(Type, Event, PrevState, State, Data) -> - PrevStateName = unwrap_state(PrevState), +handle_event(Type, Event, State, Data) -> StateName = unwrap_state(State), - try ?MODULE:StateName(Type, Event, PrevStateName, Data) of + try ?MODULE:StateName(Type, Event, Data) of Result -> wrap_result(Result) catch -- cgit v1.2.3 From edc94441562b255467773ec27b11835910a708fd Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 25 Feb 2016 15:12:48 +0100 Subject: Remove {keep_state_and_data} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Correct typo reported by Luïc Hoguin. --- lib/stdlib/test/gen_statem_SUITE.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 27b042c0d8..f5cbdd9a40 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1233,7 +1233,7 @@ wfor_conf(Type, Content, Data) -> {next_state,idle,Data, [{reply,From,'eh?'}]}; _ -> - throw({keep_state_and_data}) + throw({keep_state_and_data,[]}) end; Result -> Result -- cgit v1.2.3 From 1e4831762b5ab4bd2210fc9e0a204e00dfe81b39 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 26 Feb 2016 10:35:16 +0100 Subject: Implement 'keep_state_and_data' and 'stop' --- lib/stdlib/test/gen_statem_SUITE.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index f5cbdd9a40..09b309c36f 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1233,7 +1233,7 @@ wfor_conf(Type, Content, Data) -> {next_state,idle,Data, [{reply,From,'eh?'}]}; _ -> - throw({keep_state_and_data,[]}) + throw(keep_state_and_data) end; Result -> Result @@ -1334,7 +1334,7 @@ handle_common_events(cast, {get,Pid}, State, Data) -> handle_common_events({call,From}, stop, _, Data) -> {stop_and_reply,normal,[{reply,From,stopped}],Data}; handle_common_events(cast, stop, _, _) -> - {stop,normal}; + stop; handle_common_events({call,From}, {stop,Reason}, _, Data) -> {stop_and_reply,Reason,{reply,From,stopped},Data}; handle_common_events(cast, {stop,Reason}, _, _) -> -- cgit v1.2.3 From efda33e83f2bbc666f6ec261d54ad95c38acbc36 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 26 Feb 2016 10:51:53 +0100 Subject: Allow actions without containing list Type check atom state as early as possible --- lib/stdlib/test/gen_statem_SUITE.erl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 09b309c36f..0429c0e5f4 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1178,7 +1178,7 @@ idle({call,From}, {delayed_answer,T}, Data) -> end; idle({call,From}, {timeout,Time}, _Data) -> {next_state,timeout,{From,Time}, - [{timeout,Time,idle}]}; + {timeout,Time,idle}}; idle(Type, Content, Data) -> case handle_common_events(Type, Content, idle, Data) of undefined -> @@ -1220,7 +1220,7 @@ timeout3(_, _, Data) -> wfor_conf({call,From}, confirm, Data) -> {next_state,connected,Data, - [{reply,From,yes}]}; + {reply,From,yes}}; wfor_conf(cast, {ping,_,_}, _) -> {keep_state_and_data,[postpone]}; wfor_conf(cast, confirm, Data) -> @@ -1241,7 +1241,7 @@ wfor_conf(Type, Content, Data) -> connected({call,From}, {msg,Ref}, Data) -> {keep_state,Data, - [{reply,From,{ack,Ref}}]}; + {reply,From,{ack,Ref}}}; connected(cast, {msg,From,Ref}, Data) -> From ! {ack,Ref}, {keep_state,Data}; -- cgit v1.2.3 From ded8d9e3ec0ba6481d80e28f6057e6ccf5a6d575 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 26 Feb 2016 14:35:25 +0100 Subject: ct:ify test suite --- lib/stdlib/test/gen_statem_SUITE.erl | 165 ++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 79 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 0429c0e5f4..321573b721 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -26,7 +26,9 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. all() -> [{group, start}, @@ -82,27 +84,24 @@ end_per_group(_GroupName, Config) -> Config. init_per_testcase(_CaseName, Config) -> - ?t:messages_get(), - Dog = ?t:timetrap(?t:minutes(1)), + flush(), %%% dbg:tracer(), %%% dbg:p(all, c), %%% dbg:tpl(gen_statem, cx), %%% dbg:tpl(proc_lib, cx), %%% dbg:tpl(gen, cx), %%% dbg:tpl(sys, cx), - [{watchdog, Dog} | Config]. + Config. end_per_testcase(_CaseName, Config) -> %%% dbg:stop(), - Dog = ?config(watchdog, Config), - test_server:timetrap_cancel(Dog), Config. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -define(EXPECT_FAILURE(Code, Reason), try begin Code end of - _ -> - ?t:fail() + Reason -> + ct:fail({unexpected,Reason}) catch error:Reason -> Reason; exit:Reason -> Reason @@ -110,7 +109,7 @@ end_per_testcase(_CaseName, Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% anonymous -start1(Config) when is_list(Config) -> +start1(Config) -> %%OldFl = process_flag(trap_exit, true), {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), @@ -125,7 +124,7 @@ start1(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% anonymous w. shutdown -start2(Config) when is_list(Config) -> +start2(Config) -> %% Dont link when shutdown {ok,Pid0} = gen_statem:start(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid0), @@ -135,7 +134,7 @@ start2(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% anonymous with timeout -start3(Config) when is_list(Config) -> +start3(Config) -> %%OldFl = process_flag(trap_exit, true), {ok,Pid0} = @@ -152,7 +151,7 @@ start3(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% anonymous with ignore -start4(Config) when is_list(Config) -> +start4(Config) -> OldFl = process_flag(trap_exit, true), ignore = gen_statem:start(?MODULE, start_arg(Config, ignore), []), @@ -161,8 +160,7 @@ start4(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% anonymous with stop -start5(suite) -> []; -start5(Config) when is_list(Config) -> +start5(Config) -> OldFl = process_flag(trap_exit, true), {error,stopped} = gen_statem:start(?MODULE, start_arg(Config, stop), []), @@ -171,7 +169,7 @@ start5(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% anonymous linked -start6(Config) when is_list(Config) -> +start6(Config) -> {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), ok = do_func_test(Pid), ok = do_sync_func_test(Pid), @@ -180,7 +178,7 @@ start6(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% global register linked -start7(Config) when is_list(Config) -> +start7(Config) -> STM = {global,my_stm}, {ok,Pid} = @@ -200,7 +198,7 @@ start7(Config) when is_list(Config) -> %% local register -start8(Config) when is_list(Config) -> +start8(Config) -> %%OldFl = process_flag(trap_exit, true), Name = my_stm, STM = {local,Name}, @@ -220,7 +218,7 @@ start8(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% local register linked -start9(Config) when is_list(Config) -> +start9(Config) -> %%OldFl = process_flag(trap_exit, true), Name = my_stm, STM = {local,Name}, @@ -240,7 +238,7 @@ start9(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% global register -start10(Config) when is_list(Config) -> +start10(Config) -> STM = {global,my_stm}, {ok,Pid} = @@ -259,7 +257,7 @@ start10(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% Stop registered processes -start11(Config) when is_list(Config) -> +start11(Config) -> Name = my_stm, LocalSTM = {local,Name}, GlobalSTM = {global,Name}, @@ -278,14 +276,14 @@ start11(Config) when is_list(Config) -> receive after 1 -> true end, Result = gen_statem:start(GlobalSTM, ?MODULE, start_arg(Config, []), []), - io:format("Result = ~p~n",[Result]), + ct:log("Result = ~p~n",[Result]), {ok,_Pid3} = Result, stop_it(GlobalSTM), ok = verify_empty_msgq(). %% Via register linked -start12(Config) when is_list(Config) -> +start12(Config) -> dummy_via:reset(), VIA = {via,dummy_via,my_stm}, @@ -378,19 +376,20 @@ stop7(Config) -> %% Anonymous on remote node stop8(Config) -> - {ok,Node} = ?t:start_node(gen_statem_stop8, slave, []), + Node = gen_statem_stop8, + {ok,NodeName} = ct_slave:start(Node), Dir = filename:dirname(code:which(?MODULE)), - rpc:call(Node, code, add_path, [Dir]), + rpc:call(NodeName, code, add_path, [Dir]), {ok,Pid} = rpc:call( - Node, gen_statem,start, + NodeName, gen_statem,start, [?MODULE,start_arg(Config, []),[]]), ok = gen_statem:stop(Pid), - false = rpc:call(Node, erlang, is_process_alive, [Pid]), + false = rpc:call(NodeName, erlang, is_process_alive, [Pid]), noproc = ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason1), - true = ?t:stop_node(Node), - {{nodedown,Node},{sys,terminate,_}} = + {ok,NodeName} = ct_slave:stop(Node), + {{nodedown,NodeName},{sys,terminate,_}} = ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason2), ok. @@ -398,46 +397,48 @@ stop8(Config) -> stop9(Config) -> Name = to_stop, LocalSTM = {local,Name}, - {ok,Node} = ?t:start_node(gen_statem__stop9, slave, []), - STM = {Name,Node}, + Node = gen_statem__stop9, + {ok,NodeName} = ct_slave:start(Node), + STM = {Name,NodeName}, Dir = filename:dirname(code:which(?MODULE)), - rpc:call(Node, code, add_path, [Dir]), + rpc:call(NodeName, code, add_path, [Dir]), {ok,Pid} = rpc:call( - Node, gen_statem, start, + NodeName, gen_statem, start, [LocalSTM,?MODULE,start_arg(Config, []),[]]), ok = gen_statem:stop(STM), - undefined = rpc:call(Node,erlang,whereis,[Name]), - false = rpc:call(Node,erlang,is_process_alive,[Pid]), + undefined = rpc:call(NodeName,erlang,whereis,[Name]), + false = rpc:call(NodeName,erlang,is_process_alive,[Pid]), noproc = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), - true = ?t:stop_node(Node), - {{nodedown,Node},{sys,terminate,_}} = + {ok,NodeName} = ct_slave:stop(Node), + {{nodedown,NodeName},{sys,terminate,_}} = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), ok. %% Globally registered name on remote node stop10(Config) -> + Node = gen_statem_stop10, STM = {global,to_stop}, - {ok,Node} = ?t:start_node(gen_statem_stop10, slave, []), + {ok,NodeName} = ct_slave:start(Node), Dir = filename:dirname(code:which(?MODULE)), - rpc:call(Node,code,add_path,[Dir]), + rpc:call(NodeName,code,add_path,[Dir]), {ok,Pid} = rpc:call( - Node, gen_statem, start, + NodeName, gen_statem, start, [STM,?MODULE,start_arg(Config, []),[]]), global:sync(), ok = gen_statem:stop(STM), - false = rpc:call(Node, erlang, is_process_alive, [Pid]), + false = rpc:call(NodeName, erlang, is_process_alive, [Pid]), noproc = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason1), - true = ?t:stop_node(Node), + {ok,NodeName} = ct_slave:stop(Node), noproc = ?EXPECT_FAILURE(gen_statem:stop(STM), Reason2), ok. %% Check that time outs in calls work -abnormal1(Config) when is_list(Config) -> +abnormal1(Config) -> Name = abnormal1, LocalSTM = {local,Name}, @@ -455,7 +456,7 @@ abnormal1(Config) when is_list(Config) -> %% Check that bad return values makes the stm crash. Note that we must %% trap exit since we must link to get the real bad_return_ error -abnormal2(Config) when is_list(Config) -> +abnormal2(Config) -> OldFl = process_flag(trap_exit, true), {ok,Pid} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), @@ -465,13 +466,13 @@ abnormal2(Config) when is_list(Config) -> receive {'EXIT',Pid,{bad_return_value,badreturn}} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, process_flag(trap_exit, OldFl), ok = verify_empty_msgq(). -shutdown(Config) when is_list(Config) -> +shutdown(Config) -> process_flag(trap_exit, true), {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []), @@ -486,15 +487,15 @@ shutdown(Config) when is_list(Config) -> receive Any -> - io:format("Unexpected: ~p", [Any]), - ?t:fail() + ct:log("Unexpected: ~p", [Any]), + ct:fail({unexpected,Any}) after 500 -> ok end. -sys1(Config) when is_list(Config) -> +sys1(Config) -> {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), {status, Pid, {module,gen_statem}, _} = sys:get_status(Pid), sys:suspend(Pid), @@ -507,7 +508,7 @@ sys1(Config) when is_list(Config) -> end), receive {Tag,_} -> - ?t:fail() + ct:fail(should_be_suspended) after 3000 -> exit(Caller, ok) end, @@ -517,7 +518,7 @@ sys1(Config) when is_list(Config) -> sys:resume(Pid), stop_it(Pid). -call_format_status(Config) when is_list(Config) -> +call_format_status(Config) -> {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), Status = sys:get_status(Pid), {status,Pid,_Mod,[_PDict,running,_,_, Data]} = Status, @@ -573,7 +574,7 @@ call_format_status(Config) when is_list(Config) -> -error_format_status(Config) when is_list(Config) -> +error_format_status(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), Data = "called format_status", @@ -593,10 +594,10 @@ error_format_status(Config) when is_list(Config) -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> error_logger_forwarder:unregister(), - ?t:fail({unexpected,Other}) + ct:fail({unexpected,Other}) after 1000 -> error_logger_forwarder:unregister(), - ?t:fail() + ct:fail(timeout) end, process_flag(trap_exit, OldFl), error_logger_forwarder:unregister(), @@ -609,7 +610,7 @@ error_format_status(Config) when is_list(Config) -> end, ok = verify_empty_msgq(). -terminate_crash_format(Config) when is_list(Config) -> +terminate_crash_format(Config) -> error_logger_forwarder:register(), OldFl = process_flag(trap_exit, true), Data = crash_terminate, @@ -629,10 +630,10 @@ terminate_crash_format(Config) when is_list(Config) -> ok; Other when is_tuple(Other), element(1, Other) =:= error -> error_logger_forwarder:unregister(), - ?t:fail({unexpected,Other}) + ct:fail({unexpected,Other}) after 1000 -> error_logger_forwarder:unregister(), - ?t:fail() + ct:fail(timeout) end, process_flag(trap_exit, OldFl), error_logger_forwarder:unregister(), @@ -646,7 +647,7 @@ terminate_crash_format(Config) when is_list(Config) -> ok = verify_empty_msgq(). -get_state(Config) when is_list(Config) -> +get_state(Config) -> State = self(), {ok,Pid} = gen_statem:start( @@ -675,7 +676,7 @@ get_state(Config) when is_list(Config) -> stop_it(Pid3), ok = verify_empty_msgq(). -replace_state(Config) when is_list(Config) -> +replace_state(Config) -> State = self(), {ok, Pid} = gen_statem:start( @@ -707,7 +708,7 @@ replace_state(Config) when is_list(Config) -> ok = verify_empty_msgq(). %% Hibernation -hibernate(Config) when is_list(Config) -> +hibernate(Config) -> OldFl = process_flag(trap_exit, true), {ok,Pid0} = @@ -718,7 +719,7 @@ hibernate(Config) when is_list(Config) -> receive {'EXIT',Pid0,normal} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, {ok,Pid} = @@ -801,7 +802,7 @@ hibernate(Config) when is_list(Config) -> receive {'EXIT',Pid,normal} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, ok = verify_empty_msgq(). @@ -810,8 +811,8 @@ is_in_erlang_hibernate(Pid) -> is_in_erlang_hibernate_1(200, Pid). is_in_erlang_hibernate_1(0, Pid) -> - io:format("~p\n", [erlang:process_info(Pid, current_function)]), - ?t:fail(not_in_erlang_hibernate_3); + ct:log("~p\n", [erlang:process_info(Pid, current_function)]), + ct:fail(not_in_erlang_hibernate_3); is_in_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of @@ -827,8 +828,8 @@ is_not_in_erlang_hibernate(Pid) -> is_not_in_erlang_hibernate_1(200, Pid). is_not_in_erlang_hibernate_1(0, Pid) -> - io:format("~p\n", [erlang:process_info(Pid, current_function)]), - ?t:fail(not_in_erlang_hibernate_3); + ct:log("~p\n", [erlang:process_info(Pid, current_function)]), + ct:fail(not_in_erlang_hibernate_3); is_not_in_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of @@ -839,10 +840,8 @@ is_not_in_erlang_hibernate_1(N, Pid) -> ok end. -%%sys1(suite) -> []; -%%sys1(_) -> -enter_loop(Config) when is_list(Config) -> +enter_loop(_Config) -> OldFlag = process_flag(trap_exit, true), dummy_via:reset(), @@ -856,7 +855,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid1a,normal} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Unregistered process + {local,Name} @@ -866,7 +865,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid1b,process_not_registered} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Globally registered process + {global,Name} @@ -878,7 +877,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid2a,normal} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Unregistered process + {global,Name} @@ -888,7 +887,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid2b,process_not_registered_globally} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Unregistered process + no name @@ -900,7 +899,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid3,normal} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Process not started using proc_lib @@ -913,7 +912,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid4,process_was_not_started_by_proc_lib} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Make sure I am the parent, ie that ordering a shutdown will @@ -926,7 +925,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid5,shutdown} -> ok after 5000 -> - ?t:fail(gen_statem_did_not_die) + ct:fail(gen_statem_did_not_die) end, %% Make sure gen_statem:enter_loop does not accept {local,Name} @@ -939,7 +938,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid6a,process_not_registered} -> ok after 1000 -> - ?t:fail(gen_statem_started) + ct:fail(gen_statem_started) end, unregister(armitage), @@ -953,7 +952,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid6b,process_not_registered_globally} -> ok after 1000 -> - ?t:fail(gen_statem_started) + ct:fail(gen_statem_started) end, global:unregister_name(armitage), @@ -964,7 +963,7 @@ enter_loop(Config) when is_list(Config) -> {'EXIT',Pid6c,{process_not_registered_via,dummy_via}} -> ok after 1000 -> - ?t:fail( + ct:fail( {gen_statem_started, process_info(self(), messages)}) end, @@ -1105,7 +1104,7 @@ do_sync_disconnect(STM) -> verify_empty_msgq() -> receive after 500 -> ok end, - [] = ?t:messages_get(), + [] = flush(), ok. start_arg(Config, Arg) -> @@ -1388,3 +1387,11 @@ format_status(terminate, [_Pdict,State,Data]) -> {formatted,State,Data}; format_status(normal, [_Pdict,_State,_Data]) -> [format_status_called]. + +flush() -> + receive + Msg -> + [Msg|flush()] + after 0 -> + [] + end. -- cgit v1.2.3 From df457111fbb82d160605f45c43552249cd6f8ac5 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Fri, 26 Feb 2016 14:52:24 +0100 Subject: Test the order for multiple next_event --- lib/stdlib/test/gen_statem_SUITE.erl | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 321573b721..268b45a0e7 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -44,10 +44,10 @@ all() -> groups() -> [{start, [], [start1, start2, start3, start4, start5, start6, start7, - start8, start9, start10, start11, start12]}, + start8, start9, start10, start11, start12, next_events]}, {start_handle_event, [], [start1, start2, start3, start4, start5, start6, start7, - start8, start9, start10, start11, start12]}, + start8, start9, start10, start11, start12, next_events]}, {stop, [], [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]}, {stop_handle_event, [], @@ -998,6 +998,18 @@ enter_loop(Reg1, Reg2) -> ?MODULE, [], CallbackMode, state0, []) end. + +%% Test the order for multiple {next_event,T,C} +next_events(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), + ok = gen_statem:cast(Pid, next_event), + {state,next_events,[]} = gen_statem:call(Pid, get), + ok = gen_statem:stop(Pid), + false = erlang:is_process_alive(Pid), + noproc = + ?EXPECT_FAILURE(gen_statem:stop(Pid), Reason). + + %% %% Functionality check %% @@ -1178,6 +1190,11 @@ idle({call,From}, {delayed_answer,T}, Data) -> idle({call,From}, {timeout,Time}, _Data) -> {next_state,timeout,{From,Time}, {timeout,Time,idle}}; +idle(cast, next_event, _Data) -> + {next_state,next_events,[a,b,c], + [{next_event,internal,a}, + {next_event,internal,b}, + {next_event,internal,c}]}; idle(Type, Content, Data) -> case handle_common_events(Type, Content, idle, Data) of undefined -> @@ -1323,6 +1340,16 @@ hiber_wakeup(Type, Content, Data) -> Result end. +next_events(internal, Msg, [Msg|Msgs]) -> + {keep_state,Msgs}; +next_events(Type, Content, Data) -> + case handle_common_events(Type, Content, next_events, Data) of + undefined -> + {keep_state,Data}; + Result -> + Result + end. + handle_common_events({call,From}, get, State, Data) -> {keep_state,Data, -- cgit v1.2.3 From e660572b020da58c89149c7f052c7127cc0263cb Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 29 Feb 2016 11:36:27 +0100 Subject: Remove the remove_event action and all alike Removing events from the internal queues is not necessary with the choosen semantics of the event queue vs. hibernate. In an early implementation it was possible by combining hibernate with e.g. postpone to get an event in the queue that you would not see before processing the postponed event, and therefore should you decide to cancel a timer it was essential to be able to remove that unseen event from the queue. With the choosen semantics you will have to postpone or generate an event for it to be in the event queue, and if you e.g. postpone a timeout event and then cancel the timer it is your mistake. You have seen the event and should know better than to try to cancel the timer. So, the actions: remove_event, cancel_timer, demonitor and unlink are now removed. There have also been some cleanup of the timer handling code. --- lib/stdlib/test/gen_statem_SUITE.erl | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 268b45a0e7..38aab752b8 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1210,29 +1210,22 @@ idle(Type, Content, Data) -> end. timeout(timeout, idle, {From,Time}) -> - TRef2 = erlang:start_timer(Time, self(), ok), - TRefC1 = erlang:start_timer(Time, self(), cancel1), - TRefC2 = erlang:start_timer(Time, self(), cancel2), - {next_state,timeout2,{From,Time,TRef2}, - [{cancel_timer, TRefC1}, - {next_event,internal,{cancel_timer,TRefC2}}]}; -timeout(_, _, Data) -> - {keep_state,Data}. - -timeout2( - internal, {cancel_timer,TRefC2}, {From,Time,TRef2}) -> - Time4 = Time * 4, - receive after Time4 -> ok end, - {next_state,timeout3,{From,TRef2}, - [{cancel_timer,TRefC2}]}; -timeout2(_, _, Data) -> - {keep_state,Data}. - -timeout3(info, {timeout,TRef2,Result}, {From,TRef2}) -> + TRef = erlang:start_timer(Time, self(), ok), + {next_state,timeout2,{From,TRef}, + [{timeout,1,should_be_cancelled}, + postpone]}; % Should cancel state timeout +timeout(_, _, _) -> + keep_state_and_data. + +timeout2(timeout, idle, _) -> + keep_state_and_data; +timeout2(timeout, Reason, _) -> + {stop,Reason}; +timeout2(info, {timeout,TRef,Result}, {From,TRef}) -> gen_statem:reply([{reply,From,Result}]), {next_state,idle,state}; -timeout3(_, _, Data) -> - {keep_state,Data}. +timeout2(_, _, _) -> + {keep_state_and_data,[]}. wfor_conf({call,From}, confirm, Data) -> {next_state,connected,Data, -- cgit v1.2.3 From 79d75b981274f6841e1d4c09c125f92e1731ab4b Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 29 Feb 2016 16:10:00 +0100 Subject: Sharpen test suite --- lib/stdlib/test/gen_statem_SUITE.erl | 141 ++++++++++++++++++++++++++++++++++- 1 file changed, 138 insertions(+), 3 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 38aab752b8..e62255035d 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -37,7 +37,7 @@ all() -> {group, stop_handle_event}, {group, abnormal}, {group, abnormal_handle_event}, - shutdown, + shutdown, stop_and_reply, postpone_and_next_event, {group, sys}, hibernate, enter_loop]. @@ -495,6 +495,113 @@ shutdown(Config) -> +stop_and_reply(_Config) -> + process_flag(trap_exit, true), + + Machine = + %% Abusing the internal format of From... + #{init => + fun (cast, {echo,From1,Reply1}, _) -> + {next_state,wait,{reply,From1,Reply1}} + end, + wait => + fun (cast, {stop_and_reply,Reason,From2,Reply2},R1) -> + {stop_and_reply,Reason, + [R1,{reply,From2,Reply2}]} + end}, + {ok,STM} = + gen_statem:start_link( + ?MODULE, + {map_statem,Machine,init,undefined,[]}, + []), + + Self = self(), + Tag1 = make_ref(), + gen_statem:cast(STM, {echo,{Self,Tag1},reply1}), + Tag2 = make_ref(), + gen_statem:cast(STM, {stop_and_reply,reason,{Self,Tag2},reply2}), + case flush() of + [{Tag1,reply1},{Tag2,reply2},{'EXIT',STM,reason}] -> + ok; + Other1 -> + ct:fail({unexpected,Other1}) + end, + + {noproc,_} = + ?EXPECT_FAILURE(gen_statem:call(STM, hej), Reason), + case flush() of + [] -> + ok; + Other2 -> + ct:fail({unexpected,Other2}) + end. + + + +postpone_and_next_event(_Config) -> + process_flag(trap_exit, true), + + Machine = + %% Abusing the internal format of From... + #{init => + fun (cast, _, _) -> + {keep_state_and_data,postpone}; + ({call,From}, {buffer,Pid,[Tag3,Tag4]}, _) -> + {next_state,buffer,[], + [{next_event,internal,{reply,{Pid,Tag3},ok3}}, + {next_event,internal,{reply,{Pid,Tag4},ok4}}, + {reply,From,ok}]} + end, + buffer => + fun (internal, Reply, Replies) -> + {keep_state,[Reply|Replies]}; + (cast, Reply, Replies) -> + {keep_state,[Reply|Replies]}; + ({call,From}, {stop,Reason}, Replies) -> + {next_state,stop,Replies, + lists:reverse( + Replies, + [{reply,From,ok}, + {next_event,internal,{stop,Reason}}])} + end, + stop => + fun (internal, Result, _) -> + Result + end}, + + {ok,STM} = + gen_statem:start_link( + ?MODULE, + {map_statem,Machine,init,undefined,[]}, + []), + Self = self(), + Tag1 = make_ref(), + gen_statem:cast(STM, {reply,{Self,Tag1},ok1}), + Tag2 = make_ref(), + gen_statem:cast(STM, {reply,{Self,Tag2},ok2}), + Tag3 = make_ref(), + Tag4 = make_ref(), + ok = gen_statem:call(STM, {buffer,Self,[Tag3,Tag4]}), + ok = gen_statem:call(STM, {stop,reason}), + case flush() of + [{Tag3,ok3},{Tag4,ok4},{Tag1,ok1},{Tag2,ok2}, + {'EXIT',STM,reason}] -> + ok; + Other1 -> + ct:fail({unexpected,Other1}) + end, + + {noproc,_} = + ?EXPECT_FAILURE(gen_statem:call(STM, hej), Reason), + case flush() of + [] -> + ok; + Other2 -> + ct:fail({unexpected,Other2}) + end. + + + sys1(Config) -> {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), {status, Pid, {module,gen_statem}, _} = sys:get_status(Pid), @@ -1115,7 +1222,6 @@ do_sync_disconnect(STM) -> verify_empty_msgq() -> - receive after 500 -> ok end, [] = flush(), ok. @@ -1157,6 +1263,8 @@ init({callback_mode,CallbackMode,Arg}) -> Other -> Other end; +init({map_statem,Machine,State,Data,Ops}) when is_map(Machine) -> + {handle_event_function,State,[Data|Machine],Ops}; init([]) -> {state_functions,idle,data}. @@ -1367,6 +1475,33 @@ handle_common_events(cast, {'alive?',Pid}, _, Data) -> handle_common_events(_, _, _, _) -> undefined. +%% Wrapper state machine that uses a map state machine spec +handle_event( + Type, Event, State, [Data|Machine]) + when is_map(Machine) -> + #{State := HandleEvent} = Machine, + case + try HandleEvent(Type, Event, Data) of + Result -> + Result + catch + Result -> + Result + end of + {stop,Reason,NewData} -> + {stop,Reason,[NewData|Machine]}; + {next_state,NewState,NewData} -> + {next_state,NewState,[NewData|Machine]}; + {next_state,NewState,NewData,Ops} -> + {next_state,NewState,[NewData|Machine],Ops}; + {keep_state,NewData} -> + {keep_state,[NewData|Machine]}; + {keep_state,NewData,Ops} -> + {keep_state,[NewData|Machine],Ops}; + Other -> + Other + end; +%% %% Dispatcher to test callback_mode handle_event_function %% %% Wrap the state in a 1 element list just to test non-atom @@ -1412,6 +1547,6 @@ flush() -> receive Msg -> [Msg|flush()] - after 0 -> + after 500 -> [] end. -- cgit v1.2.3 From a0c69303c971b4c65e5cd450dbe7de680aa58181 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 1 Mar 2016 09:08:30 +0100 Subject: Fixup sharpened test suite --- lib/stdlib/test/gen_statem_SUITE.erl | 55 +++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 20 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index e62255035d..f605f0c7b9 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -37,7 +37,7 @@ all() -> {group, stop_handle_event}, {group, abnormal}, {group, abnormal_handle_event}, - shutdown, stop_and_reply, postpone_and_next_event, + shutdown, stop_and_reply, event_order, {group, sys}, hibernate, enter_loop]. @@ -501,7 +501,11 @@ stop_and_reply(_Config) -> Machine = %% Abusing the internal format of From... #{init => - fun (cast, {echo,From1,Reply1}, _) -> + fun () -> + {ok,start,undefined} + end, + start => + fun (cast, {echo,From1,Reply1}, undefined) -> {next_state,wait,{reply,From1,Reply1}} end, wait => @@ -509,11 +513,7 @@ stop_and_reply(_Config) -> {stop_and_reply,Reason, [R1,{reply,From2,Reply2}]} end}, - {ok,STM} = - gen_statem:start_link( - ?MODULE, - {map_statem,Machine,init,undefined,[]}, - []), + {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine}, []), Self = self(), Tag1 = make_ref(), @@ -538,42 +538,49 @@ stop_and_reply(_Config) -> -postpone_and_next_event(_Config) -> +event_order(_Config) -> process_flag(trap_exit, true), Machine = %% Abusing the internal format of From... #{init => + fun () -> + {ok,start,undefined} + end, + start => fun (cast, _, _) -> - {keep_state_and_data,postpone}; - ({call,From}, {buffer,Pid,[Tag3,Tag4]}, _) -> + {keep_state_and_data,postpone}; %% Handled in 'buffer' + ({call,From}, {buffer,Pid,[Tag3,Tag4,Tag5]}, + undefined) -> {next_state,buffer,[], [{next_event,internal,{reply,{Pid,Tag3},ok3}}, {next_event,internal,{reply,{Pid,Tag4},ok4}}, + {timeout,0,{reply,{Pid,Tag5},ok5}}, + %% The timeout should not happen since there + %% are events that cancel it i.e next_event + %% and postponed {reply,From,ok}]} end, buffer => fun (internal, Reply, Replies) -> {keep_state,[Reply|Replies]}; + (timeout, Reply, Replies) -> + {keep_state,[Reply|Replies]}; (cast, Reply, Replies) -> {keep_state,[Reply|Replies]}; ({call,From}, {stop,Reason}, Replies) -> - {next_state,stop,Replies, + {next_state,stop,undefined, lists:reverse( Replies, [{reply,From,ok}, {next_event,internal,{stop,Reason}}])} end, stop => - fun (internal, Result, _) -> + fun (internal, Result, undefined) -> Result end}, - {ok,STM} = - gen_statem:start_link( - ?MODULE, - {map_statem,Machine,init,undefined,[]}, - []), + {ok,STM} = gen_statem:start_link(?MODULE, {map_statem,Machine}, []), Self = self(), Tag1 = make_ref(), gen_statem:cast(STM, {reply,{Self,Tag1},ok1}), @@ -581,7 +588,8 @@ postpone_and_next_event(_Config) -> gen_statem:cast(STM, {reply,{Self,Tag2},ok2}), Tag3 = make_ref(), Tag4 = make_ref(), - ok = gen_statem:call(STM, {buffer,Self,[Tag3,Tag4]}), + Tag5 = make_ref(), + ok = gen_statem:call(STM, {buffer,Self,[Tag3,Tag4,Tag5]}), ok = gen_statem:call(STM, {stop,reason}), case flush() of [{Tag3,ok3},{Tag4,ok4},{Tag1,ok1},{Tag2,ok2}, @@ -1263,8 +1271,15 @@ init({callback_mode,CallbackMode,Arg}) -> Other -> Other end; -init({map_statem,Machine,State,Data,Ops}) when is_map(Machine) -> - {handle_event_function,State,[Data|Machine],Ops}; +init({map_statem,#{init := Init}=Machine}) -> + case Init() of + {ok,State,Data,Ops} -> + {handle_event_function,State,[Data|Machine],Ops}; + {ok,State,Data} -> + {handle_event_function,State,[Data|Machine]}; + Other -> + Other + end; init([]) -> {state_functions,idle,data}. -- cgit v1.2.3 From 9dfb4e6cf574870ac6e6a5a2a507c989c64e7525 Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 1 Mar 2016 08:31:58 +0100 Subject: Change code_change/4 to {ok,State,Data} --- lib/stdlib/test/gen_statem_SUITE.erl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index f605f0c7b9..573a64bbb7 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -55,7 +55,7 @@ groups() -> {abnormal, [], [abnormal1, abnormal2]}, {abnormal_handle_event, [], [abnormal1, abnormal2]}, {sys, [], - [sys1, + [sys1, code_change, call_format_status, error_format_status, terminate_crash_format, get_state, replace_state]}, @@ -633,6 +633,15 @@ sys1(Config) -> sys:resume(Pid), stop_it(Pid). +code_change(Config) -> + {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), + {idle,data} = sys:get_state(Pid), + sys:suspend(Pid), + sys:change_code(Pid, ?MODULE, old_vsn, extra), + sys:resume(Pid), + {idle,{old_vsn,data,extra}} = sys:get_state(Pid), + stop_it(Pid). + call_format_status(Config) -> {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), Status = sys:get_status(Pid), @@ -1550,8 +1559,8 @@ wrap_result(Result) -> -code_change(_OldVsn, State, Data, _Extra) -> - {ok,State,Data}. +code_change(OldVsn, State, Data, Extra) -> + {ok,State,{OldVsn,Data,Extra}}. format_status(terminate, [_Pdict,State,Data]) -> {formatted,State,Data}; -- cgit v1.2.3 From 9db6054d674969fef314bf8676b6f9b583af3bef Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 12 Apr 2016 14:30:02 +0200 Subject: Fix missing short forms for event timeout --- lib/stdlib/test/gen_statem_SUITE.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 573a64bbb7..27fb7d9650 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -1305,10 +1305,10 @@ terminate(_Reason, _State, _Data) -> idle(cast, {connect,Pid}, Data) -> Pid ! accept, - {next_state,wfor_conf,Data}; + {next_state,wfor_conf,Data,infinity}; % NoOp timeout just to test API idle({call,From}, connect, Data) -> gen_statem:reply(From, accept), - {next_state,wfor_conf,Data}; + {next_state,wfor_conf,Data,infinity}; % NoOp timeout just to test API idle(cast, badreturn, _Data) -> badreturn; idle({call,_From}, badreturn, _Data) -> @@ -1343,13 +1343,15 @@ idle(Type, Content, Data) -> timeout(timeout, idle, {From,Time}) -> TRef = erlang:start_timer(Time, self(), ok), + {keep_state,{From,TRef},0}; % Immediate timeout 0 +timeout(timeout, 0, {From,TRef}) -> {next_state,timeout2,{From,TRef}, [{timeout,1,should_be_cancelled}, postpone]}; % Should cancel state timeout timeout(_, _, _) -> keep_state_and_data. -timeout2(timeout, idle, _) -> +timeout2(timeout, 0, _) -> keep_state_and_data; timeout2(timeout, Reason, _) -> {stop,Reason}; -- cgit v1.2.3 From 26b3c7d60d52d8a7be006b06d856bb0f7276e77a Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Thu, 21 Apr 2016 15:58:52 +0200 Subject: Modify code_change/4 to return CallbackMode Also move check of non-atom states in callback mode state_functions to where the state function is called. This gives homogenous diagnostics for state functions, code_change/4 and system_replace_state StateFun. Irregularities pointed out by James Fish. --- lib/stdlib/test/gen_statem_SUITE.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/stdlib/test') diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index 27fb7d9650..3deb5fd986 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -637,9 +637,9 @@ code_change(Config) -> {ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []), {idle,data} = sys:get_state(Pid), sys:suspend(Pid), - sys:change_code(Pid, ?MODULE, old_vsn, extra), + sys:change_code(Pid, ?MODULE, old_vsn, state_functions), sys:resume(Pid), - {idle,{old_vsn,data,extra}} = sys:get_state(Pid), + {idle,{old_vsn,data,state_functions}} = sys:get_state(Pid), stop_it(Pid). call_format_status(Config) -> @@ -1561,8 +1561,8 @@ wrap_result(Result) -> -code_change(OldVsn, State, Data, Extra) -> - {ok,State,{OldVsn,Data,Extra}}. +code_change(OldVsn, State, Data, CallbackMode) -> + {CallbackMode,State,{OldVsn,Data,CallbackMode}}. format_status(terminate, [_Pdict,State,Data]) -> {formatted,State,Data}; -- cgit v1.2.3