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