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