%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-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(sys_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,log/1,log_to_file/1,
stats/1,trace/1,suspend/1,install/1,special_process/1]).
-export([handle_call/3,terminate/2,init/1]).
-include_lib("common_test/include/ct.hrl").
-define(server,sys_SUITE_server).
%% Doesn't look into change_code at all
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[log, log_to_file, stats, trace, suspend, install, special_process].
groups() ->
[].
init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
Config.
end_per_group(_GroupName, Config) ->
Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
log(Config) when is_list(Config) ->
{ok,_Server} = start(),
ok = sys:log(?server,true),
{ok,-44} = public_call(44),
ok = sys:log(?server,false),
ok = sys:log(?server,print),
stop(),
ok.
log_to_file(Config) when is_list(Config) ->
TempName = test_server:temp_name(proplists:get_value(priv_dir,Config) ++ "sys."),
{ok,_Server} = start(),
ok = sys:log_to_file(?server,TempName),
{ok,-44} = public_call(44),
ok = sys:log_to_file(?server,false),
{ok,Fd} = file:open(TempName,[read]),
Msg1 = io:get_line(Fd,''),
Msg2 = io:get_line(Fd,''),
file:close(Fd),
"*DBG* sys_SUITE_server got call {req,44} from " ++ _ = Msg1,
"*DBG* sys_SUITE_server sent {ok,-44} to " ++ _ = Msg2,
stop(),
ok.
stats(Config) when is_list(Config) ->
Self = self(),
{ok,_Server} = start(),
ok = sys:statistics(?server,true),
{ok,-44} = public_call(44),
{ok,Stats} = sys:statistics(?server,get),
true = lists:member({messages_in,1}, Stats),
true = lists:member({messages_out,1}, Stats),
ok = sys:statistics(?server,false),
{status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} =
sys:get_status(?server),
{ok,no_statistics} = sys:statistics(?server,get),
stop(),
ok.
trace(Config) when is_list(Config) ->
{ok,_Server} = start(),
ct:sleep(2000),
ct:capture_start(),
sys:trace(?server,true),
{ok,-44} = public_call(44),
%% ho, hum, allow for the io to reach us..
ct:sleep(1000),
ct:capture_stop(),
[Msg1,Msg2] = ct:capture_get(),
"*DBG* sys_SUITE_server got call {req,44} from " ++ _ = Msg1,
"*DBG* sys_SUITE_server sent {ok,-44} to " ++ _ = Msg2,
stop(),
ok.
suspend(Config) when is_list(Config) ->
{ok,_Server} = start(),
sys:suspend(?server,1000),
{'EXIT',_} = (catch public_call(48)),
{status,_,_,[_,suspended,_,_,_]} = sys:get_status(?server),
sys:suspend(?server,1000), %% doing it twice is no error
{'EXIT',_} = (catch public_call(48)),
sys:resume(?server),
{status,_,_,[_,running,_,_,_]} = sys:get_status(?server),
{ok,-48} = (catch public_call(48)),
sys:resume(?server), %% doing it twice is no error
{ok,-48} = (catch public_call(48)),
stop(),
ok.
install(Config) when is_list(Config) ->
{ok,_Server} = start(),
Master = self(),
SpyFun =
fun(func_state,Event,ProcState) ->
case Event of
{in,{'$gen_call',_From,{req,Arg}}} ->
io:format("Trigged\n"),
Master ! {spy_got,{request,Arg},ProcState};
Other ->
io:format("Trigged other=~p\n",[Other])
end,
func_state
end,
sys:install(?server,{SpyFun,func_state}),
{ok,-1} = (catch public_call(1)),
sys:no_debug(?server),
{ok,-2} = (catch public_call(2)),
sys:install(?server,{SpyFun,func_state}),
sys:install(?server,{SpyFun,func_state}),
{ok,-3} = (catch public_call(3)),
{ok,-4} = (catch public_call(4)),
sys:remove(?server,SpyFun),
{ok,-5} = (catch public_call(5)),
[{spy_got,{request,1},sys_SUITE_server},
{spy_got,{request,3},sys_SUITE_server},
{spy_got,{request,4},sys_SUITE_server}] = get_messages(),
sys:install(?server,{id1, SpyFun, func_state}),
sys:install(?server,{id1, SpyFun, func_state}), %% should not be installed
sys:install(?server,{id2, SpyFun, func_state}),
{ok,-1} = (catch public_call(1)),
%% We have two SpyFun installed:
[{spy_got,{request,1},sys_SUITE_server},
{spy_got,{request,1},sys_SUITE_server}] = get_messages(),
sys:remove(?server, id1),
{ok,-1} = (catch public_call(1)),
%% We have one SpyFun installed:
[{spy_got,{request,1},sys_SUITE_server}] = get_messages(),
sys:no_debug(?server),
{ok,-1} = (catch public_call(1)),
[] = get_messages(),
stop(),
ok.
get_messages() ->
receive
Msg -> [Msg|get_messages()]
after 1 -> []
end.
special_process(Config) when is_list(Config) ->
ok = spec_proc(sys_sp1),
ok = spec_proc(sys_sp2).
spec_proc(Mod) ->
{ok,_} = Mod:start_link(100),
ok = sys:statistics(Mod,true),
ok = sys:trace(Mod,true),
1 = Ch = Mod:alloc(),
Free = lists:seq(2,100),
Replace = case sys:get_state(Mod) of
{[Ch],Free} ->
fun({A,F}) ->
Free = F,
{A,[2,3,4]}
end;
{state,[Ch],Free} ->
fun({state,A,F}) ->
Free = F,
{state,A,[2,3,4]}
end
end,
case sys:replace_state(Mod, Replace) of
{[Ch],[2,3,4]} -> ok;
{state,[Ch],[2,3,4]} -> ok
end,
ok = Mod:free(Ch),
case sys:get_state(Mod) of
{[],[1,2,3,4]} -> ok;
{state,[],[1,2,3,4]} -> ok
end,
{ok,[{start_time,_},
{current_time,_},
{reductions,_},
{messages_in,2},
{messages_out,1}]} = sys:statistics(Mod,get),
ok = sys:statistics(Mod,false),
[] = sys:replace_state(Mod, fun(_) -> [] end),
process_flag(trap_exit,true),
ok = case catch sys:get_state(Mod) of
[] ->
ok;
{'EXIT',{{callback_failed,
{Mod,system_get_state},{throw,fail}},_}} ->
ok
end,
ok = sys:terminate(Mod, normal),
{ok,_} = Mod:start_link(4),
ok = case catch sys:replace_state(Mod, fun(_) -> {} end) of
{} ->
ok;
{'EXIT',{{callback_failed,
{Mod,system_replace_state},{throw,fail}},_}} ->
ok
end,
ok = sys:terminate(Mod, normal),
{ok,_} = Mod:start_link(4),
StateFun = fun(_) -> error(fail) end,
ok = case catch sys:replace_state(Mod, StateFun) of
{} ->
ok;
{'EXIT',{{callback_failed,
{Mod,system_replace_state},{error,fail}},_}} ->
ok;
{'EXIT',{{callback_failed,StateFun,{error,fail}},_}} ->
ok
end,
ok = sys:terminate(Mod, normal).
%%%%%%%%%%%%%%%%%%%%
%% Dummy server
public_call(Arg) ->
gen_server:call(?server,{req,Arg},1000).
start() ->
gen_server:start_link({local,?server},?MODULE,[],[]).
stop() ->
gen_server:call(?server,stop,1000).
init([]) ->
{ok,0}.
handle_call({req,Arg},_From,State) ->
NewState = State+1,
{reply,{ok,-Arg},NewState};
handle_call(stop,_From,State) ->
{stop,normal,ok,State}.
terminate(_Reason, _State) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%