1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2021 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 21%% 22%%---------------------------------------------------------------------- 23%% Purpose: 24%%---------------------------------------------------------------------- 25-module(megaco_udp_SUITE). 26 27%%---------------------------------------------------------------------- 28%% Include files 29%%---------------------------------------------------------------------- 30-include_lib("common_test/include/ct.hrl"). 31-include_lib("megaco/src/udp/megaco_udp.hrl"). 32-include("megaco_test_lib.hrl"). 33 34 35%%---------------------------------------------------------------------- 36%% External exports 37%%---------------------------------------------------------------------- 38-export([ 39 suite/0, all/0, groups/0, 40 init_per_suite/1, end_per_suite/1, 41 init_per_group/2, end_per_group/2, 42 init_per_testcase/2, end_per_testcase/2, 43 44 start_normal/1, 45 start_invalid_opt/1, 46 start_and_stop/1, 47 sendreceive/1, 48 block_unblock/1, 49 socket_failure/1 50 51 ]). 52 53 54%%---------------------------------------------------------------------- 55%% Internal exports 56%%---------------------------------------------------------------------- 57-export([ 58 receive_message/4, 59 process_received_message/4 60 ]). 61 62 63%%---------------------------------------------------------------------- 64%% Macros 65%%---------------------------------------------------------------------- 66 67-define(CH, megaco_test_command_handler). 68-define(TEST_VERBOSITY, debug). 69 70 71%%---------------------------------------------------------------------- 72%% Records 73%%---------------------------------------------------------------------- 74 75 76%%====================================================================== 77%% Common Test interface functions 78%%====================================================================== 79 80suite() -> 81 [{ct_hooks, [ts_install_cth]}]. 82 83all() -> 84 %% This is a temporary messure to ensure that we can 85 %% test the socket backend without effecting *all* 86 %% applications on *all* machines. 87 %% This flag is set only for *one* host. 88 case ?TEST_INET_BACKENDS() of 89 true -> 90 [ 91 {group, inet_backend_default}, 92 {group, inet_backend_inet}, 93 {group, inet_backend_socket} 94 ]; 95 _ -> 96 [ 97 {group, inet_backend_default} 98 ] 99 end. 100 101groups() -> 102 [ 103 {inet_backend_default, [], inet_backend_default_cases()}, 104 {inet_backend_inet, [], inet_backend_inet_cases()}, 105 {inet_backend_socket, [], inet_backend_socket_cases()}, 106 107 {all, [], all_cases()}, 108 {start, [], start_cases()}, 109 {sending, [], sending_cases()}, 110 {error, [], error_cases()} 111 ]. 112 113inet_backend_default_cases() -> 114 [{all, [], all_cases()}]. 115 116inet_backend_inet_cases() -> 117 [{all, [], all_cases()}]. 118 119inet_backend_socket_cases() -> 120 [{all, [], all_cases()}]. 121 122all_cases() -> 123 [ 124 {group, start}, 125 {group, sending}, 126 {group, error} 127 ]. 128 129start_cases() -> 130 [ 131 start_normal, 132 start_invalid_opt, 133 start_and_stop 134 ]. 135 136sending_cases() -> 137 [ 138 sendreceive, 139 block_unblock 140 ]. 141 142error_cases() -> 143 [ 144 socket_failure 145 ]. 146 147 148 149%% 150%% ----- 151%% 152 153init_per_suite(suite) -> 154 []; 155init_per_suite(doc) -> 156 []; 157init_per_suite(Config0) when is_list(Config0) -> 158 159 ?ANNOUNCE_SUITE_INIT(), 160 161 p("init_per_suite -> entry with" 162 "~n Config: ~p" 163 "~n Nodes: ~p", [Config0, erlang:nodes()]), 164 165 case ?LIB:init_per_suite(Config0) of 166 {skip, _} = SKIP -> 167 SKIP; 168 169 Config1 when is_list(Config1) -> 170 171 %% We need a (local) monitor on this node also 172 megaco_test_sys_monitor:start(), 173 174 p("init_per_suite -> end when" 175 "~n Config: ~p" 176 "~n Nodes: ~p", [Config1, erlang:nodes()]), 177 178 Config1 179 end. 180 181end_per_suite(suite) -> []; 182end_per_suite(doc) -> []; 183end_per_suite(Config0) when is_list(Config0) -> 184 185 p("end_per_suite -> entry with" 186 "~n Config: ~p" 187 "~n Nodes: ~p", [Config0, erlang:nodes()]), 188 189 megaco_test_sys_monitor:stop(), 190 Config1 = ?LIB:end_per_suite(Config0), 191 192 p("end_per_suite -> end when" 193 "~n Nodes: ~p", [erlang:nodes()]), 194 195 Config1. 196 197 198%% 199%% ----- 200%% 201 202init_per_group(inet_backend_default = Group, Config) -> 203 ?ANNOUNCE_GROUP_INIT(Group), 204 [{socket_create_opts, []} | Config]; 205init_per_group(inet_backend_inet = Group, Config) -> 206 ?ANNOUNCE_GROUP_INIT(Group), 207 case ?EXPLICIT_INET_BACKEND() of 208 true -> 209 %% The environment trumps us, 210 %% so only the default group should be run! 211 {skip, "explicit inet backend"}; 212 false -> 213 [{socket_create_opts, [{inet_backend, inet}]} | Config] 214 end; 215init_per_group(inet_backend_socket = Group, Config) -> 216 ?ANNOUNCE_GROUP_INIT(Group), 217 case ?EXPLICIT_INET_BACKEND() of 218 true -> 219 %% The environment trumps us, 220 %% so only the default group should be run! 221 {skip, "explicit inet backend"}; 222 false -> 223 [{socket_create_opts, [{inet_backend, socket}]} | Config] 224 end; 225init_per_group(Group, Config) -> 226 ?ANNOUNCE_GROUP_INIT(Group), 227 Config. 228 229end_per_group(_Group, Config) -> 230 Config. 231 232 233 234%% 235%% ----- 236%% 237 238init_per_testcase(Case, Config) -> 239 240 p("init_per_testcase -> entry with" 241 "~n Config: ~p" 242 "~n Nodes: ~p", [Config, erlang:nodes()]), 243 244 megaco_test_global_sys_monitor:reset_events(), 245 246 megaco_test_lib:init_per_testcase(Case, Config). 247 248end_per_testcase(Case, Config) -> 249 250 p("end_per_testcase -> entry with" 251 "~n Config: ~p" 252 "~n Nodes: ~p", [Config, erlang:nodes()]), 253 254 p("system events during test: " 255 "~n ~p", [megaco_test_global_sys_monitor:events()]), 256 257 megaco_test_lib:end_per_testcase(Case, Config). 258 259 260 261%% ================================================= 262%% 263%% ------------------ start ------------------------ 264%% 265%% ================================================= 266 267%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 268 269start_normal(suite) -> 270 []; 271start_normal(Config) when is_list(Config) -> 272 ?ACQUIRE_NODES(1, Config), 273 Opts = [{port, 0}, {receive_handle, apa}], 274 {ok, Pid} = start_case(Config, Opts, ok), 275 megaco_udp:stop_transport(Pid), 276 ok. 277 278 279%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 280 281start_invalid_opt(suite) -> 282 []; 283start_invalid_opt(Config) when is_list(Config) -> 284 ?ACQUIRE_NODES(1, Config), 285 Opts = [{port, 0}, {receivehandle, apa}], 286 start_case(Config, Opts, error). 287 288 289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 290 291start_and_stop(suite) -> 292 []; 293start_and_stop(doc) -> 294 ["This test case sets up a connection and then cloises it. " 295 "No data is sent. "]; 296start_and_stop(Config) when is_list(Config) -> 297 Factor = ?config(megaco_factor, Config), 298 ct:timetrap(Factor * ?SECS(45)), 299 Pre = fun() -> 300 p("create nodes"), 301 ServerNode = make_node_name(server), 302 ClientNode = make_node_name(client), 303 Nodes = [ServerNode, ClientNode], 304 ok = ?START_NODES(Nodes), 305 Nodes 306 end, 307 Case = fun(X) -> do_start_and_stop(Config, Factor, X) end, 308 Post = fun(Nodes) -> 309 p("stop nodes"), 310 ?STOP_NODES(lists:reverse(Nodes)) 311 end, 312 try_tc(start_and_stop, Pre, Case, Post). 313 314do_start_and_stop(Config, Factor, [ServerNode, ClientNode]) -> 315 %% Create command sequences 316 TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end, 317 TO = TOCalc(?SECS(5)), 318 p("create command sequences"), 319 ServerPort = 2944, 320 ServerCmds = start_and_stop_server_commands(Config, ServerPort), 321 {ok, ServerHost} = inet:gethostname(), 322 ClientCmds = start_and_stop_client_commands(Config, TO, ServerPort, ServerHost), 323 324 %% Start the test procs used in the test-case, one for each node 325 p("start command handlers"), 326 Server = server_start_command_handler(ServerNode, ServerCmds), 327 p("server command handler started: ~p", [Server]), 328 Client = client_start_command_handler(ClientNode, ClientCmds), 329 p("client command handler started: ~p", [Client]), 330 331 ok = 332 receive 333 {operational, Server} -> 334 p("received listening message from server [~p] => " 335 "send continue to client [~p]~n", [Server, Client]), 336 Client ! {continue, self()}, 337 ok; 338 {'EXIT', Server, {skip, Reason}} -> 339 ?SKIP(Reason); 340 {'EXIT', Client, {skip, Reason}} -> 341 ?SKIP(Reason) 342 after TO -> 343 {error, server_timeout} 344 end, 345 346 ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))), 347 p("done"), 348 ok. 349 350 351start_and_stop_server_commands(Config, Port) -> 352 Opts = [{port, Port}], 353 Self = self(), 354 [ 355 #{id => 1, 356 desc => "Command sequence init", 357 cmd => fun(State) -> 358 {ok, State#{parent => Self}} 359 end}, 360 361 #{id => 2, 362 desc => "Start transport", 363 cmd => fun(State) -> 364 server_start_transport(State) 365 end}, 366 367 #{id => 3, 368 desc => "Open", 369 cmd => fun(State) -> 370 server_open(Config, State, Opts) 371 end}, 372 373 #{id => 4, 374 desc => "Notify operational", 375 cmd => fun(State) -> 376 server_notify_operational(State) 377 end}, 378 379 #{id => 5, 380 desc => "Await nothing", 381 cmd => fun(State) -> 382 server_await_nothing(State, 5000) 383 end}, 384 385 #{id => 6, 386 desc => "Close", 387 cmd => fun(State) -> 388 server_close(State) 389 end}, 390 391 #{id => 7, 392 desc => "Stop", 393 cmd => fun(State) -> 394 server_stop_transport(State) 395 end} 396 397 ]. 398 399start_and_stop_client_commands(Config, TO, ServerPort, _ServerHost) -> 400 Opts = [{port, ServerPort}], 401 Self = self(), 402 [ 403 #{id => 1, 404 desc => "Command sequence init", 405 cmd => fun(State) -> 406 {ok, State#{parent => Self}} 407 end}, 408 409 #{id => 2, 410 desc => "Start transport", 411 cmd => fun(State) -> 412 client_start_transport(State) 413 end}, 414 415 #{id => 3, 416 desc => "Open", 417 cmd => fun(State) -> 418 client_open(Config, State, Opts) 419 end}, 420 421 #{id => 4, 422 desc => "Await continue", 423 cmd => fun(State) -> 424 client_await_continue_signal(State, TO) 425 end}, 426 427 #{id => 5, 428 desc => "Await nothing", 429 cmd => fun(State) -> 430 client_await_nothing(State, 5000) 431 end}, 432 433 #{id => 6, 434 desc => "Close", 435 cmd => fun(State) -> 436 client_close(State) 437 end}, 438 439 #{id => 7, 440 desc => "Stop transport", 441 cmd => fun(State) -> 442 client_stop_transport(State) 443 end} 444 ]. 445 446 447 448%% ================================================= 449%% 450%% ------------------ sending ------------------------ 451%% 452%% ================================================= 453 454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 455 456sendreceive(suite) -> 457 []; 458sendreceive(doc) -> 459 ["Test send and receive with the UDP transport. "]; 460sendreceive(Config) when is_list(Config) -> 461 Factor = ?config(megaco_factor, Config), 462 ct:timetrap(Factor * ?SECS(30)), 463 Pre = fun() -> 464 p("create nodes"), 465 ServerNode = make_node_name(server), 466 ClientNode = make_node_name(client), 467 Nodes = [ServerNode, ClientNode], 468 ok = ?START_NODES(Nodes), 469 Nodes 470 end, 471 Case = fun(X) -> do_sendreceive(Config, Factor, X) end, 472 Post = fun(Nodes) -> 473 p("stop nodes"), 474 ?STOP_NODES(lists:reverse(Nodes)) 475 end, 476 try_tc(sendreceive, Pre, Case, Post). 477 478do_sendreceive(Config, Factor, [ServerNode, ClientNode]) -> 479 %% Create command sequences 480 p("create command sequences"), 481 TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end, 482 TO = TOCalc(?SECS(5)), 483 ServerPort = 2944, 484 ServerCmds = sendreceive_server_commands(Config, TO, ServerPort), 485 {ok, ServerHost} = inet:gethostname(), 486 ClientCmds = sendreceive_client_commands(Config, TO, ServerPort, ServerHost), 487 488 %% Start the test procs used in the test-case, one for each node 489 p("start command handlers"), 490 Server = server_start_command_handler(ServerNode, ServerCmds), 491 p("server command handler started: ~p", [Server]), 492 Client = client_start_command_handler(ClientNode, ClientCmds), 493 p("client command handler started: ~p", [Client]), 494 495 ok = 496 receive 497 {operational, Server} -> 498 p("received operational message from server [~p] => " 499 "send continue to client [~p]~n", [Server, Client]), 500 Client ! {continue, self()}, 501 ok; 502 {'EXIT', Server, {skip, Reason}} -> 503 ?SKIP(Reason); 504 {'EXIT', Client, {skip, Reason}} -> 505 ?SKIP(Reason) 506 after TO -> 507 {error, server_timeout} 508 end, 509 510 ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))), 511 p("done"), 512 ok. 513 514 515sendreceive_server_commands(Config, TO, Port) -> 516 Opts = [{port, Port}], 517 Self = self(), 518 [ 519 #{id => 1, 520 desc => "Command sequence init", 521 cmd => fun(State) -> 522 {ok, State#{parent => Self}} 523 end}, 524 525 #{id => 2, 526 desc => "Start transport", 527 cmd => fun(State) -> 528 server_start_transport(State) 529 end}, 530 531 #{id => 3, 532 desc => "Open", 533 cmd => fun(State) -> 534 server_open(Config, State, Opts) 535 end}, 536 537 #{id => 4, 538 desc => "Notify operational", 539 cmd => fun(State) -> 540 server_notify_operational(State) 541 end}, 542 543 #{id => 5, 544 desc => "Await initial message (ping)", 545 cmd => fun(State) -> 546 server_await_initial_message(State, "ping", TO) 547 end}, 548 549 #{id => 6, 550 desc => "Send reply (pong) to initial message", 551 cmd => fun(State) -> 552 server_send_message(State, "pong") 553 end}, 554 555 #{id => 7, 556 desc => "Await nothing before sending a message (hejsan)", 557 cmd => fun(State) -> 558 server_await_nothing(State, TO div 5) 559 end}, 560 561 #{id => 8, 562 desc => "Send message (hejsan)", 563 cmd => fun(State) -> 564 server_send_message(State, "hejsan") 565 end}, 566 567 #{id => 9, 568 desc => "Await reply (hoppsan) to message", 569 cmd => fun(State) -> 570 server_await_message(State, "hoppsan", TO div 5) 571 end}, 572 573 #{id => 10, 574 desc => "Await nothing before closing", 575 cmd => fun(State) -> 576 server_await_nothing(State, TO div 5) 577 end}, 578 579 #{id => 11, 580 desc => "Close", 581 cmd => fun(State) -> 582 server_close(State) 583 end}, 584 585 #{id => 12, 586 desc => "Await nothing before stopping transport", 587 cmd => fun(State) -> 588 server_await_nothing(State, TO div 5) 589 end}, 590 591 #{id => 13, 592 desc => "Stop", 593 cmd => fun(State) -> 594 server_stop_transport(State) 595 end} 596 ]. 597 598sendreceive_client_commands(Config, TO, ServerPort, ServerHost) -> 599 OwnPort = ServerPort+1, 600 Opts = [{port, OwnPort}], 601 Self = self(), 602 [ 603 #{id => 1, 604 desc => "Command sequence init", 605 cmd => fun(State) -> 606 {ok, State#{parent => Self}} 607 end}, 608 609 #{id => 2, 610 desc => "Start transport", 611 cmd => fun(State) -> 612 client_start_transport(State) 613 end}, 614 615 #{id => 3, 616 desc => "Open", 617 cmd => fun(State) -> 618 client_open(Config, State, Opts) 619 end}, 620 621 #{id => 4, 622 desc => "Await continue", 623 cmd => fun(State) -> 624 client_await_continue_signal(State, TO) 625 end}, 626 627 #{id => 5, 628 desc => "Connect", 629 cmd => fun(State) -> 630 client_connect(State, ServerHost, ServerPort) 631 end}, 632 633 #{id => 6, 634 desc => "Send initial message (ping)", 635 cmd => fun(State) -> 636 client_send_message(State, "ping") 637 end}, 638 639 #{id => 7, 640 desc => "Await reply (pong) to initial message", 641 cmd => fun(State) -> 642 client_await_message(State, "pong", TO div 5) 643 end}, 644 645 #{id => 8, 646 desc => "Await message (hejsan)", 647 cmd => fun(State) -> 648 client_await_message(State, "hejsan", TO) 649 end}, 650 651 #{id => 9, 652 desc => "Send reply (hoppsan) to message", 653 cmd => fun(State) -> 654 client_send_message(State, "hoppsan") 655 end}, 656 657 #{id => 10, 658 desc => "Await nothing before closing", 659 cmd => fun(State) -> 660 client_await_nothing(State, TO div 5) 661 end}, 662 663 #{id => 11, 664 desc => "Close", 665 cmd => fun(State) -> 666 client_close(State) 667 end}, 668 669 #{id => 12, 670 desc => "Await nothing before stopping transport", 671 cmd => fun(State) -> 672 client_await_nothing(State, TO div 5) 673 end}, 674 675 #{id => 13, 676 desc => "Stop transport", 677 cmd => fun(State) -> 678 client_stop_transport(State) 679 end} 680 ]. 681 682 683%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 684 685block_unblock(suite) -> 686 []; 687block_unblock(doc) -> 688 ["Test the block/unblock functions of the UDP transport. "]; 689block_unblock(Config) when is_list(Config) -> 690 Factor = ?config(megaco_factor, Config), 691 ct:timetrap(Factor * ?MINS(1)), 692 Pre = fun() -> 693 p("create nodes"), 694 ServerNode = make_node_name(server), 695 ClientNode = make_node_name(client), 696 Nodes = [ServerNode, ClientNode], 697 ok = ?START_NODES(Nodes), 698 Nodes 699 end, 700 Case = fun(X) -> do_block_unblock(Config, Factor, X) end, 701 Post = fun(Nodes) -> 702 p("stop nodes"), 703 ?STOP_NODES(lists:reverse(Nodes)) 704 end, 705 try_tc(block_unblock, Pre, Case, Post). 706 707do_block_unblock(Config, Factor, [ServerNode, ClientNode]) -> 708 %% Create command sequences 709 p("create command sequences"), 710 TOCalc = fun(BaseTO) -> to_calc(Factor, BaseTO) end, 711 TO = TOCalc(?SECS(5)), 712 ServerPort = 2944, 713 p("generated command sequences with timeout: ~w msec", [TO]), 714 ServerCmds = block_unblock_server_commands(Config, TO, ServerPort), 715 {ok, ServerHost} = inet:gethostname(), 716 ClientCmds = block_unblock_client_commands(Config, TO, ServerPort, ServerHost), 717 718 %% Start the test procs used in the test-case, one for each node 719 p("start command handlers"), 720 Server = server_start_command_handler(ServerNode, ServerCmds), 721 p("server command handler started: ~p", [Server]), 722 Client = client_start_command_handler(ClientNode, ClientCmds), 723 p("client command handler started: ~p", [Client]), 724 725 %% Wait for the server to become ready for operation 726 %% and then tell the client to continue 727 ok = 728 receive 729 {operational, Server} -> 730 p("received operational message from server [~p] => " 731 "send continue to client [~p]~n", [Server, Client]), 732 Client ! {continue, self()}, 733 ok; 734 {'EXIT', Server, {skip, Reason1}} -> 735 ?SKIP(Reason1); 736 {'EXIT', Client, {skip, Reason2}} -> 737 ?SKIP(Reason2) 738 after TO -> 739 {error, server_timeout} 740 end, 741 742 %% Wait for the client to become blocked 743 %% and then tell the server to continue 744 ok = 745 receive 746 {blocked, Client} -> 747 p("received blocked message from client [~p] => " 748 "send continue to server [~p]~n", [Client, Server]), 749 Server ! {continue, self()}, 750 ok; 751 {'EXIT', Server, {skip, Reason3}} -> 752 ?SKIP(Reason3); 753 {'EXIT', Client, {skip, Reason4}} -> 754 ?SKIP(Reason4) 755 after TO -> 756 {error, timeout} 757 end, 758 759 ok = await_command_handler_completion([Server, Client], TOCalc(?SECS(20))), 760 p("done"), 761 ok. 762 763 764block_unblock_server_commands(Config, TO, Port) -> 765 Opts = [{port, Port}], 766 Self = self(), 767 [ 768 #{id => 1, 769 desc => "Command sequence init", 770 cmd => fun(State) -> 771 {ok, State#{parent => Self}} 772 end}, 773 774 #{id => 2, 775 desc => "Start transport", 776 cmd => fun(State) -> 777 server_start_transport(State) 778 end}, 779 780 #{id => 3, 781 desc => "Open", 782 cmd => fun(State) -> 783 server_open(Config, State, Opts) 784 end}, 785 786 #{id => 4, 787 desc => "Notify operational", 788 cmd => fun(State) -> 789 server_notify_operational(State) 790 end}, 791 792 #{id => 5, 793 desc => "Await initial message (ping)", 794 cmd => fun(State) -> 795 server_await_initial_message(State, "ping", TO) 796 end}, 797 798 #{id => 6, 799 desc => "Send reply (pong) to initial message", 800 cmd => fun(State) -> 801 server_send_message(State, "pong") 802 end}, 803 804 #{id => 7, 805 desc => "Await continue - and nothing else", 806 cmd => fun(State) -> 807 server_await_continue_signal(State, TO) 808 end}, 809 810 #{id => 8, 811 desc => "Send message (hejsan) (client is blocked)", 812 cmd => fun(State) -> 813 server_send_message(State, "hejsan") 814 end}, 815 816 #{id => 9, 817 desc => "Await reply (hoppsan) to message", 818 cmd => fun(State) -> 819 server_await_message(State, "hoppsan", TO) 820 end}, 821 822 #{id => 10, 823 desc => "Await nothing before closing", 824 cmd => fun(State) -> 825 server_await_nothing(State, TO div 5) 826 end}, 827 828 #{id => 11, 829 desc => "Close", 830 cmd => fun(State) -> 831 server_close(State) 832 end}, 833 834 #{id => 12, 835 desc => "Await nothing before stopping transport", 836 cmd => fun(State) -> 837 server_await_nothing(State, TO div 5) 838 end}, 839 840 #{id => 13, 841 desc => "Stop", 842 cmd => fun(State) -> 843 server_stop_transport(State) 844 end} 845 846 ]. 847 848block_unblock_client_commands(Config, TO, ServerPort, ServerHost) -> 849 OwnPort = ServerPort+1, 850 Opts = [{port, OwnPort}], 851 Self = self(), 852 [ 853 #{id => 1, 854 desc => "Command sequence init", 855 cmd => fun(State) -> 856 {ok, State#{parent => Self}} 857 end}, 858 859 #{id => 2, 860 desc => "Start transport", 861 cmd => fun(State) -> 862 client_start_transport(State) 863 end}, 864 865 #{id => 3, 866 desc => "Open", 867 cmd => fun(State) -> 868 client_open(Config, State, Opts) 869 end}, 870 871 #{id => 4, 872 desc => "Await continue", 873 cmd => fun(State) -> 874 client_await_continue_signal(State, TO) 875 end}, 876 877 #{id => 5, 878 desc => "[pseudo] Connect", 879 cmd => fun(State) -> 880 client_connect(State, ServerHost, ServerPort) 881 end}, 882 883 #{id => 6, 884 desc => "Send initial message (ping)", 885 cmd => fun(State) -> 886 client_send_message(State, "ping") 887 end}, 888 889 #{id => 7, 890 desc => "Await reply (pong) to initial message", 891 cmd => fun(State) -> 892 client_await_message(State, "pong", TO div 5) 893 end}, 894 895 #{id => 8, 896 desc => "Pre-Block info", 897 cmd => fun(#{socket := Socket} = State) -> 898 p("Socket Info: " 899 "~n Port Info: ~p", [inet:info(Socket)]), 900 {ok, State} 901 end}, 902 903 #{id => 9, 904 desc => "Block", 905 cmd => fun(State) -> 906 client_block(State) 907 end}, 908 909 #{id => 10, 910 desc => "Post-Block info", 911 cmd => fun(#{socket := Socket} = State) -> 912 Active = 913 case inet:getopts(Socket, [active]) of 914 {ok, [{active, Act}]} -> 915 Act; 916 _ -> 917 undefined 918 end, 919 p("Socket Info: " 920 "~n Active: ~p" 921 "~n Port Info: ~p", 922 [Active, inet:info(Socket)]), 923 {ok, State} 924 end}, 925 926 #{id => 11, 927 desc => "Notify blocked", 928 cmd => fun(State) -> 929 client_notify_blocked(State) 930 end}, 931 932 #{id => 12, 933 desc => "Await nothing before unblocking", 934 cmd => fun(#{socket := Socket} = State) -> 935 Fail = 936 fun(_) -> 937 Active = 938 case inet:getopts(Socket, [active]) of 939 {ok, [{active, Act}]} -> 940 Act; 941 _ -> 942 undefined 943 end, 944 p("Socket Info: " 945 "~n Active: ~p" 946 "~n Port Info: ~p", 947 [Active, inet:info(Socket)]), 948 ok 949 end, 950 client_await_nothing(State, Fail, TO div 2) 951 end}, 952 953 #{id => 13, 954 desc => "Pre-Unblock info", 955 cmd => fun(#{socket := Socket} = State) -> 956 Active = 957 case inet:getopts(Socket, [active]) of 958 {ok, [{active, Act}]} -> 959 Act; 960 _ -> 961 undefined 962 end, 963 p("Socket Info: " 964 "~n Active: ~p" 965 "~n Port Info: ~p", 966 [Active, inet:info(Socket)]), 967 {ok, State} 968 end}, 969 970 #{id => 14, 971 desc => "Unblock", 972 cmd => fun(State) -> 973 client_unblock(State) 974 end}, 975 976 #{id => 15, 977 desc => "Post-Unblock info", 978 cmd => fun(#{socket := Socket} = State) -> 979 Active = 980 case inet:getopts(Socket, [active]) of 981 {ok, [{active, Act}]} -> 982 Act; 983 _ -> 984 undefined 985 end, 986 p("Socket Info: " 987 "~n Active: ~p" 988 "~n Port Info: ~p", 989 [Active, inet:info(Socket)]), 990 {ok, State} 991 end}, 992 993 #{id => 16, 994 desc => "Await message (hejsan)", 995 cmd => fun(State) -> 996 client_await_message(State, "hejsan", TO) 997 end}, 998 999 #{id => 17, 1000 desc => "Send reply (hoppsan) to message", 1001 cmd => fun(State) -> 1002 client_send_message(State, "hoppsan") 1003 end}, 1004 1005 #{id => 18, 1006 desc => "Await nothing before closing", 1007 cmd => fun(State) -> 1008 client_await_nothing(State, TO) 1009 end}, 1010 1011 #{id => 19, 1012 desc => "Close", 1013 cmd => fun(State) -> 1014 client_close(State) 1015 end}, 1016 1017 #{id => 20, 1018 desc => "Await nothing before stopping transport", 1019 cmd => fun(State) -> 1020 client_await_nothing(State, TO) 1021 end}, 1022 1023 #{id => 21, 1024 desc => "Stop transport", 1025 cmd => fun(State) -> 1026 client_stop_transport(State) 1027 end} 1028 ]. 1029 1030 1031%% ================================================= 1032%% 1033%% ------------------ errors ------------------------ 1034%% 1035%% ================================================= 1036 1037socket_failure(suite) -> 1038 []; 1039socket_failure(Config) when is_list(Config) -> 1040 ?ACQUIRE_NODES(1, Config), 1041 failing_socket(). 1042 1043 1044%%====================================================================== 1045%% Test functions 1046%%====================================================================== 1047 1048start_case(Config, Opts, Expect) -> 1049 case (catch megaco_udp:start_transport()) of 1050 {ok, Pid} -> 1051 case (catch ?OPEN(Config, Pid, Opts)) of 1052 {ok, _Handle, _CtrlPid} when Expect =:= ok -> 1053 {ok, Pid}; 1054 {ok, Handle, CtrlPid} -> 1055 megaco_udp:stop_transport(Pid), 1056 ?ERROR({unexpected_start_sucesss, Handle, CtrlPid}); 1057 {error, _Reason} when Expect =:= error -> 1058 megaco_udp:stop_transport(Pid), 1059 ok; 1060 {error, Reason} -> 1061 megaco_udp:stop_transport(Pid), 1062 ?ERROR({unexpected_start_failure, Reason}); 1063 Error -> 1064 ?ERROR({unexpected_result, Error}) 1065 end; 1066 {error, Reason} -> 1067 ?ERROR({failed_starting_transport, Reason}) 1068 end. 1069 1070 1071failing_socket() -> 1072 ?SKIP(not_yet_implemented). 1073 1074 1075 1076%%---------------------------------------------------------------------- 1077%% Message Callback functions 1078%%---------------------------------------------------------------------- 1079 1080receive_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) 1081 when is_pid(ReceiveHandle) andalso is_binary(BinMsg) -> 1082 Msg = binary_to_list(BinMsg), 1083 ReceiveHandle ! {receive_message, {ControlPid, SendHandle, Msg}}, 1084 ok. 1085 1086process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg) 1087 when is_pid(ReceiveHandle) andalso is_binary(BinMsg) -> 1088 Msg = binary_to_list(BinMsg), 1089 ReceiveHandle ! {process_received_message, {ControlPid, SendHandle, Msg}}, 1090 ok. 1091 1092 1093%%====================================================================== 1094%% Internal functions 1095%%====================================================================== 1096 1097%% ------- Server command handler and utility functions ---------- 1098 1099server_start_command_handler(Node, Commands) -> 1100 start_command_handler(Node, Commands, #{}, "server"). 1101 1102server_start_transport(State) when is_map(State) -> 1103 case (catch megaco_udp:start_transport()) of 1104 {ok, Ref} -> 1105 p("Transport started: ~p", [Ref]), 1106 {ok, State#{transport_ref => Ref}}; 1107 Error -> 1108 Error 1109 end. 1110 1111server_open(Config, #{transport_ref := Ref} = State, Options) 1112 when is_list(Options) -> 1113 Opts = [{receive_handle, self()}, {module, ?MODULE} | Options], 1114 try ?OPEN(Config, Ref, Opts) of 1115 {ok, Socket, ControlPid} -> 1116 p("opened: " 1117 "~n Socket: ~p" 1118 "~n ControlPid: ~p", [Socket, ControlPid]), 1119 {ok, State#{handle => {socket, Socket}, % Temporary 1120 control_pid => ControlPid}}; 1121 {error, {could_not_open_udp_port, eaddrinuse}} -> 1122 {skip, {server, eaddrinuse}}; 1123 {error, _} = ERROR -> 1124 ERROR 1125 catch 1126 C:E:S -> 1127 {error, {catched, C, E, S}} 1128 end. 1129 1130server_notify_operational(#{parent := Parent} = State) -> 1131 Parent ! {operational, self()}, 1132 {ok, State}. 1133 1134server_await_continue_signal(#{parent := Parent} = State, Timeout) -> 1135 receive 1136 {continue, Parent} -> 1137 p("received expected continue signal"), 1138 {ok, State}; 1139 Any -> 1140 p("received UNEXPECTED message: " 1141 "~n ~p", [Any]), 1142 {error, {unexpected, Any}} 1143 after Timeout -> 1144 {error, timeout} 1145 end. 1146 1147server_await_initial_message(State, InitialMessage, Timeout) 1148 when is_map(State) -> 1149 receive 1150 {receive_message, {ControlPid, Handle, InitialMessage}} -> 1151 p("received expected event with: " 1152 "~n ControlPid: ~p" 1153 "~n Handle: ~p", [ControlPid, Handle]), 1154 NewState = State#{handle => Handle}, 1155 {ok, NewState}; 1156 1157 Any -> 1158 p("received unexpected event: ~p", [Any]), 1159 {error, {unexpected_event, Any}} 1160 1161 after Timeout -> 1162 {error, timeout} 1163 end. 1164 1165server_send_message(#{handle := Handle} = State, Message) -> 1166 Bin = if 1167 is_list(Message) -> 1168 list_to_binary(Message); 1169 true -> 1170 Message 1171 end, 1172 megaco_udp:send_message(Handle, Bin), 1173 {ok, State}. 1174 1175server_await_nothing(State, Timeout) 1176 when is_map(State) -> 1177 receive 1178 Any -> 1179 p("received unexpected event: ~p", [Any]), 1180 {error, {unexpected_event, Any}} 1181 1182 after Timeout -> 1183 {ok, State} 1184 end. 1185 1186server_await_message(State, ExpectMessage, Timeout) 1187 when is_map(State) -> 1188 receive 1189 {receive_message, {_, _, ExpectMessage}} -> 1190 p("received expected message [~p]", [ExpectMessage]), 1191 {ok, State}; 1192 1193 Any -> 1194 p("received unexpected event: ~p", [Any]), 1195 {error, {unexpected_event, Any}} 1196 1197 after Timeout -> 1198 {error, timeout} 1199 end. 1200 1201server_close(#{handle := {socket, Socket}} = State) -> 1202 megaco_udp:close(Socket), 1203 {ok, State#{handle => undefined, control_pid => undefined}}; 1204server_close(#{handle := Handle} = State) 1205 when (Handle =/= undefined) -> 1206 megaco_udp:close(Handle), 1207 {ok, State#{handle => undefined, control_pid => undefined}}. 1208 1209server_stop_transport(#{transport_ref := Ref} = State) 1210 when (Ref =/= undefined) -> 1211 megaco_udp:stop_transport(Ref), 1212 {ok, State#{transport_ref => undefined}}. 1213 1214 1215%% ------- Client command handler and utility functions ---------- 1216 1217client_start_command_handler(Node, Commands) -> 1218 start_command_handler(Node, Commands, #{}, "client"). 1219 1220client_start_transport(State) when is_map(State) -> 1221 case (catch megaco_udp:start_transport()) of 1222 {ok, Ref} -> 1223 {ok, State#{transport_ref => Ref}}; 1224 Error -> 1225 Error 1226 end. 1227 1228client_open(Config, #{transport_ref := Ref} = State, Options) 1229 when is_list(Options) -> 1230 Opts = [{receive_handle, self()}, {module, ?MODULE} | Options], 1231 try ?OPEN(Config, Ref, Opts) of 1232 {ok, Socket, ControlPid} -> 1233 {ok, State#{handle => {socket, Socket}, 1234 socket => Socket, 1235 control_pid => ControlPid}}; 1236 {error, {could_not_open_udp_port, eaddrinuse}} -> 1237 {skip, {client, eaddrinuse}}; 1238 {error, _} = ERROR -> 1239 ERROR 1240 catch 1241 C:E:S -> 1242 {error, {catched, C, E, S}} 1243 end. 1244 1245client_await_continue_signal(#{parent := Parent} = State, Timeout) -> 1246 receive 1247 {continue, Parent} -> 1248 {ok, State} 1249 after Timeout -> 1250 {error, timeout} 1251 end. 1252 1253client_notify_blocked(#{parent := Parent} = State) -> 1254 Parent ! {blocked, self()}, 1255 {ok, State}. 1256 1257client_await_nothing(State, Timeout) -> 1258 client_await_nothing(State, fun(_) -> ok end, Timeout). 1259 1260client_await_nothing(State, Fail, Timeout) 1261 when is_map(State) andalso is_function(Fail, 1) -> 1262 receive 1263 Any -> 1264 p("received unexpected event: ~p", [Any]), 1265 (catch Fail(Any)), 1266 {error, {unexpected_event, Any}} 1267 after Timeout -> 1268 {ok, State} 1269 end. 1270 1271client_connect(#{handle := {socket, Socket}} = State, Host, Port) -> 1272 Handle = megaco_udp:create_send_handle(Socket, Host, Port), 1273 {ok, State#{handle => Handle}}. 1274 1275client_send_message(#{handle := Handle} = State, Message) -> 1276 Bin = if 1277 is_list(Message) -> 1278 list_to_binary(Message); 1279 true -> 1280 Message 1281 end, 1282 megaco_udp:send_message(Handle, Bin), 1283 {ok, State}. 1284 1285client_await_message(State, ExpectMessage, Timeout) 1286 when is_map(State) -> 1287 receive 1288 {receive_message, {_, _, ExpectMessage}} -> 1289 {ok, State}; 1290 1291 Any -> 1292 p("received unexpected event: ~p", [Any]), 1293 {error, {unexpected_event, Any}} 1294 1295 after Timeout -> 1296 {error, timeout} 1297 end. 1298 1299client_block(#{handle := Handle} = State) 1300 when (Handle =/= undefined) -> 1301 ok = megaco_udp:block(Handle), 1302 {ok, State}. 1303 1304client_unblock(#{handle := Handle} = State) 1305 when (Handle =/= undefined) -> 1306 ok = megaco_udp:unblock(Handle), 1307 {ok, State}. 1308 1309client_close(#{handle := {socket, Socket}} = State) -> 1310 megaco_udp:close(Socket), 1311 {ok, State#{handle => undefined, control_pid => undefined}}; 1312client_close(#{handle := Handle} = State) 1313 when (Handle =/= undefined) -> 1314 megaco_udp:close(Handle), 1315 {ok, State#{handle => undefined, control_pid => undefined}}. 1316 1317client_stop_transport(#{transport_ref := Ref} = State) 1318 when (Ref =/= undefined) -> 1319 megaco_udp:stop_transport(Ref), 1320 {ok, State#{transport_ref => undefined}}. 1321 1322 1323%% -------- Command handler interface --------- 1324 1325start_command_handler(Node, Commands, State, ShortName) -> 1326 ?CH:start(Node, Commands, State, ShortName). 1327 1328 1329await_command_handler_completion(Pids, Timeout) -> 1330 ?CH:await_completion(Pids, Timeout). 1331 1332 1333%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1334 1335try_tc(TCName, Pre, Case, Post) -> 1336 try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post). 1337 1338try_tc(TCName, Name, Verbosity, Pre, Case, Post) -> 1339 ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post). 1340 1341 1342%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1343 1344%% ------- Misc functions -------- 1345 1346make_node_name(Name) -> 1347 case string:tokens(atom_to_list(node()), [$@]) of 1348 [_,Host] -> 1349 list_to_atom(lists:concat([atom_to_list(Name) ++ "@" ++ Host])); 1350 _ -> 1351 exit("Test node must be started with '-sname'") 1352 end. 1353 1354 1355to_calc(1 = _Factor, BaseTO) when is_integer(BaseTO) andalso (BaseTO > 0) -> 1356 BaseTO; 1357to_calc(Factor, BaseTO) when is_integer(Factor) andalso (Factor > 0) andalso 1358 is_integer(BaseTO) andalso (BaseTO > 0) -> 1359 trunc( ((Factor + 1) / 2) * BaseTO ). 1360 1361 1362p(F) -> 1363 p(F, []). 1364 1365p(F, A) -> 1366 p(get(sname), F, A). 1367 1368p(S, F, A) when is_list(S) -> 1369 io:format("*** [~s] ~p ~s ***" 1370 "~n " ++ F ++ "~n", 1371 [?FTS(), self(), S | A]); 1372p(_S, F, A) -> 1373 io:format("*** [~s] ~p *** " 1374 "~n " ++ F ++ "~n", 1375 [?FTS(), self() | A]). 1376 1377 1378%% ms() -> 1379%% erlang:monotonic_time(milli_seconds). 1380 1381 1382