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