1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(sys_SUITE).
21-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
22	 init_per_group/2,end_per_group/2,log/1,log_to_file/1,
23	 stats/1,trace/1,suspend/1,install/1,special_process/1]).
24-export([handle_call/3,terminate/2,init/1]).
25-include_lib("common_test/include/ct.hrl").
26
27-define(server,sys_SUITE_server).
28
29
30%% Doesn't look into change_code at all
31
32
33suite() -> [{ct_hooks,[ts_install_cth]}].
34
35all() ->
36    [log, log_to_file, stats, trace, suspend, install, special_process].
37
38groups() ->
39    [].
40
41init_per_suite(Config) ->
42    Config.
43
44end_per_suite(_Config) ->
45    ok.
46
47init_per_group(_GroupName, Config) ->
48    Config.
49
50end_per_group(_GroupName, Config) ->
51    Config.
52
53
54%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55
56log(Config) when is_list(Config) ->
57    {ok,_Server} = start(),
58    ok = sys:log(?server,true),
59    {ok,-44} = public_call(44),
60    ok = sys:log(?server,false),
61    ok = sys:log(?server,print),
62    stop(),
63    ok.
64
65log_to_file(Config) when is_list(Config) ->
66    TempName = test_server:temp_name(proplists:get_value(priv_dir,Config) ++ "sys."),
67    {ok,_Server} = start(),
68    ok = sys:log_to_file(?server,TempName),
69    {ok,-44} = public_call(44),
70    ok = sys:log_to_file(?server,false),
71    {ok,Fd} = file:open(TempName,[read]),
72    Msg1 = io:get_line(Fd,''),
73    Msg2 = io:get_line(Fd,''),
74    file:close(Fd),
75    "*DBG* sys_SUITE_server got call {req,44} from " ++ _ = Msg1,
76    "*DBG* sys_SUITE_server sent {ok,-44} to " ++ _ = Msg2,
77    stop(),
78    ok.
79
80stats(Config) when is_list(Config) ->
81    Self = self(),
82    {ok,_Server} = start(),
83    ok = sys:statistics(?server,true),
84    {ok,-44} = public_call(44),
85    {ok,Stats} = sys:statistics(?server,get),
86    true = lists:member({messages_in,1}, Stats),
87    true = lists:member({messages_out,1}, Stats),
88    ok = sys:statistics(?server,false),
89    {status,_Pid,{module,_Mod},[_PDict,running,Self,_,_]} =
90	sys:get_status(?server),
91    {ok,no_statistics} = sys:statistics(?server,get),
92    stop(),
93    ok.
94
95trace(Config) when is_list(Config) ->
96    {ok,_Server} = start(),
97    ct:sleep(2000),
98    ct:capture_start(),
99    sys:trace(?server,true),
100    {ok,-44} = public_call(44),
101    %% ho, hum, allow for the io to reach us..
102    ct:sleep(1000),
103    ct:capture_stop(),
104    [Msg1,Msg2] = ct:capture_get(),
105    "*DBG* sys_SUITE_server got call {req,44} from " ++ _ = Msg1,
106    "*DBG* sys_SUITE_server sent {ok,-44} to " ++ _ = Msg2,
107    stop(),
108    ok.
109
110suspend(Config) when is_list(Config) ->
111    {ok,_Server} = start(),
112    sys:suspend(?server,1000),
113    {'EXIT',_} = (catch public_call(48)),
114    {status,_,_,[_,suspended,_,_,_]} = sys:get_status(?server),
115    sys:suspend(?server,1000), %% doing it twice is no error
116    {'EXIT',_} = (catch public_call(48)),
117    sys:resume(?server),
118    {status,_,_,[_,running,_,_,_]} = sys:get_status(?server),
119    {ok,-48} = (catch public_call(48)),
120    sys:resume(?server), %% doing it twice is no error
121    {ok,-48} = (catch public_call(48)),
122    stop(),
123    ok.
124
125install(Config) when is_list(Config) ->
126    {ok,_Server} = start(),
127    Master = self(),
128    SpyFun =
129	fun(func_state,Event,ProcState) ->
130		case Event of
131		    {in,{'$gen_call',_From,{req,Arg}}} ->
132			io:format("Trigged\n"),
133			Master ! {spy_got,{request,Arg},ProcState};
134		    Other ->
135			io:format("Trigged other=~p\n",[Other])
136		end,
137                func_state
138	end,
139    sys:install(?server,{SpyFun,func_state}),
140    {ok,-1} = (catch public_call(1)),
141    sys:no_debug(?server),
142    {ok,-2} = (catch public_call(2)),
143    sys:install(?server,{SpyFun,func_state}),
144    sys:install(?server,{SpyFun,func_state}),
145    {ok,-3} = (catch public_call(3)),
146    {ok,-4} = (catch public_call(4)),
147    sys:remove(?server,SpyFun),
148    {ok,-5} = (catch public_call(5)),
149    [{spy_got,{request,1},sys_SUITE_server},
150     {spy_got,{request,3},sys_SUITE_server},
151     {spy_got,{request,4},sys_SUITE_server}] = get_messages(),
152
153    sys:install(?server,{id1, SpyFun, func_state}),
154    sys:install(?server,{id1, SpyFun, func_state}), %% should not be installed
155    sys:install(?server,{id2, SpyFun, func_state}),
156    {ok,-1} = (catch public_call(1)),
157    %% We have two SpyFun installed:
158    [{spy_got,{request,1},sys_SUITE_server},
159     {spy_got,{request,1},sys_SUITE_server}] = get_messages(),
160    sys:remove(?server, id1),
161    {ok,-1} = (catch public_call(1)),
162    %% We have one SpyFun installed:
163    [{spy_got,{request,1},sys_SUITE_server}] = get_messages(),
164    sys:no_debug(?server),
165    {ok,-1} = (catch public_call(1)),
166    [] = get_messages(),
167    stop(),
168    ok.
169
170get_messages() ->
171    receive
172	Msg -> [Msg|get_messages()]
173    after 1 -> []
174    end.
175
176special_process(Config) when is_list(Config) ->
177    ok = spec_proc(sys_sp1),
178    ok = spec_proc(sys_sp2).
179
180spec_proc(Mod) ->
181    {ok,_} = Mod:start_link(100),
182    ok = sys:statistics(Mod,true),
183    ok = sys:trace(Mod,true),
184    1 = Ch = Mod:alloc(),
185    Free = lists:seq(2,100),
186    Replace = case sys:get_state(Mod) of
187		  {[Ch],Free} ->
188		      fun({A,F}) ->
189			      Free = F,
190			      {A,[2,3,4]}
191		      end;
192		  {state,[Ch],Free} ->
193		      fun({state,A,F}) ->
194			      Free = F,
195			      {state,A,[2,3,4]}
196		      end
197	      end,
198    case sys:replace_state(Mod, Replace) of
199	{[Ch],[2,3,4]} -> ok;
200	{state,[Ch],[2,3,4]} -> ok
201    end,
202    ok = Mod:free(Ch),
203    case sys:get_state(Mod) of
204	{[],[1,2,3,4]} -> ok;
205	{state,[],[1,2,3,4]} -> ok
206    end,
207    {ok,[{start_time,_},
208	 {current_time,_},
209	 {reductions,_},
210	 {messages_in,2},
211	 {messages_out,1}]} = sys:statistics(Mod,get),
212    ok = sys:statistics(Mod,false),
213    [] = sys:replace_state(Mod, fun(_) -> [] end),
214    process_flag(trap_exit,true),
215    ok = case catch sys:get_state(Mod) of
216	     [] ->
217		 ok;
218	     {'EXIT',{{callback_failed,
219		       {Mod,system_get_state},{throw,fail}},_}} ->
220		 ok
221	 end,
222    ok = sync_terminate(Mod),
223    {ok,_} = Mod:start_link(4),
224    ok = case catch sys:replace_state(Mod, fun(_) -> {} end) of
225	     {} ->
226		 ok;
227	     {'EXIT',{{callback_failed,
228		       {Mod,system_replace_state},{throw,fail}},_}} ->
229		 ok
230	 end,
231    ok = sync_terminate(Mod),
232    {ok,_} = Mod:start_link(4),
233    StateFun = fun(_) -> error(fail) end,
234    ok = case catch sys:replace_state(Mod, StateFun) of
235	     {} ->
236		 ok;
237	     {'EXIT',{{callback_failed,
238		       {Mod,system_replace_state},{error,fail}},_}} ->
239		 ok;
240	     {'EXIT',{{callback_failed,StateFun,{error,fail}},_}} ->
241		 ok
242	 end,
243    ok = sync_terminate(Mod).
244
245sync_terminate(Mod) ->
246    P = whereis(Mod),
247    MRef = erlang:monitor(process,P),
248    ok = sys:terminate(Mod, normal),
249    receive
250        {'DOWN',MRef,_,_,normal} ->
251            ok
252    end,
253    undefined = whereis(Mod),
254    ok.
255
256%%%%%%%%%%%%%%%%%%%%
257%% Dummy server
258
259public_call(Arg) ->
260    gen_server:call(?server,{req,Arg},1000).
261
262start() ->
263    gen_server:start_link({local,?server},?MODULE,[],[]).
264
265stop() ->
266    gen_server:call(?server,stop,1000).
267
268init([]) ->
269    {ok,0}.
270
271handle_call({req,Arg},_From,State) ->
272    NewState = State+1,
273    {reply,{ok,-Arg},NewState};
274handle_call(stop,_From,State) ->
275    {stop,normal,ok,State}.
276
277terminate(_Reason, _State) ->
278    ok.
279
280%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
281