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(gen_server_SUITE).
21
22-include_lib("common_test/include/ct.hrl").
23-include_lib("kernel/include/inet.hrl").
24
25-export([init_per_testcase/2, end_per_testcase/2]).
26
27-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
28	 init_per_group/2,end_per_group/2]).
29-export([start/1, crash/1, call/1, send_request/1, cast/1, cast_fast/1,
30	 continue/1, info/1, abcast/1, multicall/1, multicall_down/1,
31	 call_remote1/1, call_remote2/1, call_remote3/1,
32	 call_remote_n1/1, call_remote_n2/1, call_remote_n3/1, spec_init/1,
33	 spec_init_local_registered_parent/1,
34	 spec_init_global_registered_parent/1,
35	 otp_5854/1, hibernate/1, auto_hibernate/1, otp_7669/1, call_format_status/1,
36	 error_format_status/1, terminate_crash_format/1,
37	 get_state/1, replace_state/1, call_with_huge_message_queue/1,
38	 undef_handle_call/1, undef_handle_cast/1, undef_handle_info/1,
39	 undef_init/1, undef_code_change/1, undef_terminate1/1,
40	 undef_terminate2/1, undef_in_terminate/1, undef_in_handle_info/1,
41	 undef_handle_continue/1,
42
43         format_log_1/1, format_log_2/1,
44         reply_by_alias_with_payload/1
45	]).
46
47-export([stop1/1, stop2/1, stop3/1, stop4/1, stop5/1, stop6/1, stop7/1,
48	 stop8/1, stop9/1, stop10/1]).
49
50%% spawn export
51-export([spec_init_local/2, spec_init_global/2, spec_init_via/2,
52	 spec_init_default_timeout/2, spec_init_global_default_timeout/2,
53         spec_init_anonymous/1,
54	 spec_init_anonymous_default_timeout/1,
55	 spec_init_not_proc_lib/1, cast_fast_messup/0]).
56
57
58%% The gen_server behaviour
59-export([init/1, handle_call/3, handle_cast/2, handle_continue/2,
60	 handle_info/2, code_change/3, terminate/2, format_status/2]).
61
62suite() ->
63    [{ct_hooks,[ts_install_cth]},
64     {timetrap,{minutes,1}}].
65
66all() ->
67    [start, {group,stop}, crash, call, send_request, cast, cast_fast, info, abcast,
68     continue, multicall, multicall_down, call_remote1, call_remote2,
69     call_remote3, call_remote_n1, call_remote_n2,
70     call_remote_n3, spec_init,
71     spec_init_local_registered_parent,
72     spec_init_global_registered_parent, otp_5854, hibernate, auto_hibernate,
73     otp_7669,
74     call_format_status, error_format_status, terminate_crash_format,
75     get_state, replace_state,
76     call_with_huge_message_queue, {group, undef_callbacks},
77     undef_in_terminate, undef_in_handle_info,
78     format_log_1, format_log_2, reply_by_alias_with_payload].
79
80groups() ->
81    [{stop, [],
82      [stop1, stop2, stop3, stop4, stop5, stop6, stop7, stop8, stop9, stop10]},
83     {undef_callbacks, [],
84      [undef_handle_call, undef_handle_cast, undef_handle_info, undef_handle_continue,
85       undef_init, undef_code_change, undef_terminate1, undef_terminate2]}].
86
87
88init_per_suite(Config) ->
89    Config.
90
91end_per_suite(_Config) ->
92    ok.
93
94init_per_group(undef_callbacks, Config) ->
95    DataDir = ?config(data_dir, Config),
96    Server = filename:join(DataDir, "oc_server.erl"),
97    {ok, oc_server} = compile:file(Server),
98    Config;
99init_per_group(_GroupName, Config) ->
100    Config.
101
102end_per_group(_GroupName, Config) ->
103    Config.
104
105
106init_per_testcase(Case, Config) when Case == call_remote1;
107				     Case == call_remote2;
108				     Case == call_remote3;
109				     Case == call_remote_n1;
110				     Case == call_remote_n2;
111				     Case == call_remote_n3;
112                                     Case == send_request ->
113    {ok,N} = start_node(hubba),
114    [{node,N} | Config];
115
116init_per_testcase(_Case, Config) ->
117    Config.
118
119end_per_testcase(_Case, Config) ->
120    case proplists:get_value(node, Config) of
121	undefined ->
122	    ok;
123	N ->
124	    test_server:stop_node(N)
125    end,
126    ok.
127
128
129%% --------------------------------------
130%% Start and stop a gen_server.
131%% --------------------------------------
132
133start(Config) when is_list(Config) ->
134    OldFl = process_flag(trap_exit, true),
135
136    %% anonymous
137    {ok, Pid0} = gen_server:start(gen_server_SUITE, [], []),
138    ok = gen_server:call(Pid0, started_p),
139    ok = gen_server:call(Pid0, stop),
140    busy_wait_for_process(Pid0,600),
141    {'EXIT', {noproc,_}} = (catch gen_server:call(Pid0, started_p, 1)),
142
143    %% anonymous with timeout
144    {ok, Pid00} = gen_server:start(gen_server_SUITE, [],
145				   [{timeout,1000}]),
146    ok = gen_server:call(Pid00, started_p),
147    ok = gen_server:call(Pid00, stop),
148    {error, timeout} = gen_server:start(gen_server_SUITE, sleep,
149					[{timeout,100}]),
150
151    %% anonymous with ignore
152    ignore = gen_server:start(gen_server_SUITE, ignore, []),
153
154    %% anonymous with stop
155    {error, stopped} = gen_server:start(gen_server_SUITE, stop, []),
156
157    %% anonymous linked
158    {ok, Pid1} =
159	gen_server:start_link(gen_server_SUITE, [], []),
160    ok = gen_server:call(Pid1, started_p),
161    ok = gen_server:call(Pid1, stop),
162    receive
163	{'EXIT', Pid1, stopped} ->
164	    ok
165    after 5000 ->
166	    ct:fail(not_stopped)
167    end,
168
169    %% anonymous monitored
170    {ok, {Pid1b, Mon1b}} =
171	gen_server:start_monitor(gen_server_SUITE, [], []),
172    ok = gen_server:call(Pid1b, started_p),
173    ok = gen_server:call(Pid1b, stop),
174    receive
175	{'DOWN', Mon1b, process, Pid1b, stopped} ->
176	    ok
177    after 5000 ->
178	    ct:fail(not_stopped)
179    end,
180
181    %% local register
182    {ok, Pid2} =
183	gen_server:start({local, my_test_name},
184			 gen_server_SUITE, [], []),
185    ok = gen_server:call(my_test_name, started_p),
186    {error, {already_started, Pid2}} =
187	gen_server:start({local, my_test_name},
188			 gen_server_SUITE, [], []),
189    ok = gen_server:call(my_test_name, stop),
190
191    busy_wait_for_process(Pid2,600),
192
193    {'EXIT', {noproc,_}} = (catch gen_server:call(Pid2, started_p, 10)),
194
195    %% local register linked
196    {ok, Pid3} =
197	gen_server:start_link({local, my_test_name},
198			      gen_server_SUITE, [], []),
199    ok = gen_server:call(my_test_name, started_p),
200    {error, {already_started, Pid3}} =
201	gen_server:start({local, my_test_name},
202			 gen_server_SUITE, [], []),
203    ok = gen_server:call(my_test_name, stop),
204    receive
205	{'EXIT', Pid3, stopped} ->
206	    ok
207    after 5000 ->
208	    ct:fail(not_stopped)
209    end,
210
211    %% local register monitored
212    {ok, {Pid3b, Mon3b}} =
213	gen_server:start_monitor({local, my_test_name},
214                                 gen_server_SUITE, [], []),
215    ok = gen_server:call(my_test_name, started_p),
216    {error, {already_started, Pid3b}} =
217	gen_server:start_monitor({local, my_test_name},
218                                 gen_server_SUITE, [], []),
219    ok = gen_server:call(my_test_name, stop),
220    receive
221	{'DOWN', Mon3b, process, Pid3b, stopped} ->
222	    ok
223    after 5000 ->
224	    ct:fail(not_stopped)
225    end,
226
227    %% global register
228    {ok, Pid4} =
229	gen_server:start({global, my_test_name},
230			 gen_server_SUITE, [], []),
231    ok = gen_server:call({global, my_test_name}, started_p),
232    {error, {already_started, Pid4}} =
233	gen_server:start({global, my_test_name},
234			 gen_server_SUITE, [], []),
235    ok = gen_server:call({global, my_test_name}, stop),
236    busy_wait_for_process(Pid4,600),
237    {'EXIT', {noproc,_}} = (catch gen_server:call(Pid4, started_p, 10)),
238
239    %% global register linked
240    {ok, Pid5} =
241	gen_server:start_link({global, my_test_name},
242			      gen_server_SUITE, [], []),
243    ok = gen_server:call({global, my_test_name}, started_p),
244    {error, {already_started, Pid5}} =
245	gen_server:start({global, my_test_name},
246			 gen_server_SUITE, [], []),
247    ok = gen_server:call({global, my_test_name}, stop),
248    receive
249	{'EXIT', Pid5, stopped} ->
250	    ok
251    after 5000 ->
252	    ct:fail(not_stopped)
253    end,
254
255    %% global register monitored
256    {ok, {Pid5b, Mon5b}} =
257	gen_server:start_monitor({global, my_test_name},
258                                 gen_server_SUITE, [], []),
259    ok = gen_server:call({global, my_test_name}, started_p),
260    {error, {already_started, Pid5b}} =
261	gen_server:start_monitor({global, my_test_name},
262                                 gen_server_SUITE, [], []),
263    ok = gen_server:call({global, my_test_name}, stop),
264    receive
265	{'DOWN', Mon5b, process, Pid5b, stopped} ->
266	    ok
267    after 5000 ->
268	    ct:fail(not_stopped)
269    end,
270
271    %% via register
272    dummy_via:reset(),
273    {ok, Pid6} =
274	gen_server:start({via, dummy_via, my_test_name},
275			 gen_server_SUITE, [], []),
276    ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
277    {error, {already_started, Pid6}} =
278	gen_server:start({via, dummy_via, my_test_name},
279			 gen_server_SUITE, [], []),
280    ok = gen_server:call({via, dummy_via, my_test_name}, stop),
281    busy_wait_for_process(Pid6,600),
282    {'EXIT', {noproc,_}} = (catch gen_server:call(Pid6, started_p, 10)),
283
284    %% via register linked
285    dummy_via:reset(),
286    {ok, Pid7} =
287	gen_server:start_link({via, dummy_via, my_test_name},
288			      gen_server_SUITE, [], []),
289    ok = gen_server:call({via, dummy_via, my_test_name}, started_p),
290    {error, {already_started, Pid7}} =
291	gen_server:start({via, dummy_via, my_test_name},
292			 gen_server_SUITE, [], []),
293    ok = gen_server:call({via, dummy_via, my_test_name}, stop),
294    receive
295	{'EXIT', Pid7, stopped} ->
296	    ok
297    after 5000 ->
298	    ct:fail(not_stopped)
299    end,
300    receive
301	Msg -> ct:fail({unexpected,Msg})
302    after 1 -> ok
303    end,
304
305    process_flag(trap_exit, OldFl),
306    ok.
307
308%% Anonymous, reason 'normal'
309stop1(_Config) ->
310    {ok, Pid} = gen_server:start(?MODULE, [], []),
311    ok = gen_server:stop(Pid),
312    false = erlang:is_process_alive(Pid),
313    {'EXIT',noproc} = (catch gen_server:stop(Pid)),
314    ok.
315
316%% Anonymous, other reason
317stop2(_Config) ->
318    {ok,Pid} = gen_server:start(?MODULE, [], []),
319    ok = gen_server:stop(Pid, other_reason, infinity),
320    false = erlang:is_process_alive(Pid),
321    ok.
322
323%% Anonymous, invalid timeout
324stop3(_Config) ->
325    {ok,Pid} = gen_server:start(?MODULE, [], []),
326    {'EXIT',_} = (catch gen_server:stop(Pid, other_reason, invalid_timeout)),
327    true = erlang:is_process_alive(Pid),
328    ok = gen_server:stop(Pid),
329    false = erlang:is_process_alive(Pid),
330    ok.
331
332%% Registered name
333stop4(_Config) ->
334    {ok,Pid} = gen_server:start({local,to_stop},?MODULE, [], []),
335    ok = gen_server:stop(to_stop),
336    false = erlang:is_process_alive(Pid),
337    {'EXIT',noproc} = (catch gen_server:stop(to_stop)),
338    ok.
339
340%% Registered name and local node
341stop5(_Config) ->
342    {ok,Pid} = gen_server:start({local,to_stop},?MODULE, [], []),
343    ok = gen_server:stop({to_stop,node()}),
344    false = erlang:is_process_alive(Pid),
345    {'EXIT',noproc} = (catch gen_server:stop({to_stop,node()})),
346    ok.
347
348%% Globally registered name
349stop6(_Config) ->
350    {ok, Pid} = gen_server:start({global, to_stop}, ?MODULE, [], []),
351    ok = gen_server:stop({global,to_stop}),
352    false = erlang:is_process_alive(Pid),
353    {'EXIT',noproc} = (catch gen_server:stop({global,to_stop})),
354    ok.
355
356%% 'via' registered name
357stop7(_Config) ->
358    dummy_via:reset(),
359    {ok, Pid} = gen_server:start({via, dummy_via, to_stop},
360				 ?MODULE, [], []),
361    ok = gen_server:stop({via, dummy_via, to_stop}),
362    false = erlang:is_process_alive(Pid),
363    {'EXIT',noproc} = (catch gen_server:stop({via, dummy_via, to_stop})),
364    ok.
365
366%% Anonymous on remote node
367stop8(_Config) ->
368    {ok,Node} = test_server:start_node(gen_server_SUITE_stop8,slave,[]),
369    Dir = filename:dirname(code:which(?MODULE)),
370    rpc:call(Node,code,add_path,[Dir]),
371    {ok, Pid} = rpc:call(Node,gen_server,start,[?MODULE,[],[]]),
372    ok = gen_server:stop(Pid),
373    false = rpc:call(Node,erlang,is_process_alive,[Pid]),
374    {'EXIT',noproc} = (catch gen_server:stop(Pid)),
375    true = test_server:stop_node(Node),
376    {'EXIT',{{nodedown,Node},_}} = (catch gen_server:stop(Pid)),
377    ok.
378
379%% Registered name on remote node
380stop9(_Config) ->
381    {ok,Node} = test_server:start_node(gen_server_SUITE_stop9,slave,[]),
382    Dir = filename:dirname(code:which(?MODULE)),
383    rpc:call(Node,code,add_path,[Dir]),
384    {ok, Pid} = rpc:call(Node,gen_server,start,[{local,to_stop},?MODULE,[],[]]),
385    ok = gen_server:stop({to_stop,Node}),
386    undefined = rpc:call(Node,erlang,whereis,[to_stop]),
387    false = rpc:call(Node,erlang,is_process_alive,[Pid]),
388    {'EXIT',noproc} = (catch gen_server:stop({to_stop,Node})),
389    true = test_server:stop_node(Node),
390    {'EXIT',{{nodedown,Node},_}} = (catch gen_server:stop({to_stop,Node})),
391    ok.
392
393%% Globally registered name on remote node
394stop10(_Config) ->
395    {ok,Node} = test_server:start_node(gen_server_SUITE_stop10,slave,[]),
396    Dir = filename:dirname(code:which(?MODULE)),
397    rpc:call(Node,code,add_path,[Dir]),
398    {ok, Pid} = rpc:call(Node,gen_server,start,[{global,to_stop},?MODULE,[],[]]),
399    ok = global:sync(),
400    ok = gen_server:stop({global,to_stop}),
401    false = rpc:call(Node,erlang,is_process_alive,[Pid]),
402    {'EXIT',noproc} = (catch gen_server:stop({global,to_stop})),
403    true = test_server:stop_node(Node),
404    {'EXIT',noproc} = (catch gen_server:stop({global,to_stop})),
405    ok.
406
407crash(Config) when is_list(Config) ->
408    error_logger_forwarder:register(),
409
410    process_flag(trap_exit, true),
411
412    %% This crash should not generate a crash report.
413    {ok,Pid0} = gen_server:start_link(?MODULE, [], []),
414    {'EXIT',{{shutdown,reason},_}} =
415 	(catch gen_server:call(Pid0, shutdown_reason)),
416    receive {'EXIT',Pid0,{shutdown,reason}} -> ok end,
417
418    %% This crash should not generate a crash report.
419    {ok,Pid1} = gen_server:start_link(?MODULE, {state,state1}, []),
420    {'EXIT',{{shutdown,stop_reason},_}} =
421	(catch gen_server:call(Pid1, stop_shutdown_reason)),
422    receive {'EXIT',Pid1,{shutdown,stop_reason}} -> ok end,
423
424    %% This crash should not generate a crash report.
425    {ok,Pid2} = gen_server:start_link(?MODULE, [], []),
426    {'EXIT',{shutdown,_}} =
427 	(catch gen_server:call(Pid2, exit_shutdown)),
428    receive {'EXIT',Pid2,shutdown} -> ok end,
429
430    %% This crash should not generate a crash report.
431    {ok,Pid3} = gen_server:start_link(?MODULE, {state,state3}, []),
432    {'EXIT',{shutdown,_}} =
433	(catch gen_server:call(Pid3, stop_shutdown)),
434    receive {'EXIT',Pid3,shutdown} -> ok end,
435
436    process_flag(trap_exit, false),
437
438    %% This crash should generate a crash report and a report
439    %% from gen_server.
440    {ok,Pid4} = gen_server:start(?MODULE, {state,state4}, []),
441    {'EXIT',{crashed,_}} = (catch gen_server:call(Pid4, crash)),
442    ClientPid = self(),
443    receive
444	{error,_GroupLeader4,{Pid4,
445			      "** Generic server"++_,
446			      [Pid4,crash,{formatted, state4},
447			       {crashed,[{?MODULE,handle_call,3,_}
448					 |_Stacktrace]},
449			       ClientPid, [_|_] = _ClientStack]}} ->
450	    ok;
451	Other4a ->
452	    io:format("Unexpected: ~p", [Other4a]),
453	    ct:fail(failed)
454    end,
455    receive
456	{error_report,_,{Pid4,crash_report,[List4|_]}} ->
457	    {exit,crashed,[{?MODULE, handle_call, 3, _}|_]} = proplists:get_value(error_info, List4),
458	    Pid4 = proplists:get_value(pid, List4);
459	Other4 ->
460	    io:format("Unexpected: ~p", [Other4]),
461	    ct:fail(failed)
462    end,
463
464    receive
465	Any ->
466	    io:format("Unexpected: ~p", [Any]),
467	    ct:fail(failed)
468    after 500 ->
469	    ok
470    end,
471
472    ok.
473
474%% --------------------------------------
475%% Test gen_server:call and handle_call.
476%% Test all different return values from
477%% handle_call.
478%% --------------------------------------
479
480call(Config) when is_list(Config) ->
481    OldFl = process_flag(trap_exit, true),
482
483    {ok, _Pid} =
484	gen_server:start_link({local, my_test_name},
485			      gen_server_SUITE, [], []),
486
487    ok = gen_server:call(my_test_name, started_p),
488    delayed = gen_server:call(my_test_name, {delayed_answer,1}),
489
490    %% two requests within a specified time.
491    ok = gen_server:call(my_test_name, {call_within, 1000}),
492    timer:sleep(500),
493    ok = gen_server:call(my_test_name, next_call),
494    ok = gen_server:call(my_test_name, {call_within, 1000}),
495    timer:sleep(1500),
496    false = gen_server:call(my_test_name, next_call),
497
498    %% timeout call.
499    delayed = gen_server:call(my_test_name, {delayed_answer,1}, 30),
500    {'EXIT',{timeout,_}} =
501	(catch gen_server:call(my_test_name, {delayed_answer,30}, 1)),
502
503    %% bad return value in the gen_server loop from handle_call.
504    {'EXIT',{{bad_return_value, badreturn},_}} =
505	(catch gen_server:call(my_test_name, badreturn)),
506
507    process_flag(trap_exit, OldFl),
508    ok.
509
510%% --------------------------------------
511%% Test gen_server:send_request.
512%% --------------------------------------
513
514send_request(Config) when is_list(Config) ->
515    OldFl = process_flag(trap_exit, true),
516
517    {ok, Pid} = gen_server:start_link({local, my_test_name},
518                                      gen_server_SUITE, [], []),
519
520    Async = fun(Process, Req) ->
521                    try
522                        Promise = gen_server:send_request(Process, Req),
523                        gen_server:wait_response(Promise, infinity)
524                    catch _:Reason:ST ->
525                            {'did_exit', Reason, ST}
526                    end
527            end,
528    {reply,ok} = Async(my_test_name, started_p),
529
530    {reply,delayed} = Async(Pid, {delayed_answer,1}),
531
532    %% two requests within a specified time.
533    Promise1 = gen_server:send_request(my_test_name, {call_within, 1000}),
534    Promise2 = gen_server:send_request(my_test_name, next_call),
535    {reply, ok} = gen_server:wait_response(Promise1, infinity),
536    {reply, ok} = gen_server:wait_response(Promise2, infinity),
537
538    Promise3 = gen_server:send_request(my_test_name, {call_within, 1000}),
539    no_reply = gen_server:check_response({foo, bar}, Promise3),
540    receive {[alias|Ref],_} = Msg when is_reference(Ref) ->
541            {reply, ok} = gen_server:check_response(Msg, Promise3)
542    after 1000 ->
543            %% Format changed which is ok. This test is just to make you
544            %% aware that you have changed it
545            exit(message_format_changed)
546    end,
547    timer:sleep(1500),
548
549    {reply, false} = Async(my_test_name, next_call),
550
551    %% timeout
552    Promise5 = gen_server:send_request(my_test_name, {delayed_answer,50}),
553    timeout = gen_server:wait_response(Promise5, 0),
554    {reply, delayed} = gen_server:wait_response(Promise5, infinity),
555
556    %% bad return value in the gen_server loop from handle_call.
557    {error,{{bad_return_value, badreturn},_}} = Async(my_test_name, badreturn),
558
559    %% Test other error cases
560    {error, {noproc,_}} = Async(Pid, started_p),
561    {error, {noproc,_}} = Async(my_test_name, started_p),
562    {error, {noconnection, _}} = Async({my_test_name, foo@node}, started_p),
563
564    {error, {noproc,_}} = Async({global, non_existing}, started_p),
565    catch exit(whereis(dummy_via), foo),
566    {'EXIT', {badarg,_}} =
567        (catch gen_server:send_request({via, dummy_via, non_existing}, started_p)),
568
569    %% Remote nodes
570    Via = dummy_via:reset(),
571    Remote = proplists:get_value(node,Config),
572    {ok, RPid} = rpc:call(Remote, gen_server, start, [{global, remote}, ?MODULE, [], []]),
573    dummy_via:register_name(remote, RPid),
574    {reply, ok} = Async(RPid, started_p),
575    {reply, ok} = Async({global, remote}, started_p),
576    {reply, ok} = Async({via, dummy_via, remote}, started_p),
577    {error, {shutdown, _}} = Async({global, remote}, stop_shutdown),
578    {error, {noproc, _}} = Async({global, remote}, started_p),
579    {error, {noproc, _}} = Async({via, dummy_via, remote}, started_p),
580    {error, {noproc, _}} = Async({via, dummy_via, non_existing}, started_p),
581
582    {ok, _} = rpc:call(Remote, gen_server, start, [{local, remote}, ?MODULE, [], []]),
583    {reply, ok} = Async({remote, Remote}, started_p),
584    {error, {shutdown, _}} = Async({remote, Remote}, stop_shutdown),
585    {error, {noproc, _}} = Async({remote, Remote}, started_p),
586
587    %% Cleanup
588    catch exit(Via, foo2),
589    receive {'EXIT', Via, foo2} -> ok end,
590    process_flag(trap_exit, OldFl),
591    ok.
592
593
594%% --------------------------------------
595%% Test handle_continue.
596%% --------------------------------------
597
598continue(Config) when is_list(Config) ->
599    {ok, Pid} = gen_server:start_link(gen_server_SUITE, {continue, self()}, []),
600    [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
601
602    gen_server:call(Pid, {continue_reply, self()}),
603    [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
604
605    gen_server:call(Pid, {continue_noreply, self()}),
606    [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
607
608    gen_server:cast(Pid, {continue_noreply, self()}),
609    [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
610
611    Pid ! {continue_noreply, self()},
612    [{Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
613
614    Pid ! {continue_continue, self()},
615    [{Pid, before_continue}, {Pid, continue}, {Pid, after_continue}] = read_replies(Pid),
616
617    Ref = monitor(process, Pid),
618    Pid ! continue_stop,
619    verify_down_reason(Ref, Pid, normal).
620
621read_replies(Pid) ->
622    receive
623	{Pid, ack} -> read_replies()
624    after
625	1000 -> ct:fail({continue, ack})
626    end.
627
628read_replies() ->
629    receive
630	Msg -> [Msg | read_replies()]
631    after
632	0 -> []
633    end.
634
635%% --------------------------------------
636%% Test call to nonexisting processes on remote nodes
637%% --------------------------------------
638
639start_node(Name) ->
640    Pa = filename:dirname(code:which(?MODULE)),
641    N = test_server:start_node(Name, slave, [{args, " -pa " ++ Pa}]),
642    %% After starting a slave, it takes a little while until global knows
643    %% about it, even if nodes() includes it, so we make sure that global
644    %% knows about it before registering something on all nodes.
645    ok = global:sync(),
646    N.
647
648call_remote1(Config) when is_list(Config) ->
649    N = hubba,
650    Node = proplists:get_value(node,Config),
651    {ok, Pid} = rpc:call(Node, gen_server, start,
652			 [{global, N}, ?MODULE, [], []]),
653    ok = (catch gen_server:call({global, N}, started_p, infinity)),
654    exit(Pid, boom),
655    {'EXIT', {Reason, _}} = (catch gen_server:call({global, N},
656						   started_p, infinity)),
657    true = (Reason == noproc) orelse (Reason == boom),
658    ok.
659
660call_remote2(Config) when is_list(Config) ->
661    N = hubba,
662    Node = proplists:get_value(node,Config),
663
664    {ok, Pid} = rpc:call(Node, gen_server, start,
665			 [{global, N}, ?MODULE, [], []]),
666    ok = (catch gen_server:call(Pid, started_p, infinity)),
667    exit(Pid, boom),
668    {'EXIT', {Reason, _}} = (catch gen_server:call(Pid,
669						   started_p, infinity)),
670    true = (Reason == noproc) orelse (Reason == boom),
671    ok.
672
673call_remote3(Config) when is_list(Config) ->
674    Node = proplists:get_value(node,Config),
675
676    {ok, Pid} = rpc:call(Node, gen_server, start,
677			 [{local, piller}, ?MODULE, [], []]),
678    ok = (catch gen_server:call({piller, Node}, started_p, infinity)),
679    exit(Pid, boom),
680    {'EXIT', {Reason, _}} = (catch gen_server:call({piller, Node},
681						   started_p, infinity)),
682    true = (Reason == noproc) orelse (Reason == boom),
683    ok.
684
685%% --------------------------------------
686%% Test call to nonexisting node
687%% --------------------------------------
688
689call_remote_n1(Config) when is_list(Config) ->
690    N = hubba,
691    Node = proplists:get_value(node,Config),
692    {ok, _Pid} = rpc:call(Node, gen_server, start,
693			  [{global, N}, ?MODULE, [], []]),
694    _ = test_server:stop_node(Node),
695    {'EXIT', {noproc, _}} =
696	(catch gen_server:call({global, N}, started_p, infinity)),
697
698    ok.
699
700call_remote_n2(Config) when is_list(Config) ->
701    N = hubba,
702    Node = proplists:get_value(node,Config),
703
704    {ok, Pid} = rpc:call(Node, gen_server, start,
705			 [{global, N}, ?MODULE, [], []]),
706    _ = test_server:stop_node(Node),
707    {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call(Pid,
708							     started_p, infinity)),
709
710    ok.
711
712call_remote_n3(Config) when is_list(Config) ->
713    Node = proplists:get_value(node,Config),
714
715    {ok, _Pid} = rpc:call(Node, gen_server, start,
716			  [{local, piller}, ?MODULE, [], []]),
717    _ = test_server:stop_node(Node),
718    {'EXIT', {{nodedown, Node}, _}} = (catch gen_server:call({piller, Node},
719							     started_p, infinity)),
720
721    ok.
722
723%% --------------------------------------
724%% Test gen_server:cast and handle_cast.
725%% Test all different return values from
726%% handle_cast.
727%% --------------------------------------
728
729cast(Config) when is_list(Config) ->
730    {ok, Pid} =
731	gen_server:start({local, my_test_name},
732			 gen_server_SUITE, [], []),
733
734    ok = gen_server:call(my_test_name, started_p),
735
736    ok = gen_server:cast(my_test_name, {self(),handle_cast}),
737    receive
738	{Pid, handled_cast} ->
739	    ok
740    after 1000 ->
741	    ct:fail(handle_cast)
742    end,
743
744    ok = gen_server:cast(my_test_name, {self(),delayed_cast,1}),
745    receive
746	{Pid, delayed} ->
747	    ok
748    after 1000 ->
749	    ct:fail(delayed_cast)
750    end,
751
752    ok = gen_server:cast(my_test_name, {self(),stop}),
753    receive
754	{Pid, stopped} ->
755	    ok
756    after 1000 ->
757	    ct:fail(stop)
758    end,
759    ok.
760
761%% Test that cast really return immediately.
762cast_fast(Config) when is_list(Config) ->
763    {ok,Node} = start_node(hubba),
764    {_,"@"++Host} = lists:splitwith(fun ($@) -> false; (_) -> true end,
765				    atom_to_list(Node)),
766    FalseNode = list_to_atom("hopp@"++Host),
767    true = rpc:cast(Node, ?MODULE, cast_fast_messup, []),
768    ct:sleep(1000),
769    [Node] = nodes(),
770    {Time,ok} = timer:tc(fun() ->
771				 gen_server:cast({hopp,FalseNode}, hopp)
772			 end),
773    true = test_server:stop_node(Node),
774    if Time > 1000000 ->       % Default listen timeout is about 7.0 s
775	    ct:fail(hanging_cast);
776       true ->
777	    ok
778    end.
779
780cast_fast_messup() ->
781    %% Register a false node: hopp@hostname
782    unregister(erl_epmd),
783    {ok, _} = erl_epmd:start_link(),
784    {ok,S} = gen_tcp:listen(0, []),
785    {ok,P} = inet:port(S),
786    {ok,_Creation} = erl_epmd:register_node(hopp, P),
787    receive after infinity -> ok end.
788
789%% --------------------------------------
790%% Test handle_info.
791%% --------------------------------------
792
793info(Config) when is_list(Config) ->
794    {ok, Pid} =
795	gen_server:start({local, my_test_name},
796			 gen_server_SUITE, [], []),
797
798    ok = gen_server:call(my_test_name, started_p),
799
800    Pid ! {self(),handle_info},
801    receive
802	{Pid, handled_info} ->
803	    ok
804    after 1000 ->
805	    ct:fail(handle_info)
806    end,
807
808    Pid ! {self(),delayed_info,1},
809    receive
810	{Pid, delayed_info} ->
811	    ok
812    after 1000 ->
813	    ct:fail(delayed_info)
814    end,
815
816    Pid ! {self(),stop},
817    receive
818	{Pid, stopped_info} ->
819	    ok
820    after 1000 ->
821	    ct:fail(stop_info)
822    end,
823    ok.
824
825hibernate(Config) when is_list(Config) ->
826    OldFl = process_flag(trap_exit, true),
827    {ok, Pid0} =
828	gen_server:start_link({local, my_test_name_hibernate0},
829			      gen_server_SUITE, hibernate, []),
830    is_in_erlang_hibernate(Pid0),
831    ok = gen_server:call(my_test_name_hibernate0, stop),
832    receive
833	{'EXIT', Pid0, stopped} ->
834 	    ok
835    after 5000 ->
836	    ct:fail(gen_server_did_not_die)
837    end,
838
839    {ok, Pid} =
840	gen_server:start_link({local, my_test_name_hibernate},
841			      gen_server_SUITE, [], []),
842
843    ok = gen_server:call(my_test_name_hibernate, started_p),
844    true = gen_server:call(my_test_name_hibernate, hibernate),
845    is_in_erlang_hibernate(Pid),
846    Parent = self(),
847    Fun = fun() ->
848		  receive go -> ok end,
849		  receive after 1000 -> ok end,
850		  X = erlang:process_info(Pid, current_function),
851 		  Pid ! continue,
852 		  Parent ! {result,X}
853 	  end,
854    Pid2 = spawn_link(Fun),
855    true = gen_server:call(my_test_name_hibernate, {hibernate_noreply,Pid2}),
856
857    gen_server:cast(my_test_name_hibernate, hibernate_later),
858    true = ({current_function,{erlang,hibernate,3}} =/=
859		erlang:process_info(Pid, current_function)),
860    is_in_erlang_hibernate(Pid),
861    ok = gen_server:call(my_test_name_hibernate, started_p),
862    true = ({current_function,{erlang,hibernate,3}} =/=
863		erlang:process_info(Pid, current_function)),
864
865    gen_server:cast(my_test_name_hibernate, hibernate_now),
866    is_in_erlang_hibernate(Pid),
867    ok = gen_server:call(my_test_name_hibernate, started_p),
868    true = ({current_function,{erlang,hibernate,3}} =/=
869		erlang:process_info(Pid, current_function)),
870
871    Pid ! hibernate_later,
872    true = ({current_function,{erlang,hibernate,3}} =/=
873		erlang:process_info(Pid, current_function)),
874    is_in_erlang_hibernate(Pid),
875    ok = gen_server:call(my_test_name_hibernate, started_p),
876    true = ({current_function,{erlang,hibernate,3}} =/=
877		erlang:process_info(Pid, current_function)),
878
879    Pid ! hibernate_now,
880    is_in_erlang_hibernate(Pid),
881    ok = gen_server:call(my_test_name_hibernate, started_p),
882    true = ({current_function,{erlang,hibernate,3}} =/=
883		erlang:process_info(Pid, current_function)),
884    receive
885	{result,R} ->
886	    {current_function,{erlang,hibernate,3}} = R
887    end,
888
889    true = gen_server:call(my_test_name_hibernate, hibernate),
890    is_in_erlang_hibernate(Pid),
891    sys:suspend(my_test_name_hibernate),
892    is_in_erlang_hibernate(Pid),
893    sys:resume(my_test_name_hibernate),
894    is_in_erlang_hibernate(Pid),
895    ok = gen_server:call(my_test_name_hibernate, started_p),
896    true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)),
897
898    ok = gen_server:call(my_test_name_hibernate, stop),
899    receive
900	{'EXIT', Pid, stopped} ->
901 	    ok
902    after 5000 ->
903	    ct:fail(gen_server_did_not_die)
904    end,
905    process_flag(trap_exit, OldFl),
906    ok.
907
908auto_hibernate(Config) when is_list(Config) ->
909    OldFl = process_flag(trap_exit, true),
910    HibernateAfterTimeout = 100,
911    State = {auto_hibernate_state},
912    {ok, Pid} =
913        gen_server:start_link({local, my_test_name_auto_hibernate},
914            gen_server_SUITE, {state,State}, [{hibernate_after, HibernateAfterTimeout}]),
915    %% After init test
916    is_not_in_erlang_hibernate(Pid),
917    timer:sleep(HibernateAfterTimeout),
918    is_in_erlang_hibernate(Pid),
919    %% Get state test
920    State = sys:get_state(my_test_name_auto_hibernate),
921    is_in_erlang_hibernate(Pid),
922    %% Call test
923    ok = gen_server:call(my_test_name_auto_hibernate, started_p),
924    is_not_in_erlang_hibernate(Pid),
925    timer:sleep(HibernateAfterTimeout),
926    is_in_erlang_hibernate(Pid),
927    %% Cast test
928    ok = gen_server:cast(my_test_name_auto_hibernate, {self(),handle_cast}),
929    receive
930        {Pid, handled_cast} ->
931            ok
932    after 1000 ->
933        ct:fail(cast)
934    end,
935    is_not_in_erlang_hibernate(Pid),
936    timer:sleep(HibernateAfterTimeout),
937    is_in_erlang_hibernate(Pid),
938    %% Info test
939    Pid ! {self(),handle_info},
940    receive
941        {Pid, handled_info} ->
942            ok
943    after 1000 ->
944        ct:fail(info)
945    end,
946    is_not_in_erlang_hibernate(Pid),
947    timer:sleep(HibernateAfterTimeout),
948    is_in_erlang_hibernate(Pid),
949
950    ok = gen_server:call(my_test_name_auto_hibernate, stop),
951    receive
952        {'EXIT', Pid, stopped} ->
953            ok
954    after 5000 ->
955        ct:fail(gen_server_did_not_die)
956    end,
957    process_flag(trap_exit, OldFl),
958    ok.
959
960is_in_erlang_hibernate(Pid) ->
961    receive after 1 -> ok end,
962    is_in_erlang_hibernate_1(200, Pid).
963
964is_in_erlang_hibernate_1(0, Pid) ->
965    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
966    ct:fail(not_in_erlang_hibernate_3);
967is_in_erlang_hibernate_1(N, Pid) ->
968    {current_function,MFA} = erlang:process_info(Pid, current_function),
969    case MFA of
970	{erlang,hibernate,3} ->
971	    ok;
972	_ ->
973	    receive after 10 -> ok end,
974	    is_in_erlang_hibernate_1(N-1, Pid)
975    end.
976
977is_not_in_erlang_hibernate(Pid) ->
978    receive after 1 -> ok end,
979    is_not_in_erlang_hibernate_1(200, Pid).
980
981is_not_in_erlang_hibernate_1(0, Pid) ->
982    io:format("~p\n", [erlang:process_info(Pid, current_function)]),
983    ct:fail(not_in_erlang_hibernate_3);
984is_not_in_erlang_hibernate_1(N, Pid) ->
985    {current_function,MFA} = erlang:process_info(Pid, current_function),
986    case MFA of
987        {erlang,hibernate,3} ->
988            receive after 10 -> ok end,
989            is_not_in_erlang_hibernate_1(N-1, Pid);
990        _ ->
991            ok
992    end.
993
994%% --------------------------------------
995%% Test gen_server:abcast and handle_cast.
996%% Test all different return values from
997%% handle_cast.
998%% --------------------------------------
999
1000abcast(Config) when is_list(Config) ->
1001    {ok, Pid} =
1002	gen_server:start({local, my_test_name},
1003			 gen_server_SUITE, [], []),
1004
1005    ok = gen_server:call(my_test_name, started_p),
1006
1007    abcast = gen_server:abcast(my_test_name, {self(),handle_cast}),
1008    receive
1009	{Pid, handled_cast} ->
1010	    ok
1011    after 1000 ->
1012	    ct:fail(abcast)
1013    end,
1014
1015    abcast = gen_server:abcast([node()], my_test_name,
1016			       {self(),delayed_cast,1}),
1017    receive
1018	{Pid, delayed} ->
1019	    ok
1020    after 1000 ->
1021	    ct:fail(delayed_abcast)
1022    end,
1023
1024    abcast = gen_server:abcast(my_test_name, {self(),stop}),
1025    receive
1026	{Pid, stopped} ->
1027	    ok
1028    after 1000 ->
1029	    ct:fail(abcast_stop)
1030    end,
1031    ok.
1032
1033%% --------------------------------------
1034%% Test gen_server:multicall and handle_call.
1035%% Test all different return values from
1036%% handle_call.
1037%% --------------------------------------
1038
1039multicall(Config) when is_list(Config) ->
1040    OldFl = process_flag(trap_exit, true),
1041
1042    {ok, Pid} =
1043	gen_server:start_link({local, my_test_name},
1044			      gen_server_SUITE, [], []),
1045
1046    ok = gen_server:call(my_test_name, started_p),
1047    Nodes = nodes(),
1048    Node = node(),
1049    {[{Node,delayed}],Nodes} =
1050	gen_server:multi_call(my_test_name, {delayed_answer,1}),
1051
1052    %% two requests within a specified time.
1053    {[{Node,ok}],[]} =
1054	gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
1055    timer:sleep(500),
1056    {[{Node,ok}],[]} =
1057	gen_server:multi_call([Node], my_test_name, next_call),
1058    {[{Node,ok}],[]} =
1059	gen_server:multi_call([Node], my_test_name, {call_within, 1000}),
1060    timer:sleep(1500),
1061    {[{Node,false}],[]} =
1062	gen_server:multi_call([Node],my_test_name, next_call),
1063
1064    %% Stop the server.
1065    {[{Node,ok}],[]} =
1066	gen_server:multi_call([Node],my_test_name, stop),
1067    receive
1068	{'EXIT', Pid, stopped} -> ok
1069    after 1000 ->
1070	    ct:fail(multicall_stop)
1071    end,
1072
1073    process_flag(trap_exit, OldFl),
1074
1075    ok.
1076
1077%% OTP-3587
1078multicall_down(Config) when is_list(Config) ->
1079    %% We need a named host which is inaccessible.
1080    Name = node@test01,
1081
1082    %% We use 'global' as a gen_server to call.
1083    {Good, Bad} = gen_server:multi_call([Name, node()],
1084					global_name_server,
1085					info,
1086					3000),
1087    io:format("good = ~p, bad = ~p~n", [Good, Bad]),
1088    [Name] = Bad,
1089    ok.
1090
1091busy_wait_for_process(Pid,N) ->
1092    case erlang:is_process_alive(Pid) of
1093	true ->
1094	    receive
1095	    after 100 ->
1096		    ok
1097	    end,
1098	    busy_wait_for_process(Pid,N-1);
1099	_ ->
1100	    ok
1101    end.
1102%%--------------------------------------------------------------
1103%% Test gen_server:enter_loop/[3,4,5]. Used when you want to write
1104%% your own special init-phase.
1105spec_init(Config) when is_list(Config) ->
1106
1107    OldFlag = process_flag(trap_exit, true),
1108
1109    {ok, Pid0} = start_link(spec_init_local, [{ok, my_server}, []]),
1110    ok = gen_server:call(Pid0, started_p),
1111    ok = gen_server:call(Pid0, stop),
1112    receive
1113	{'EXIT', Pid0, stopped} ->
1114 	    ok
1115    after 5000 ->
1116	    ct:fail(gen_server_did_not_die)
1117    end,
1118
1119    {ok, Pid01} = start_link(spec_init_local, [{not_ok, my_server}, []]),
1120    receive
1121 	{'EXIT', Pid01, process_not_registered} ->
1122 	    ok
1123    after 5000 ->
1124	    ct:fail(gen_server_did_not_die)
1125    end,
1126
1127    {ok, Pid1} = start_link(spec_init_global, [{ok, my_server}, []]),
1128    ok = gen_server:call(Pid1, started_p),
1129    ok = gen_server:call(Pid1, stop),
1130    receive
1131	{'EXIT', Pid1, stopped} ->
1132 	    ok
1133    after 5000 ->
1134	    ct:fail(gen_server_did_not_die)
1135    end,
1136
1137    {ok, Pid11} =
1138	start_link(spec_init_global, [{not_ok, my_server}, []]),
1139
1140    receive
1141	{'EXIT', Pid11, process_not_registered_globally} ->
1142 	    ok
1143    after 5000 ->
1144	    ct:fail(gen_server_did_not_die)
1145    end,
1146
1147    {ok, Pid2} = start_link(spec_init_anonymous, [[]]),
1148    ok = gen_server:call(Pid2, started_p),
1149    ok = gen_server:call(Pid2, stop),
1150    receive
1151	{'EXIT', Pid2, stopped} ->
1152 	    ok
1153    after 5000 ->
1154	    ct:fail(gen_server_did_not_die)
1155    end,
1156
1157    {ok, Pid3} = start_link(spec_init_anonymous_default_timeout, [[]]),
1158    ok = gen_server:call(Pid3, started_p),
1159    ok = gen_server:call(Pid3, stop),
1160    receive
1161	{'EXIT', Pid3, stopped} ->
1162 	    ok
1163    after 5000 ->
1164	    ct:fail(gen_server_did_not_die)
1165    end,
1166
1167    {ok, Pid4} =
1168	start_link(spec_init_default_timeout, [{ok, my_server}, []]),
1169    ok = gen_server:call(Pid4, started_p),
1170    ok = gen_server:call(Pid4, stop),
1171    receive
1172	{'EXIT', Pid4, stopped} ->
1173 	    ok
1174    after 5000 ->
1175	    ct:fail(gen_server_did_not_die)
1176    end,
1177
1178    %% Before the OTP-10130 fix this failed because a timeout message
1179    %% was generated as the spawned process crashed because a {global, Name}
1180    %% was matched as a timeout value instead of matching on scope.
1181    {ok, _PidHurra} =
1182	start_link(spec_init_global_default_timeout, [{ok, hurra}, []]),
1183    timer:sleep(1000),
1184    ok = gen_server:call(_PidHurra, started_p),
1185
1186    Pid5 =
1187	erlang:spawn_link(?MODULE, spec_init_not_proc_lib, [[]]),
1188    receive
1189	{'EXIT', Pid5, process_was_not_started_by_proc_lib} ->
1190 	    ok
1191    after 5000 ->
1192	    ct:fail(gen_server_did_not_die)
1193    end,
1194    process_flag(trap_exit, OldFlag),
1195    ok.
1196
1197%%--------------------------------------------------------------
1198%% OTP-4820. Test that terminate is run when the parent is a locally
1199%% registered process.
1200spec_init_local_registered_parent(Config) when is_list(Config) ->
1201
1202    register(foobar, self()),
1203    process_flag(trap_exit, true),
1204
1205    {ok, Pid} = start_link(spec_init_local, [{ok, my_server}, []]),
1206
1207    ok = gen_server:cast(my_server, {self(),stop}),
1208    receive
1209	{Pid, stopped} ->
1210	    ok
1211    after 1000 ->
1212	    ct:fail(stop)
1213    end,
1214    unregister(foobar),
1215    ok.
1216
1217%%--------------------------------------------------------------
1218%% OTP-4820. Test that terminate is run when the parent is a global registered
1219%% process.
1220spec_init_global_registered_parent(Config) when is_list(Config) ->
1221
1222    global:register_name(foobar, self()),
1223    process_flag(trap_exit, true),
1224
1225    {ok, Pid} = start_link(spec_init_global, [{ok, my_server}, []]),
1226
1227    ok = gen_server:call(Pid, started_p),
1228    ok = gen_server:cast(Pid, {self(),stop}),
1229
1230    receive
1231	{Pid, stopped} ->
1232	    ok
1233    after 1000 ->
1234	    ct:fail(stop)
1235    end,
1236    global:unregister_name(foobar),
1237    ok.
1238
1239%%--------------------------------------------------------------
1240
1241%% Test check for registered name in enter_loop/3,4,5.
1242otp_5854(Config) when is_list(Config) ->
1243    OldFlag = process_flag(trap_exit, true),
1244
1245    dummy_via:reset(),
1246
1247    %% Make sure gen_server:enter_loop does not accept {local,Name}
1248    %% when it's another process than the calling one which is
1249    %% registered under that name
1250    register(armitage, self()),
1251    {ok, Pid1} =
1252	start_link(spec_init_local, [{not_ok, armitage}, []]),
1253    receive
1254	{'EXIT', Pid1, process_not_registered} ->
1255	    ok
1256    after 1000 ->
1257	    ct:fail(gen_server_started)
1258    end,
1259    unregister(armitage),
1260
1261    %% Make sure gen_server:enter_loop does not accept {global,Name}
1262    %% when it's another process than the calling one which is
1263    %% registered under that name
1264    global:register_name(armitage, self()),
1265    {ok, Pid2} =
1266	start_link(spec_init_global, [{not_ok, armitage}, []]),
1267    receive
1268	{'EXIT', Pid2, process_not_registered_globally} ->
1269	    ok
1270    after 1000 ->
1271	    ct:fail(gen_server_started)
1272    end,
1273    global:unregister_name(armitage),
1274
1275    %% (same for {via, Mod, Name})
1276    dummy_via:register_name(armitage, self()),
1277    {ok, Pid3} =
1278	start_link(spec_init_via, [{not_ok, armitage}, []]),
1279    receive
1280	{'EXIT', Pid3, {process_not_registered_via, dummy_via}} ->
1281	    ok
1282    after 1000 ->
1283	    ct:fail(gen_server_started)
1284    end,
1285    dummy_via:unregister_name(armitage),
1286
1287    process_flag(trap_exit, OldFlag),
1288    ok.
1289
1290%% If initialization fails (with ignore or {stop,Reason}),
1291%% make sure that the process is not registered when gen_server:start()
1292%% returns.
1293
1294otp_7669(Config) when is_list(Config) ->
1295    do_times(100, fun do_otp_7669_local_ignore/0),
1296    do_times(100, fun do_otp_7669_global_ignore/0),
1297    do_times(10, fun do_otp_7669_stop/0),
1298    ok.
1299
1300do_times(0, _) ->
1301    ok;
1302do_times(N, Fun) ->
1303    Fun(),
1304    do_times(N-1, Fun).
1305
1306do_otp_7669_local_ignore() ->
1307    %% The name should never be registered after the return
1308    %% from gen_server:start/3.
1309    ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
1310    undefined = whereis(?MODULE),
1311    ignore = gen_server:start({local,?MODULE}, ?MODULE, ignore, []),
1312    undefined = whereis(?MODULE),
1313    ignore = gen_server:start_link({local,?MODULE}, ?MODULE, ignore, []),
1314    undefined = whereis(?MODULE).
1315
1316do_otp_7669_global_ignore() ->
1317    ignore = gen_server:start({global,?MODULE}, ?MODULE, ignore, []),
1318    undefined = global:whereis_name(?MODULE),
1319    ignore = gen_server:start_link({global,?MODULE}, ?MODULE, ignore, []),
1320    undefined = global:whereis_name(?MODULE).
1321
1322do_otp_7669_stop() ->
1323    %% The name should never be registered after the return
1324    %% from gen_server:start/3.
1325    {error,stopped} = gen_server:start({local,?MODULE},
1326				       ?MODULE, stop, []),
1327    undefined = whereis(?MODULE),
1328
1329    {error,stopped} = gen_server:start({global,?MODULE},
1330				       ?MODULE, stop, []),
1331    undefined = global:whereis_name(?MODULE).
1332
1333%% Verify that sys:get_status correctly calls our format_status/2 fun.
1334call_format_status(Config) when is_list(Config) ->
1335    Parent = self(),
1336
1337    {ok, Pid} = gen_server:start_link({local, call_format_status},
1338				      ?MODULE, [], []),
1339    Status1 = sys:get_status(call_format_status),
1340    {status, Pid, Mod, [_Pdict1, running, Parent, _, Data1]} = Status1,
1341    [format_status_called | _] = lists:reverse(Data1),
1342    Status2 = sys:get_status(call_format_status, 5000),
1343    {status, Pid, Mod, [_Pdict2, running, Parent, _, Data2]} = Status2,
1344    [format_status_called | _] = lists:reverse(Data2),
1345
1346    %% check that format_status can handle a name being a pid (atom is
1347    %% already checked by the previous test)
1348    {ok, Pid3} = gen_server:start_link(gen_server_SUITE, [], []),
1349    Status3 = sys:get_status(Pid3),
1350    {status, Pid3, Mod, [_PDict3, running, Parent, _, Data3]} = Status3,
1351    [format_status_called | _] = lists:reverse(Data3),
1352
1353    %% check that format_status can handle a name being a term other than a
1354    %% pid or atom
1355    GlobalName1 = {global, "CallFormatStatus"},
1356    {ok, Pid4} = gen_server:start_link(GlobalName1,
1357				       gen_server_SUITE, [], []),
1358    Status4 = sys:get_status(Pid4),
1359    {status, Pid4, Mod, [_PDict4, running, Parent, _, Data4]} = Status4,
1360    [format_status_called | _] = lists:reverse(Data4),
1361    GlobalName2 = {global, {name, "term"}},
1362    {ok, Pid5} = gen_server:start_link(GlobalName2,
1363				       gen_server_SUITE, [], []),
1364    Status5 = sys:get_status(GlobalName2),
1365    {status, Pid5, Mod, [_PDict5, running, Parent, _, Data5]} = Status5,
1366    [format_status_called | _] = lists:reverse(Data5),
1367    ok.
1368
1369%% Verify that error termination correctly calls our format_status/2 fun.
1370error_format_status(Config) when is_list(Config) ->
1371    error_logger_forwarder:register(),
1372    OldFl = process_flag(trap_exit, true),
1373    State = "called format_status",
1374    {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []),
1375    {'EXIT',{crashed,_}} = (catch gen_server:call(Pid, crash)),
1376    receive
1377	{'EXIT', Pid, crashed} ->
1378	    ok
1379    end,
1380    ClientPid = self(),
1381    receive
1382	{error,_GroupLeader,{Pid,
1383			     "** Generic server"++_,
1384			     [Pid,crash,{formatted, State},
1385			      {crashed,[{?MODULE,handle_call,3,_}
1386					|_Stacktrace]},
1387			       ClientPid, [_|_] = _ClientStack]}} ->
1388	    ok;
1389	Other ->
1390	    io:format("Unexpected: ~p", [Other]),
1391	    ct:fail(failed)
1392    end,
1393    process_flag(trap_exit, OldFl),
1394    ok.
1395
1396%% Verify that error when terminating correctly calls our format_status/2 fun
1397%%
1398terminate_crash_format(Config) when is_list(Config) ->
1399    error_logger_forwarder:register(),
1400    OldFl = process_flag(trap_exit, true),
1401    State = crash_terminate,
1402    {ok, Pid} = gen_server:start_link(?MODULE, {state, State}, []),
1403    gen_server:call(Pid, stop),
1404    receive {'EXIT', Pid, {crash, terminate}} -> ok end,
1405    ClientPid = self(),
1406    receive
1407	{error,_GroupLeader,{Pid,
1408			     "** Generic server"++_,
1409			     [Pid,stop, {formatted, State},
1410			      {{crash, terminate},
1411			       [{?MODULE,terminate,2,_}|_Stacktrace]},
1412			       ClientPid, [_|_] = _ClientStack]}} ->
1413	    ok;
1414	Other ->
1415	    io:format("Unexpected: ~p", [Other]),
1416	    ct:fail(failed)
1417    after 5000 ->
1418	    io:format("Timeout: expected error logger msg", []),
1419	    ct:fail(failed)
1420    end,
1421    process_flag(trap_exit, OldFl),
1422    ok.
1423
1424%% Verify that sys:get_state correctly returns gen_server state
1425get_state(Config) when is_list(Config) ->
1426    State = self(),
1427    {ok, _Pid} = gen_server:start_link({local, get_state},
1428				       ?MODULE, {state,State}, []),
1429    State = sys:get_state(get_state),
1430    State = sys:get_state(get_state, 5000),
1431    {ok, Pid} = gen_server:start_link(?MODULE, {state,State}, []),
1432    State = sys:get_state(Pid),
1433    State = sys:get_state(Pid, 5000),
1434    ok = sys:suspend(Pid),
1435    State = sys:get_state(Pid),
1436    ok = sys:resume(Pid),
1437    ok.
1438
1439%% Verify that sys:replace_state correctly replaces gen_server state
1440replace_state(Config) when is_list(Config) ->
1441    State = self(),
1442    {ok, _Pid} = gen_server:start_link({local, replace_state},
1443				       ?MODULE, {state,State}, []),
1444    State = sys:get_state(replace_state),
1445    NState1 = "replaced",
1446    Replace1 = fun(_) -> NState1 end,
1447    NState1 = sys:replace_state(replace_state, Replace1),
1448    NState1 = sys:get_state(replace_state),
1449    {ok, Pid} = gen_server:start_link(?MODULE, {state,NState1}, []),
1450    NState1 = sys:get_state(Pid),
1451    Suffix = " again",
1452    NState2 = NState1 ++ Suffix,
1453    Replace2 = fun(S) -> S ++ Suffix end,
1454    NState2 = sys:replace_state(Pid, Replace2, 5000),
1455    NState2 = sys:get_state(Pid, 5000),
1456    %% verify no change in state if replace function crashes
1457    Replace3 = fun(_) -> throw(fail) end,
1458    {'EXIT',{{callback_failed,
1459	      {gen_server,system_replace_state},{throw,fail}},_}} =
1460	(catch sys:replace_state(Pid, Replace3)),
1461    NState2 = sys:get_state(Pid, 5000),
1462    %% verify state replaced if process sys suspended
1463    ok = sys:suspend(Pid),
1464    Suffix2 = " and again",
1465    NState3 = NState2 ++ Suffix2,
1466    Replace4 = fun(S) -> S ++ Suffix2 end,
1467    NState3 = sys:replace_state(Pid, Replace4),
1468    ok = sys:resume(Pid),
1469    NState3 = sys:get_state(Pid, 5000),
1470    ok.
1471
1472%% Test that the time for a huge message queue is not
1473%% significantly slower than with an empty message queue.
1474call_with_huge_message_queue(Config) when is_list(Config) ->
1475    Pid = spawn_link(fun echo_loop/0),
1476
1477    {Time,ok} = tc(fun() -> calls(10000, Pid) end),
1478
1479    _ = [self() ! {msg,N} || N <- lists:seq(1, 500000)],
1480    erlang:garbage_collect(),
1481    {NewTime,ok} = tc(fun() -> calls(10000, Pid) end),
1482    io:format("Time for empty message queue: ~p", [Time]),
1483    io:format("Time for huge message queue: ~p", [NewTime]),
1484
1485    IsCover = test_server:is_cover(),
1486    case (NewTime+1) / (Time+1) of
1487	Q when Q < 10; IsCover ->
1488	    ok;
1489	Q ->
1490	    io:format("Q = ~p", [Q]),
1491	    ct:fail(failed)
1492    end,
1493    ok.
1494
1495calls(0, _) -> ok;
1496calls(N, Pid) ->
1497    {ultimate_answer,42} = call(Pid, {ultimate_answer,42}),
1498    calls(N-1, Pid).
1499
1500call(Pid, Msg) ->
1501    gen_server:call(Pid, Msg, infinity).
1502
1503tc(Fun) ->
1504    timer:tc(erlang, apply, [Fun,[]]).
1505
1506echo_loop() ->
1507    receive
1508	{'$gen_call',{Pid,Ref},Msg} ->
1509	    Pid ! {Ref,Msg},
1510	    echo_loop()
1511    end.
1512
1513%% Test the default implementation of terminate if the callback module
1514%% does not export it
1515undef_terminate1(Config) when is_list(Config) ->
1516    {ok, Server} = oc_server:start(),
1517    MRef = monitor(process, Server),
1518    ok = gen_server:stop(Server),
1519    ok = verify_down_reason(MRef, Server, normal).
1520
1521%% Test the default implementation of terminate if the callback module
1522%% does not export it
1523undef_terminate2(Config) when is_list(Config) ->
1524    {ok, Server} = oc_server:start(),
1525    MRef = monitor(process, Server),
1526    ok = gen_server:stop(Server, {error, test}, infinity),
1527    ok = verify_down_reason(MRef, Server, {error, test}).
1528
1529%% Start should return an undef error if init isn't implemented
1530undef_init(_Config) ->
1531    {error, {undef, [{oc_init_server, init, [_], _}|_]}} =
1532        gen_server:start(oc_init_server, [], []),
1533    process_flag(trap_exit, true),
1534    {error, {undef, [{oc_init_server, init, [_], _}|_]}} =
1535        (catch gen_server:start_link(oc_init_server, [], [])),
1536    receive
1537        {'EXIT', Server,
1538         {undef, [{oc_init_server, init, [_], _}|_]}} when is_pid(Server) ->
1539            ok
1540    after 1000 ->
1541        ct:fail(expected_exit_msg)
1542    end.
1543
1544%% The upgrade should fail if code_change is expected in the callback module
1545%% but not exported, but the server should continue with the old code
1546undef_code_change(Config) when is_list(Config) ->
1547    {ok, Server} = oc_server:start(),
1548    {error, {'EXIT', {undef, [{oc_server, code_change, [_, _, _], _}|_]}}}
1549        = fake_upgrade(Server, ?MODULE),
1550    true = is_process_alive(Server).
1551
1552%% The server should crash if the handle_call callback is
1553%% not exported in the callback module
1554undef_handle_call(_Config) ->
1555    {ok, Server} = oc_server:start(),
1556    try
1557        gen_server:call(Server, call_msg),
1558        ct:fail(should_crash)
1559    catch exit:{{undef, [{oc_server, handle_call, _, _}|_]},
1560                {gen_server, call, _}} ->
1561        ok
1562    end.
1563
1564%% The server should crash if the handle_cast callback is
1565%% not exported in the callback module
1566undef_handle_cast(_Config) ->
1567    {ok, Server} = oc_server:start(),
1568    MRef = monitor(process, Server),
1569    gen_server:cast(Server, cast_msg),
1570    verify_undef_down(MRef, Server, oc_server, handle_cast),
1571    ok.
1572
1573%% The server should crash if the handle_continue callback is
1574%% not exported in the callback module
1575undef_handle_continue(_Config) ->
1576    {ok, Server} = oc_server:start(continue),
1577    MRef = monitor(process, Server),
1578    verify_undef_down(MRef, Server, oc_server, handle_continue),
1579    ok.
1580
1581%% The server should log but not crash if the handle_info callback is
1582%% calling an undefined function
1583undef_handle_info(Config) when is_list(Config) ->
1584    error_logger_forwarder:register(),
1585    {ok, Server} = oc_server:start(),
1586    Server ! hej,
1587    wait_until_processed(Server, hej, 10),
1588    true = is_process_alive(Server),
1589    receive
1590        {warning_msg, _GroupLeader,
1591         {Server, "** Undefined handle_info in " ++ _, [oc_server, hej]}} ->
1592            ok;
1593        Other ->
1594            io:format("Unexpected: ~p", [Other]),
1595            ct:fail(failed)
1596    end.
1597
1598%% Test that the default implementation of terminate isn't catching the
1599%% wrong undef error
1600undef_in_terminate(Config) when is_list(Config) ->
1601    State = {undef_in_terminate, {oc_server, terminate}},
1602    {ok, Server} = gen_server:start(?MODULE, {state, State}, []),
1603    try
1604        ok = gen_server:stop(Server),
1605        ct:fail(failed)
1606    catch
1607        exit:{undef, [{oc_server, terminate, [], _}|_]} ->
1608            ok
1609    end.
1610
1611%% Test that the default implementation of handle_info isn't catching the
1612%% wrong undef error
1613undef_in_handle_info(Config) when is_list(Config) ->
1614     {ok, Server} = gen_server:start(?MODULE, [], []),
1615     MRef = monitor(process, Server),
1616     Server ! {call_undef_fun, ?MODULE, handle_info},
1617     verify_undef_down(MRef, Server, ?MODULE, handle_info),
1618     ok.
1619
1620verify_down_reason(MRef, Server, Reason) ->
1621    receive
1622        {'DOWN', MRef, process, Server, Reason} ->
1623            ok
1624    after 5000 ->
1625        ct:fail(failed)
1626    end.
1627
1628verify_undef_down(MRef, Pid, Mod, Fun) ->
1629    ok = receive
1630        {'DOWN', MRef, process, Pid,
1631         {undef, [{Mod, Fun, _, _}|_]}} ->
1632            ok
1633    after 5000 ->
1634        ct:fail(should_crash)
1635    end.
1636
1637fake_upgrade(Pid, Mod) ->
1638    sys:suspend(Pid),
1639    sys:replace_state(Pid, fun(State) -> {new, State} end),
1640    Ret = sys:change_code(Pid, Mod, old_vsn, []),
1641    ok = sys:resume(Pid),
1642    Ret.
1643
1644wait_until_processed(_Pid, _Message, 0) ->
1645    ct:fail(not_processed);
1646wait_until_processed(Pid, Message, N) ->
1647    {messages, Messages} = erlang:process_info(Pid, messages),
1648    case lists:member(Message, Messages) of
1649        true ->
1650            timer:sleep(100),
1651            wait_until_processed(Pid, Message, N-1);
1652        false ->
1653            ok
1654    end.
1655
1656%% Test report callback for Logger handler error_logger
1657format_log_1(_Config) ->
1658    FD = application:get_env(kernel,error_logger_format_depth),
1659    application:unset_env(kernel,error_logger_format_depth),
1660    Term = lists:seq(1,15),
1661    Name = self(),
1662    Report = #{label=>{gen_server,terminate},
1663               name=>Name,
1664               last_message=>Term,
1665               state=>Term,
1666               log=>[],
1667               reason=>Term,
1668               client_info=>{self(),{clientname,[]}}},
1669    {F1,A1} = gen_server:format_log(Report),
1670    FExpected1 = "** Generic server ~tp terminating \n"
1671        "** Last message in was ~tp~n"
1672        "** When Server state == ~tp~n"
1673        "** Reason for termination ==~n** ~tp~n"
1674        "** Client ~tp stacktrace~n"
1675        "** ~tp~n",
1676    ct:log("F1: ~ts~nA1: ~tp",[F1,A1]),
1677    FExpected1=F1,
1678    [Name,Term,Term,Term,clientname,[]] = A1,
1679
1680    Warning = #{label=>{gen_server,no_handle_info},
1681                module=>?MODULE,
1682                message=>Term},
1683    {WF1,WA1} = gen_server:format_log(Warning),
1684    WFExpected1 = "** Undefined handle_info in ~p~n"
1685        "** Unhandled message: ~tp~n",
1686    ct:log("WF1: ~ts~nWA1: ~tp",[WF1,WA1]),
1687    WFExpected1=WF1,
1688    [?MODULE,Term] = WA1,
1689
1690    Depth = 10,
1691    ok = application:set_env(kernel,error_logger_format_depth,Depth),
1692    Limited = [1,2,3,4,5,6,7,8,9,'...'],
1693    {F2,A2} = gen_server:format_log(#{label=>{gen_server,terminate},
1694                                      name=>Name,
1695                                      last_message=>Term,
1696                                      state=>Term,
1697                                      log=>[],
1698                                      reason=>Term,
1699                                      client_info=>{self(),{clientname,[]}}}),
1700    FExpected2 = "** Generic server ~tP terminating \n"
1701        "** Last message in was ~tP~n"
1702        "** When Server state == ~tP~n"
1703        "** Reason for termination ==~n** ~tP~n"
1704        "** Client ~tP stacktrace~n"
1705        "** ~tP~n",
1706    ct:log("F2: ~ts~nA2: ~tp",[F2,A2]),
1707    FExpected2=F2,
1708    [Name,Depth,Limited,Depth,Limited,Depth,Limited,Depth,
1709     clientname,Depth,[],Depth] = A2,
1710
1711    {WF2,WA2} = gen_server:format_log(Warning),
1712    WFExpected2 = "** Undefined handle_info in ~p~n"
1713        "** Unhandled message: ~tP~n",
1714    ct:log("WF2: ~ts~nWA2: ~tp",[WF2,WA2]),
1715    WFExpected2=WF2,
1716    [?MODULE,Limited,Depth] = WA2,
1717
1718    case FD of
1719        undefined ->
1720            application:unset_env(kernel,error_logger_format_depth);
1721        _ ->
1722            application:set_env(kernel,error_logger_format_depth,FD)
1723    end,
1724    ok.
1725
1726%% Test report callback for any Logger handler
1727format_log_2(_Config) ->
1728    Term = lists:seq(1,15),
1729    Name = self(),
1730    NameStr = pid_to_list(Name),
1731    Report = #{label=>{gen_server,terminate},
1732               name=>Name,
1733               last_message=>Term,
1734               state=>Term,
1735               log=>[],
1736               reason=>Term,
1737               client_info=>{self(),{clientname,[]}}},
1738    FormatOpts1 = #{},
1739    Str1 = flatten_format_log(Report,FormatOpts1),
1740    L1 = length(Str1),
1741    Expected1 = "** Generic server "++NameStr++" terminating \n"
1742        "** Last message in was ",
1743    ct:log("Str1: ~ts",[Str1]),
1744    ct:log("length(Str1): ~p",[L1]),
1745    true = lists:prefix(Expected1,Str1),
1746
1747    Warning = #{label=>{gen_server,no_handle_info},
1748                module=>?MODULE,
1749                message=>Term},
1750    WStr1 = flatten_format_log(Warning,FormatOpts1),
1751    WL1 = length(WStr1),
1752    WExpected1 = "** Undefined handle_info in gen_server_SUITE\n"
1753        "** Unhandled message: ",
1754    ct:log("WStr1: ~ts",[WStr1]),
1755    ct:log("length(WStr1): ~p",[WL1]),
1756    true = lists:prefix(WExpected1,WStr1),
1757
1758    Depth = 10,
1759    FormatOpts2 = #{depth=>Depth},
1760    Str2 = flatten_format_log(Report,FormatOpts2),
1761    L2 = length(Str2),
1762    Expected2 = "** Generic server "++NameStr++" terminating \n"
1763        "** Last message in was ",
1764    ct:log("Str2: ~ts",[Str2]),
1765    ct:log("length(Str2): ~p",[L2]),
1766    true = lists:prefix(Expected2,Str2),
1767    true = L2<L1,
1768
1769    WStr2 = flatten_format_log(Warning,FormatOpts2),
1770    WL2 = length(WStr2),
1771    WExpected2 = "** Undefined handle_info in gen_server_SUITE\n"
1772        "** Unhandled message: ",
1773    ct:log("WStr2: ~ts",[WStr2]),
1774    ct:log("length(WStr2): ~p",[WL2]),
1775    true = lists:prefix(WExpected2,WStr2),
1776    true = WL2<WL1,
1777
1778    FormatOpts3 = #{chars_limit=>200},
1779    Str3 = flatten_format_log(Report,FormatOpts3),
1780    L3 = length(Str3),
1781    Expected3 = "** Generic server "++NameStr++" terminating \n"
1782        "** Last message in was ",
1783    ct:log("Str3: ~ts",[Str3]),
1784    ct:log("length(Str3): ~p",[L3]),
1785    true = lists:prefix(Expected3,Str3),
1786    true = L3<L1,
1787
1788    WFormatOpts3 = #{chars_limit=>80},
1789    WStr3 = flatten_format_log(Warning,WFormatOpts3),
1790    WL3 = length(WStr3),
1791    WExpected3 = "** Undefined handle_info in gen_server_SUITE\n"
1792        "** Unhandled message: ",
1793    ct:log("WStr3: ~ts",[WStr3]),
1794    ct:log("length(WStr3): ~p",[WL3]),
1795    true = lists:prefix(WExpected3,WStr3),
1796    true = WL3<WL1,
1797
1798    FormatOpts4 = #{single_line=>true},
1799    Str4 = flatten_format_log(Report,FormatOpts4),
1800    L4 = length(Str4),
1801    Expected4 = "Generic server "++NameStr++" terminating. Reason: ",
1802    ct:log("Str4: ~ts",[Str4]),
1803    ct:log("length(Str4): ~p",[L4]),
1804    true = lists:prefix(Expected4,Str4),
1805    true = L4<L1,
1806
1807    WStr4 = flatten_format_log(Warning,FormatOpts4),
1808    WL4 = length(WStr4),
1809    WExpected4 = "Undefined handle_info in gen_server_SUITE. "
1810        "Unhandled message: ",
1811    ct:log("WStr4: ~ts",[WStr4]),
1812    ct:log("length(WStr4): ~p",[WL4]),
1813    true = lists:prefix(WExpected4,WStr4),
1814    true = WL4<WL1,
1815
1816    FormatOpts5 = #{single_line=>true, depth=>Depth},
1817    Str5 = flatten_format_log(Report,FormatOpts5),
1818    L5 = length(Str5),
1819    Expected5 = "Generic server "++NameStr++" terminating. Reason: ",
1820    ct:log("Str5: ~ts",[Str5]),
1821    ct:log("length(Str5): ~p",[L5]),
1822    true = lists:prefix(Expected5,Str5),
1823    true = L5<L4,
1824
1825    WStr5 = flatten_format_log(Warning,FormatOpts5),
1826    WL5 = length(WStr5),
1827    WExpected5 = "Undefined handle_info in gen_server_SUITE. "
1828        "Unhandled message: ",
1829    ct:log("WStr5: ~ts",[WStr5]),
1830    ct:log("length(WStr5): ~p",[WL5]),
1831    true = lists:prefix(WExpected5,WStr5),
1832    true = WL5<WL4,
1833
1834    FormatOpts6 = #{single_line=>true, chars_limit=>200},
1835    Str6 = flatten_format_log(Report,FormatOpts6),
1836    L6 = length(Str6),
1837    Expected6 = "Generic server "++NameStr++" terminating. Reason: ",
1838    ct:log("Str6: ~ts",[Str6]),
1839    ct:log("length(Str6): ~p",[L6]),
1840    true = lists:prefix(Expected6,Str6),
1841    true = L6<L4,
1842
1843    WFormatOpts6 = #{single_line=>true, chars_limit=>80},
1844    WStr6 = flatten_format_log(Warning,WFormatOpts6),
1845    WL6 = length(WStr6),
1846    WExpected6 = "Undefined handle_info in gen_server_SUITE. "
1847        "Unhandled message: ",
1848    ct:log("WStr6: ~ts",[WStr6]),
1849    ct:log("length(WStr6): ~p",[WL6]),
1850    true = lists:prefix(WExpected6,WStr6),
1851    true = WL6<WL4,
1852
1853    ok.
1854
1855flatten_format_log(Report, Format) ->
1856    lists:flatten(gen_server:format_log(Report, Format)).
1857
1858reply_by_alias_with_payload(Config) when is_list(Config) ->
1859    %% "Payload" version of tag not used yet, but make sure
1860    %% gen_server:reply/2 works with it...
1861    %%
1862    %% Whitebox...
1863    Reply = make_ref(),
1864    Alias = alias(),
1865    Tag = [[alias|Alias], "payload"],
1866    spawn_link(fun () ->
1867                       gen_server:reply({undefined, Tag},
1868                                        Reply)
1869               end),
1870    receive
1871        {[[alias|Alias]|_] = Tag, Reply} ->
1872            ok
1873    end,
1874    %% Check gen:reply/2 as well...
1875    Reply2 = make_ref(),
1876    Alias2 = alias(),
1877    Tag2 = [[alias|Alias2], "payload"],
1878    spawn_link(fun () ->
1879                       gen:reply({undefined, Tag2},
1880                                 Reply2)
1881               end),
1882    receive
1883        {[[alias|Alias2]|_] = Tag2, Reply2} ->
1884            ok
1885    end.
1886
1887%%--------------------------------------------------------------
1888%% Help functions to spec_init_*
1889start_link(Init, Options) ->
1890    proc_lib:start_link(?MODULE, Init, Options).
1891
1892spec_init_local({ok, Name}, Options) ->
1893    process_flag(trap_exit, true),
1894    register(Name, self()),
1895    proc_lib:init_ack({ok, self()}),
1896    %% Supervised init can occur here  ...
1897    gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity);
1898
1899spec_init_local({not_ok, Name}, Options) ->
1900    process_flag(trap_exit, true),
1901    proc_lib:init_ack({ok, self()}),
1902    %% Supervised init can occur here  ...
1903    gen_server:enter_loop(?MODULE, Options, {}, {local, Name}, infinity).
1904
1905spec_init_global({ok, Name}, Options) ->
1906    process_flag(trap_exit, true),
1907    global:register_name(Name, self()),
1908    proc_lib:init_ack({ok, self()}),
1909    %% Supervised init can occur here  ...
1910    gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity);
1911
1912spec_init_global({not_ok, Name}, Options) ->
1913    process_flag(trap_exit, true),
1914    proc_lib:init_ack({ok, self()}),
1915    %% Supervised init can occur here  ...
1916    gen_server:enter_loop(?MODULE, Options, {}, {global, Name}, infinity).
1917
1918spec_init_via({ok, Name}, Options) ->
1919    process_flag(trap_exit, true),
1920    dummy_via:register_name(Name, self()),
1921    proc_lib:init_ack({ok, self()}),
1922    %% Supervised init can occur here  ...
1923    gen_server:enter_loop(?MODULE, Options, {},
1924			  {via, dummy_via, Name}, infinity);
1925
1926spec_init_via({not_ok, Name}, Options) ->
1927    process_flag(trap_exit, true),
1928    proc_lib:init_ack({ok, self()}),
1929    %% Supervised init can occur here  ...
1930    gen_server:enter_loop(?MODULE, Options, {},
1931			  {via, dummy_via, Name}, infinity).
1932
1933spec_init_default_timeout({ok, Name}, Options) ->
1934    process_flag(trap_exit, true),
1935    register(Name, self()),
1936    proc_lib:init_ack({ok, self()}),
1937    %% Supervised init can occur here  ...
1938    gen_server:enter_loop(?MODULE, Options, {}, {local, Name}).
1939
1940%% OTP-10130, A bug was introduced where global scope was not matched when
1941%% enter_loop/4 was called (no timeout).
1942spec_init_global_default_timeout({ok, Name}, Options) ->
1943    process_flag(trap_exit, true),
1944    global:register_name(Name, self()),
1945    proc_lib:init_ack({ok, self()}),
1946    %% Supervised init can occur here  ...
1947    gen_server:enter_loop(?MODULE, Options, {}, {global, Name}).
1948
1949spec_init_anonymous(Options) ->
1950    process_flag(trap_exit, true),
1951    proc_lib:init_ack({ok, self()}),
1952    %% Supervised init can occur here  ...
1953    gen_server:enter_loop(?MODULE, Options, {}, infinity).
1954
1955spec_init_anonymous_default_timeout(Options) ->
1956    process_flag(trap_exit, true),
1957    proc_lib:init_ack({ok, self()}),
1958    %% Supervised init can occur here  ...
1959    gen_server:enter_loop(?MODULE, Options, {}).
1960
1961spec_init_not_proc_lib(Options) ->
1962    gen_server:enter_loop(?MODULE, Options, {}, infinity).
1963
1964%%% --------------------------------------------------------
1965%%% Here is the tested gen_server behaviour.
1966%%% --------------------------------------------------------
1967
1968init([]) ->
1969    {ok, []};
1970init(ignore) ->
1971    ignore;
1972init(stop) ->
1973    {stop, stopped};
1974init(hibernate) ->
1975    {ok,[],hibernate};
1976init(sleep) ->
1977    ct:sleep(1000),
1978    {ok, []};
1979init({continue, Pid}) ->
1980    self() ! {after_continue, Pid},
1981    {ok, [], {continue, {message, Pid}}};
1982init({state,State}) ->
1983    {ok,State}.
1984
1985handle_call(started_p, _From, State) ->
1986    io:format("FROZ"),
1987    {reply,ok,State};
1988handle_call({delayed_answer, T}, From, _State) ->
1989    {noreply,{reply_to,From},T};
1990handle_call({call_within, T}, _From, _) ->
1991    {reply,ok,call_within,T};
1992handle_call(next_call, _From, call_within) ->
1993    {reply,ok,[]};
1994handle_call(next_call, _From, State) ->
1995    {reply,false,State};
1996handle_call(badreturn, _From, _State) ->
1997    badreturn;
1998handle_call(hibernate, _From, _State) ->
1999    {reply,true,[],hibernate};
2000handle_call({hibernate_noreply,Pid}, From, _State) ->
2001    Pid ! go,
2002    {noreply,From,hibernate};
2003handle_call(stop, _From, State) ->
2004    {stop,stopped,ok,State};
2005handle_call(crash, _From, _State) ->
2006    exit(crashed);
2007handle_call(exit_shutdown, _From, _State) ->
2008    exit(shutdown);
2009handle_call(stop_shutdown, _From, State) ->
2010    {stop,shutdown,State};
2011handle_call(shutdown_reason, _From, _State) ->
2012    exit({shutdown,reason});
2013handle_call({call_undef_fun, Mod, Fun}, _From, State) ->
2014    Mod:Fun(),
2015    {reply, ok, State};
2016handle_call({continue_reply, Pid}, _From, State) ->
2017    self() ! {after_continue, Pid},
2018    {reply, ok, State, {continue, {message, Pid}}};
2019handle_call({continue_noreply, Pid}, From, State) ->
2020    self() ! {after_continue, Pid},
2021    {noreply, State, {continue, {message, Pid, From}}};
2022handle_call(stop_shutdown_reason, _From, State) ->
2023    {stop,{shutdown,stop_reason},State}.
2024
2025handle_cast({From,handle_cast}, State) ->
2026    From ! {self(), handled_cast},
2027    {noreply, State};
2028handle_cast({From,delayed_cast,T}, _State) ->
2029    {noreply, {delayed_cast,From}, T};
2030handle_cast(hibernate_now, _State) ->
2031    {noreply, [], hibernate};
2032handle_cast(hibernate_later, _State) ->
2033    {ok, _} = timer:send_after(1000,self(),hibernate_now),
2034    {noreply, []};
2035handle_cast({call_undef_fun, Mod, Fun}, State) ->
2036    Mod:Fun(),
2037    {noreply, State};
2038handle_cast({continue_noreply, Pid}, State) ->
2039    self() ! {after_continue, Pid},
2040    {noreply, State, {continue, {message, Pid}}};
2041handle_cast({From, stop}, State) ->
2042    io:format("BAZ"),
2043    {stop, {From,stopped}, State}.
2044
2045handle_info(timeout, {reply_to, From}) ->
2046    gen_server:reply(From, delayed),
2047    {noreply, []};
2048handle_info(timeout, hibernate_me) -> % Arrive here from
2049						% handle_info(hibernate_later,...)
2050    {noreply, [], hibernate};
2051handle_info(hibernate_now, _State) ->  % Arrive here from
2052						% handle_cast({_,hibernate_later},...)
2053						% and by direct ! from testcase
2054    {noreply, [], hibernate};
2055handle_info(hibernate_later, _State) ->
2056    {noreply, hibernate_me, 1000};
2057handle_info(timeout, call_within) ->
2058    {noreply, []};
2059handle_info(timeout, {delayed_cast, From}) ->
2060    From ! {self(), delayed},
2061    {noreply, []};
2062handle_info(timeout, {delayed_info, From}) ->
2063    From ! {self(), delayed_info},
2064    {noreply, []};
2065handle_info({call_undef_fun, Mod, Fun}, State) ->
2066    Mod:Fun(),
2067    {noreply, State};
2068handle_info({From, handle_info}, _State) ->
2069    From ! {self(), handled_info},
2070    {noreply, []};
2071handle_info({From, delayed_info, T}, _State) ->
2072    {noreply, {delayed_info, From}, T};
2073handle_info(continue, From) ->
2074    gen_server:reply(From,true),
2075    {noreply, []};
2076handle_info({From, stop}, State) ->
2077    {stop, {From,stopped_info}, State};
2078handle_info({after_continue, Pid}, State) ->
2079    Pid ! {self(), after_continue},
2080    Pid ! {self(), ack},
2081    {noreply, State};
2082handle_info({continue_noreply, Pid}, State) ->
2083    self() ! {after_continue, Pid},
2084    {noreply, State, {continue, {message, Pid}}};
2085handle_info({continue_continue, Pid}, State) ->
2086    {noreply, State, {continue, {continue, Pid}}};
2087handle_info(continue_stop, State) ->
2088    {noreply, State, {continue, stop}};
2089handle_info(_Info, State) ->
2090    {noreply, State}.
2091
2092handle_continue({continue, Pid}, State) ->
2093    Pid ! {self(), before_continue},
2094    self() ! {after_continue, Pid},
2095    {noreply, State, {continue, {message, Pid}}};
2096handle_continue(stop, State) ->
2097    {stop, normal, State};
2098handle_continue({message, Pid}, State) ->
2099    Pid ! {self(), continue},
2100    {noreply, State};
2101handle_continue({message, Pid, From}, State) ->
2102    Pid ! {self(), continue},
2103    gen_server:reply(From, ok),
2104    {noreply, State}.
2105
2106code_change(_OldVsn,
2107            {new, {undef_in_code_change, {Mod, Fun}}} = State,
2108            _Extra) ->
2109    Mod:Fun(),
2110    {ok, State}.
2111
2112terminate({From, stopped}, _State) ->
2113    io:format("FOOBAR"),
2114    From ! {self(), stopped},
2115    ok;
2116terminate({From, stopped_info}, _State) ->
2117    From ! {self(), stopped_info},
2118    ok;
2119terminate(_, crash_terminate) ->
2120    exit({crash, terminate});
2121terminate(_, {undef_in_terminate, {Mod, Fun}}) ->
2122    Mod:Fun(),
2123    ok;
2124terminate(_Reason, _State) ->
2125    ok.
2126
2127format_status(terminate, [_PDict, State]) ->
2128    {formatted, State};
2129format_status(normal, [_PDict, _State]) ->
2130    format_status_called.
2131